Expensify / App

Welcome to New Expensify: a complete re-imagination of financial collaboration, centered around chat. Help us build the next generation of Expensify by sharing feedback and contributing to the code.
https://new.expensify.com
MIT License
2.96k stars 2.47k forks source link

[LOW] [Splits] [$500] IOU - App returns to participant selection page when hitting Save with Tab on Description page #37464

Closed m-natarajan closed 2 days ago

m-natarajan commented 2 months ago

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: 1.4.45-0 Reproducible in staging?: y Reproducible in production?: n If this was caught during regression testing, add the test name, ID and link from TestRail: Email or phone of affected tester (no customers): Logs: https://stackoverflow.com/c/expensify/questions/4856 Expensify/Expensify Issue URL: Issue reported by: Applause internal team Slack conversation:

Action Performed:

  1. Go to staging.new.expensify.com
  2. Go to FAB > Request money > Manual.
  3. Enter amount and select participant.
  4. On confirmation page, press Tab.
  5. Navigate to Description and hit Enter.
  6. Enter description and save it with Tab and Enter key.

Expected Result:

The description will be saved and app will land on confirmation page.

Actual Result:

The description is saved and app returns to participant selection page.

Workaround:

unknown

Platforms:

Which of our officially supported platforms is this issue occurring on?

Screenshots/Videos

Add any screenshot/video evidence

https://github.com/Expensify/App/assets/38435837/0fb64f28-a879-431f-9c7c-73f8545689d9

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~010769f678e16c288e
  • Upwork Job ID: 1767859361668382720
  • Last Price Increase: 2024-03-27
  • Automatic offers:
    • akinwale | Reviewer | 0
melvin-bot[bot] commented 2 months ago

Triggered auto assignment to @MitchExpensify (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details.

github-actions[bot] commented 2 months ago

:wave: Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:

  1. Identify the pull request that introduced this issue and revert it.
  2. Find someone who can quickly fix the issue.
  3. Fix the issue yourself.
melvin-bot[bot] commented 2 months ago

Triggered auto assignment to @techievivek (Engineering), see https://stackoverflowteams.com/c/expensify/questions/9980/ for more details.

m-natarajan commented 2 months ago

@techievivek FYI I haven't added the External label as I wasn't 100% sure about this issue. Please take a look and add the label if you agree it's a bug and can be handled by external contributors.

bernhardoj commented 2 months ago

This has the same root cause as https://github.com/Expensify/App/issues/33502#issuecomment-1907604187

techievivek commented 2 months ago

Not a blocker for sure. Also, not sure if we really want to fix this. Or as per this comment https://github.com/Expensify/App/issues/33502#issuecomment-1909057724 we can solve all this together.

techievivek commented 2 months ago

@MitchExpensify Do you have any thoughts about above ^?

dragnoir commented 2 months ago

Proposal

Please re-state the problem that we are trying to solve in this issue.

Save button clicked by keyboard go back twice

What is the root cause of that problem?

When I tested, I found that there's no issue with react navigation or react native web. The issue is within our button component.

A simple check anyone can do, replace the button with the one from react-native, no issue :)

The issue is whith all the button components on the app. Every action via keyboard enter key will trigger double the action.

https://github.com/Expensify/App/blob/0cc58170ec003d20b606b118afaba62a906c3160/src/components/Button/index.tsx#L281-L284

The condition above doesn't check if there's a keyboard enter key event.

What changes do you think we should make in order to solve the problem?

The best way to handle here:

               onPress={(event) => {
                    if (event?.type === 'click') {
                        const currentTarget = event?.currentTarget as HTMLElement;
                        currentTarget?.blur();
                    }

+                  if (event?.type === 'keyup') {
+                        return;
+                   }

                    if (shouldEnableHapticFeedback) {
                        HapticFeedback.press();
                    }
                    return onPress(event);
                }}

This will prevent the double actions on the Button component and will solve the related bugs.

What alternative solutions did you explore? (Optional)

MitchExpensify commented 2 months ago

Not worth fixing at this time

dragnoir commented 1 month ago

@MitchExpensify the issue is within all buttons on the app and there's an easy fix here

MitchExpensify commented 1 month ago

If there is a general solution its worth considering reopening, @techievivek does the solution linked above look like it will fix all cases of this?

dragnoir commented 1 month ago

@techievivek can you please check my proposal? Thank you

techievivek commented 1 month ago

Adding a C+ so they can help review the proposal.

melvin-bot[bot] commented 1 month ago

Job added to Upwork: https://www.upwork.com/jobs/~010769f678e16c288e

melvin-bot[bot] commented 1 month ago

Triggered auto assignment to Contributor-plus team member for initial proposal review - @mkhutornyi (External)

techievivek commented 1 month ago

@mkhutornyi Can you please help review the proposal here https://github.com/Expensify/App/issues/37464#issuecomment-1971486442 and see if that can fix all the keyboard navigation related bugs? Thanks

mkhutornyi commented 1 month ago

@dragnoir thanks for the proposal.

nkdengineer commented 1 month ago

We also should consider @bernhardoj `s comment here

dragnoir commented 1 month ago

@mkhutornyi The issue is old, it was there even before. Every button now on the app triggers action twice if you navigate to it via the TAB key then you hit the ENTER key from the keyboard. We can't catch it easily because triggering twice an action does not cause issues in most cases. But if you log the onClick with a console message, you will see it twice.

@nkdengineer on the comment you mentioned, bernhardoj think it's an issue from react native web and it needs to be fixed upstream. You can check here https://github.com/Expensify/App/issues/33502#issuecomment-1971614956 I fixed the issue there with the same proposal here.

nkdengineer commented 1 month ago

@dragnoir Oh, got it. Thanks for your information

melvin-bot[bot] commented 1 month ago

@techievivek @MitchExpensify @mkhutornyi this issue was created 2 weeks ago. Are we close to approving a proposal? If not, what's blocking us from getting this issue assigned? Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!

MitchExpensify commented 1 month ago

@mkhutornyi What are our next steps here?

nkdengineer commented 1 month ago

Proposal

Please re-state the problem that we are trying to solve in this issue.

Solution 2: If we want the onPress to be called in "keyup" event rather than "click":

Solution 3:

techievivek commented 1 month ago

Gentle bump @mkhutornyi, can you please review the proposals today? Thanks.

mkhutornyi commented 1 month ago

I agree this is not upstream issue. We should either

  1. prevent our custom Enter key event when button is highlighted
  2. prevent Up event when Enter key is already triggered

I prefer 1. because it aligns with other Tab key press behavior (pressed on Down event, triggered on Up event)

bernhardoj commented 1 month ago

I agree this is not upstream issue.

It's an upstream issue.

prevent our custom Enter key event when button is highlighted

There is no enter key shortcut triggered in this issue.

dragnoir commented 1 month ago

It's an upstream issue.

It's not. You can use the Button component from react native and the issue is not there anymore.

We don't handle events correctly. You can google the issue, this happened to lots of users having same framework as here and they solved it using this way

mkhutornyi commented 1 month ago

Oh you're right that it's not related to custom Enter key event which I initially thought. I just tested passing disablePressOnEnter to FormProvider but bug still happening.

https://github.com/Expensify/App/assets/97676131/66b6dd14-0d51-46dd-add9-6087b40cb725


I think the expected behavior should be to trigger onPress on Up event like other views. Edit: But based on current structure of Button component, it seems not possible.

https://github.com/Expensify/App/assets/97676131/d996d51b-2b1d-4dc1-8a96-f515749a8fd2

bernhardoj commented 1 month ago

and they solved it using https://github.com/Expensify/App/issues/37464#issuecomment-1971486442

I tested your solution and it throws a console error, that's why the second onPress isn't triggered. Blurring the element on the second press event doesn't cancel the press event itself.

I think the expected behavior should be to trigger onPress on Up event like other views.

Most of the buttons on the apps use ROLE.BUTTON which renders it as <button>. Native <button> will trigger onclick by pressing it down with the keyboard and react-native-web calls onPress from the onclick event.

https://github.com/Expensify/App/assets/50919443/dd52aeaf-8958-44e9-958b-5882c7e550c9

The MenuItem role is menuitem which will render it as a div and react-native-web manually handles the click/press event in keyup event and it makes sure the element is not a native interactive element (for example button). https://github.com/necolas/react-native-web/blob/5f9c32eba0f840bde7b462a57d0748358ff866f6/packages/react-native-web/src/modules/usePressEvents/PressResponder.js#L305-L328

mkhutornyi commented 1 month ago

@bernhardoj looks like your upstream PR is stale. Created on Jan 24 but no one is taking care of it. Can you please bump reviewers?

nkdengineer commented 1 month ago

@mkhutornyi Do you have any comment proposal](https://github.com/Expensify/App/issues/37464#issuecomment-2002357953) ?

mkhutornyi commented 1 month ago

@nkdengineer thanks for the proposal. Agree with RCA (though same as @bernhardoj's). Can you please try to fix in upstream?

dragnoir commented 1 month ago

@mkhutornyi if it's an upstream issue on,react-native-web why does changing the button from @components/Button with a button from react native solve the issue?

mkhutornyi commented 1 month ago

@dragnoir you meant Pressable? @components/Button is using Pressable in low level.

dragnoir commented 1 month ago

@dragnoir you meant Pressable? @components/Button is using Pressable in low level.

@mkhutornyi yes right.

Can you please try this simple test? change this code here

add simple console function and assign it to the onSubmit And add at the bottom a Pressable component with the same onPress={testPress}

+ const  testPress  = (event) => {
+  console.log('event:  ', event);
+  console.log("Pressed");
+ };

<StepScreenWrapper
// rest of the code..

  <FormProvider
  style={[styles.flexGrow1,  styles.ph5]}
  formID={ONYXKEYS.FORMS.MONEY_REQUEST_DESCRIPTION_FORM}
+ onSubmit={testPress}
// ... rest on the code

+ <Pressable  accessibilityRole="button"  onPress={testPress}>
+   <Text>Press me</Text>
+ </Pressable>
</StepScreenWrapper>

This will show on the console how the Pressable will trigger the action just once. But the Form (use the Bottom component) will trigger the action twice ⇒ This reflects that the issue is not upstream but in the way we handle press events.

if you want to read more about the issue you can check this link: https://stackabuse.com/bytes/triggering-button-click-with-javascript-on-enter-key-press/

SOLUTION

The issue is mainly in this part of the code: https://github.com/Expensify/App/blob/156e9bfd9c86213ba3a2667dbdf5b505753dbdc8/src/components/Button/index.tsx#L286-L296

We are handling the click events separately causing the trigger of the key-up event. Also handling the event from a parent component causes something called Event Bubbling and Propagation described in detail on the link above

Those updates below fix the issue

onPress={(event) => {
  event?.stopPropagation();
  return  onPress(event);
}}

or

onPress={(event) => {
  event?.preventDefault();
  return  onPress(event);
}}
bernhardoj commented 1 month ago

I have bumped the upstream PR. If the maintainer approves the PR (or if we want to create a patch), can we reopen https://github.com/Expensify/App/issues/33502 instead and include both issues in the App PR test step?

melvin-bot[bot] commented 1 month ago

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

mkhutornyi commented 1 month ago

I have bumped the upstream PR. If the maintainer approves the PR (or if we want to create a patch), can we reopen #33502 instead and include both issues in the App PR test step?

Similar to https://github.com/Expensify/App/issues/38163#issuecomment-2000846846, I think we can fix here.

dragnoir commented 1 month ago

@mkhutornyi pls check my comment here https://github.com/Expensify/App/issues/37464#issuecomment-2004939788

mkhutornyi commented 1 month ago

@dragnoir if it's not upstream issue, what are the exact offending lines in the app?

dragnoir commented 1 month ago

@mkhutornyi pls check "SOLUTION" part here https://github.com/Expensify/App/issues/37464#issuecomment-2004939788

mkhutornyi commented 1 month ago

@dragnoir thanks. I confirmed that your RCA is correct. I see that you suggested 3 solutions. Which solution is the main one? And explain why it's the best solution over others.

  1. || event?.type === 'keyup'
  2. stopPropagation()
  3. preventDefault()
mkhutornyi commented 1 month ago

I am no longer waiting upstream fix. And @bernhardoj's upstream fix was also rejected.

mkhutornyi commented 1 month ago

https://github.com/Expensify/App/blob/00e0121fa17a7c19335a8fa10eed51c25e933d6a/src/components/Button/index.tsx#L287-L290

The root cause is indeed here but this is on purpose. onPress should be called only once and while keep Enter pressed in, it should be not called anymore.

dragnoir commented 1 month ago

@mkhutornyi I like the solution I mentioned on my proposal

- if (event?.type === 'click') {
+ if (event?.type === 'click' || event?.type === 'keyup') {
  const  currentTarget = event?.currentTarget  as  HTMLElement;
  currentTarget?.blur();
}

We keep everything as it is and we make sure we handle the keyup event.

mkhutornyi commented 1 month ago

@dragnoir that solution didn't work. It causes console error and that's why the next lines were not triggered.

dragnoir commented 1 month ago

@dragnoir that solution didn't work. It causes console error and that's why the next lines were not triggered.

True, I forgot about it. I will check again.

melvin-bot[bot] commented 1 month ago

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

dragnoir commented 1 month ago

@mkhutornyi Sorry for the delay, I wanted to test all possible solutions and check if there's an issue or regression.

This is the best way to handle here:

onPress={(event) => {
                    if (event?.type === 'click') {
                        const currentTarget = event?.currentTarget as HTMLElement;
                        currentTarget?.blur();
                    }

+                  if (event?.type === 'keyup') {
+                        return;
+                   }

                    if (shouldEnableHapticFeedback) {
                        HapticFeedback.press();
                    }
                    return onPress(event);
                }}

This will prevent the double actions on the Button component and will solve the related bugs.

mkhutornyi commented 1 month ago

I also agree with that approach. Please update proposal accordingly.