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
3.52k stars 2.87k forks source link

[HOLD for payment 2023-06-29] [$1000] Arrow key shortcut stops working #19700

Closed aldo-expensify closed 1 year ago

aldo-expensify commented 1 year 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!


Coming from: https://github.com/Expensify/App/pull/18883/files#r1206010822

Action Performed:

  1. Open the panel to invite new members to a workspace (/workspace//invite)
  2. Verify that arrows up and down work and they change the selected row
  3. Select something with the mouse
  4. Click Next
  5. Go back
  6. BUG: The arrow keys don't change the highlighted row anymore

Expected Result:

Pressing UP or DOWN should change the highlighted row

Actual Result:

Pressing UP or DOWN doesn't do anything

Workaround:

Can the user still use Expensify without this being fixed? Have you informed them of the workaround?

Platforms:

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

Version Number: Reproducible in staging?: Reproducible in production?: 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 Notes/Photos/Videos: Any additional supporting documentation Expensify/Expensify Issue URL: Issue reported by: Slack conversation:

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~01ecaf4548dae58200
  • Upwork Job ID: 1668438254258597888
  • Last Price Increase: 2023-06-13
melvin-bot[bot] commented 1 year ago

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

melvin-bot[bot] commented 1 year ago

Bug0 Triage Checklist (Main S/O)

aldo-expensify commented 1 year ago

The cause is pretty narrowed down here:

I think this would have been easier to fix if we were dealing with functional components. There out of the box memoization with Class components. The recommended way is to use the library memoize-one which we don't currently have, and I'm not sure we want it since we are moving toward functional components.

johncschuster commented 1 year ago

FYI - No Slack thread for this one.

melvin-bot[bot] commented 1 year ago

Triggered auto assignment to @flodnv (Engineering), see https://stackoverflow.com/c/expensify/questions/4319 for more details.

flodnv commented 1 year ago

From @aldo-expensify's investigation it seems like @roryabraham you caused this in https://github.com/Expensify/App/pull/18883, can you have a look please and let us know what you think?

aldo-expensify commented 1 year ago

Also, Vit was recommending me to get help from one of our external expert agencies to work on this (here). I think that could be a good idea.

roryabraham commented 1 year ago

Looking into this now

roryabraham commented 1 year ago

I'm not sure I yet see how this is related to https://github.com/Expensify/App/pull/18883, because the OptionsSelector doesn't yet use the useArrowKeyFocusManager or useKeyboardShortcut hooks.

roryabraham commented 1 year ago

Found this lib which honestly seems pretty slick

aldo-expensify commented 1 year ago

I'm pretty sure you could fix this particular bug by playing with the priorities during subscribe, but I still think this should be fix in a way it stops unsubscribing/subscribing every cycle.

aldo-expensify commented 1 year ago

Found this lib which honestly seems pretty slick

Interesting, the focus trap thing could help solving the problem we have with key event listeners that keep listening even out of view (see https://expensify.slack.com/archives/C01GTK53T8Q/p1685138015892469 / https://github.com/Expensify/App/issues/18419)

roryabraham commented 1 year ago

This seems like the exact scenario the upcoming React.useEvent hook is designed for.

aldo-expensify commented 1 year ago

This seems like the exact scenario the upcoming React.useEvent hook is designed for.

In only found this: https://github.com/reactjs/rfcs/pull/220

Is this going to be implemented? Looks good, but I think for the moment, if that is not near to be released, this can be done with useCallback + useMemo in functional react. In class components is hard I believe.

roryabraham commented 1 year ago

Yeah, it's just an RFC now, and we should be able to simulate it.

roryabraham commented 1 year ago

Put up a draft PR with a potential fix: https://github.com/Expensify/App/pull/20016. More testing and discussion is needed since it uses an experimental React feature which is explained in good detail here: https://react.dev/learn/separating-events-from-effects#declaring-an-event-function

johncschuster commented 1 year ago

PR is being worked on, Melv. Chill.

roryabraham commented 1 year ago

I haven't made any progress on the PR, been tied down with deploy chores. Considering making this external, but if we need to use a new React hook to fix it then we need a slack convo first

melvin-bot[bot] commented 1 year ago

@johncschuster @roryabraham this issue was created 2 weeks ago. Are we close to a solution? Let's make sure we're treating this as a top priority. Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!

johncschuster commented 1 year ago

This is being solved internally, Melv. Chill

flodnv commented 1 year ago

@roryabraham is it being solved internally? Your last comment mentions making it External, can we do that now?

roryabraham commented 1 year ago

Yeah, I'm a bit hesitant to make it external without a clearer understanding of the root cause of the problem. Going to make this external.

melvin-bot[bot] commented 1 year ago

Job added to Upwork: https://www.upwork.com/jobs/~01ecaf4548dae58200

melvin-bot[bot] commented 1 year ago

Current assignee @johncschuster is eligible for the External assigner, not assigning anyone new.

melvin-bot[bot] commented 1 year ago

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

melvin-bot[bot] commented 1 year ago

Current assignee @roryabraham is eligible for the External assigner, not assigning anyone new.

gedu commented 1 year ago

Proposal

Please restate the problem that we are trying to solve in this issue.

The issue occurs when the user selects an item from the OptionList, moves to a next screen, and then returns. Upon returning, the arrow key selection (UP and DOWN) stops working in the PopoverMenu component. To reproduce: Open the panel to invite new members to a workspace (/workspace//invite). Verify that arrow keys (UP and DOWN) work and change the selected row. Select an item using the mouse. Click “Next.” Go back to the previous screen. BUG: The arrow keys no longer change the highlighted row.

What is the root cause of this problem?

The issue stems from a conflict between the keyboard subscription in the PopoverMenu component (which also re-renders multiple times) and the useKeyboardShortcut hook. Initially, when entering the Workspace invite members page, the keyboard subscription is handled by the ArrowKeyFocusManager in the componentDidMount event, occurring after the PopoverMenu subscription. This initial setup works fine. However, upon leaving the screen and returning, the PopoverMenu subscribes again, even though it is not currently visible. Consequently, when the Workspace page becomes visible again, the componentDidMount event is not fired, and the last subscription from the PopoverMenu remains active.

What changes do you propose to solve the problem?

To resolve the issue, we need to modify the implementation of the PopoverMenu component. The PopoverMenu component uses the useArrowKeyFocusManager, which internally uses the useKeyboardShortcut hook. Currently, the PopoverMenu does not pass information about whether it is active or not to the useArrowKeyFocusManager, causing it to always subscribe to keyboard shortcuts. To address this, we can add an “isActive” prop to the useArrowKeyFocusManager, which will indicate whether the menu is currently active or not. This prop can be derived from the “props.isVisible” value. On top of this, I would add the suggestion and cleanups from @aldo-expensify

roryabraham commented 1 year ago

Ok, I think that makes sense. Thanks for the explanation @gedu 🙇🏼

melvin-bot[bot] commented 1 year ago

📣 @gedu You have been assigned to this job by @roryabraham! Please apply to this job in Upwork and leave a comment on the Github issue letting us know when we can expect a PR to be ready for review 🧑‍💻 Keep in mind: Code of Conduct | Contributing 📖

Santhosh-Sellavel commented 1 year ago

I'll just wait for the PR then, thanks for the early review @roryabraham!

gedu commented 1 year ago

@roryabraham @aldo-expensify Hey, while I was adding the isActive and doing the cleanup, I noticed that the useArrowKeyFocusManager function has an unstable type for the disabledIndexes parameter, which is disabledIndexes = []. This causes any hook that uses this parameter to be recreated every time.

I was improving the callback for useKeyboardShortcut so the useEffect doesn't get called everytime. but if I do this

 const arrowUpCallback = useCallback(() => {
        if (maxIndex < 0) {
            return;
        }

        setFocusedIndex((index) => {
            const currentFocusedIndex = index > 0 ? index - 1 : maxIndex;
            let newFocusedIndex = currentFocusedIndex;

            while (disabledIndexes.includes(newFocusedIndex)) {
                newFocusedIndex = newFocusedIndex > 0 ? newFocusedIndex - 1 : maxIndex;
                if (newFocusedIndex === currentFocusedIndex) {
                    // all indexes are disabled
                    return index; // no-op
                }
            }
            return newFocusedIndex;
        });
    }, [disabledIndexes, maxIndex]);
    useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_UP, arrowUpCallback, arrowConfig);
because `disabledIndexes` always is a new array the function will be recreating calling again the `useEffect`, chatting internally I think the best option is to create a const array and use it, in this case, is good because we just query the value, doing this we avoid that when other use this hook they don't need to use `useMemo` and pass always an array.

```
const EMPTY_ARRAY = Object.freeze([]);

function useArrowKeyFocusManager({
maxIndex,
onFocusedIndexChange = () => {},
initialFocusedIndex = 0,
disabledIndexes = EMPTY_ARRAY,
shouldExcludeTextAreaNodes = true,
isActive,

}) {}



Doing `freeze` so if someone tries to mutate the array get an error, because at least for now we don't want to support that behavior.

I want to point this out because as we start using hooks, these issues could arise in many places.

What do you think?

Before
<img width="337" alt="Screen Shot 2023-06-14 at 15 37 46" src="https://github.com/Expensify/App/assets/1676818/5e0e4291-852e-4fe4-8c84-d3a2429eb005">

After
<img width="309" alt="Screen Shot 2023-06-14 at 15 38 13" src="https://github.com/Expensify/App/assets/1676818/277053ba-4635-4b74-b425-dc720e039509">
chrispader commented 1 year ago

The isActive addition would also come in handy in this PR, since we want to be able to use the useArrowKeyFocusManager for two different contexts (emojis and suggestions), and being able to disable a keyboard shortcut subscription temporarily, would be great

melvin-bot[bot] commented 1 year ago

Based on my calculations, the pull request did not get merged within 3 working days of assignment. Please, check out my computations here:

On to the next one 🚀

melvin-bot[bot] commented 1 year ago

Reviewing label has been removed, please complete the "BugZero Checklist".

melvin-bot[bot] commented 1 year ago

The solution for this issue has been :rocket: deployed to production :rocket: in version 1.3.30-5 and is now subject to a 7-day regression period :calendar:. Here is the list of pull requests that resolve this issue:

If no regressions arise, payment will be issued on 2023-06-29. :confetti_ball:

After the hold period is over and BZ checklist items are completed, please complete any of the applicable payments for this issue, and check them off once done.

As a reminder, here are the bonuses/penalties that should be applied for any External issue:

melvin-bot[bot] commented 1 year ago

BugZero Checklist: The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed:

roryabraham commented 1 year ago

I think this is ready for payment now

Santhosh-Sellavel commented 1 year ago

BugZero Checklist: The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed:

  • [x] [@Santhosh-Sellavel] The PR that introduced the bug has been identified. Link to the PR: https://github.com/Expensify/App/pull/18883
  • [x] [@Santhosh-Sellavel] The offending PR has been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake. Link to comment: Already pointed out by @aldo-expensify in th issue description https://github.com/Expensify/App/pull/18883/files#r1206010822
  • [x] [@Santhosh-Sellavel] A discussion in #expensify-bugs has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner. Link to discussion: Should have been caught with our checklist.
  • [x] [@Santhosh-Sellavel] Determine if we should create a regression test for this bug. Yes
  • [x] [@Santhosh-Sellavel] If we decide to create a regression test for the bug, please propose the regression test steps to ensure the same bug will not reach production again. https://github.com/Expensify/App/issues/19700#issuecomment-1616859600
  • [ ] [@johncschuster] Link the GH issue for creating/updating the regression test once above steps have been agreed upon:
Santhosh-Sellavel commented 1 year ago

Bug: Arrow key selection stops working on the workspace invite members page

Regression Steps

  1. Open the panel to invite new members to a workspace (/workspace//invite)
  2. Verify that arrows up and down work and the selected row is changed
  3. Select something with the mouse
  4. Click Next
  5. Go back
  6. The arrow keys change the highlighted row

👍 or 👎

cc: @roryabraham @johncschuster

johncschuster commented 1 year ago

@Santhosh-Sellavel Upwork invite sent. Can you please ping me when you've accepted?

johncschuster commented 1 year ago

@Santhosh-Sellavel has requested payment via NewDot 🎉

anmurali commented 1 year ago

Paid

johncschuster commented 1 year ago

Thanks, @anmurali!

roryabraham commented 1 year ago

Then, since @gedu works for Callstack, we are all set to close this 🎉