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.14k stars 2.64k forks source link

[$250] Submit expense - Tabs disappear when changing from Scan to Distance via SHIFT+TAB #43719

Open lanitochka17 opened 1 month ago

lanitochka17 commented 1 month 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.83-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: https://expensify.testrail.io/index.php?/tests/view/4626993 Issue reported by: Applause - Internal Team

Action Performed:

  1. Go to staging.new.expensify.com
  2. Go to FAB > Submit expense
  3. Go to Scan
  4. Click on empty area on the RHP (like the empty header area)
  5. Press SHIFT+TAB

Expected Result:

Nothing will happen

Actual Result:

RHP changes to Distance flow, and tabs (Manual, Scan, Distance) are missing

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/78819774/d86b3e9c-7d57-4722-b6ae-547be8e690f1

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~0112bb5e5d8d723e7f
  • Upwork Job ID: 1801340710232481793
  • Last Price Increase: 2024-07-18
Issue OwnerCurrent Issue Owner: @rayane-djouah
melvin-bot[bot] commented 1 month ago

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

github-actions[bot] commented 1 month 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.
lanitochka17 commented 1 month ago

@tgolen 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

lanitochka17 commented 1 month ago

We think that this bug might be related to #vip-vsp

melvin-bot[bot] commented 1 month ago

Job added to Upwork: https://www.upwork.com/jobs/~0112bb5e5d8d723e7f

melvin-bot[bot] commented 1 month ago

Triggered auto assignment to @OfstadC (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

melvin-bot[bot] commented 1 month ago

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

tgolen commented 1 month ago

I'm demoting this one and assigning to external.

tsa321 commented 1 month ago

cannot reproduce in production release. Offending PR: https://github.com/Expensify/App/pull/39520

studentofcoding commented 1 month ago

Not produceable on Production and local

vishnu-karuppusamy commented 1 month ago

Proposal

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

Pressing SHIFT+TAB on the top section of the RHP updates the contents of the RHP.

What is the root cause of that problem?

{* Common wrapper for all the three screens *}
<ScreenWrapper
    includeSafeAreaPaddingBottom={false}
    shouldEnableKeyboardAvoidingView={false}
    shouldEnableMinHeight={DeviceCapabilities.canUseTouchScreen()}
    headerGapStyles={isDraggingOver ? [styles.receiptDropHeaderGap] : []}
    testID={IOURequestStartPage.displayName}
>
    {({safeAreaPaddingBottomStyle}) => (
        <DragAndDropProvider
            setIsDraggingOver={setIsDraggingOver}
            isDisabled={selectedTab !== CONST.TAB_REQUEST.SCAN}
        >
            <View style={[styles.flex1, safeAreaPaddingBottomStyle]}>
                <HeaderWithBackButton
                    title={tabTitles[iouType]}
                    onBackButtonPress={navigateBack}
                />
                {iouType !== CONST.IOU.TYPE.SEND && iouType !== CONST.IOU.TYPE.PAY && iouType !== CONST.IOU.TYPE.INVOICE ? (
                    <OnyxTabNavigator
                        id={CONST.TAB.IOU_REQUEST_TYPE}
                        onTabSelected={resetIOUTypeIfChanged}
                        tabBar={TabSelector}
                    >
                        <TopTab.Screen name={CONST.TAB_REQUEST.MANUAL}>
                            {() => (
                                <IOURequestStepAmount
                                    shouldKeepUserInput
                                    route={route}
                                />
                            )}
                        </TopTab.Screen>
                        <TopTab.Screen name={CONST.TAB_REQUEST.SCAN}>{() => <IOURequestStepScan route={route} />}</TopTab.Screen>
                        {shouldDisplayDistanceRequest && <TopTab.Screen name={CONST.TAB_REQUEST.DISTANCE}>{() => <IOURequestStepDistance route={route} />}</TopTab.Screen>}
                    </OnyxTabNavigator>
                ) : (
                    <IOURequestStepAmount route={route} />
                )}
            </View>
        </DragAndDropProvider>
    )}
</ScreenWrapper>

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

Update the below in src/pages/iou/request/IOURequestStartPage.tsx:

<ScreenWrapper
    includeSafeAreaPaddingBottom={false}
    shouldEnableKeyboardAvoidingView={false}
    shouldEnableMinHeight={DeviceCapabilities.canUseTouchScreen()}
    headerGapStyles={isDraggingOver ? [styles.receiptDropHeaderGap] : []}
    testID={IOURequestStartPage.displayName}
    selectedTab={selectedTab}
>
    {({safeAreaPaddingBottomStyle}) => (
        <DragAndDropProvider
            setIsDraggingOver={setIsDraggingOver}
            isDisabled={selectedTab !== CONST.TAB_REQUEST.SCAN}
        >
            <View style={[styles.flex1, safeAreaPaddingBottomStyle]}>
                <View id={`${CONST.TAB.IOU_REQUEST_TYPE}_header`}>
                    <HeaderWithBackButton
                        title={tabTitles[iouType]}
                        onBackButtonPress={navigateBack}
                    />
                </View>
                {iouType !== CONST.IOU.TYPE.SEND && iouType !== CONST.IOU.TYPE.PAY && iouType !== CONST.IOU.TYPE.INVOICE ? (
                    <OnyxTabNavigator
                        id={CONST.TAB.IOU_REQUEST_TYPE}
                        onTabSelected={resetIOUTypeIfChanged}
                        tabBar={(props) => (
                            <TabSelector
                                {...props}
                                id={`${CONST.TAB.IOU_REQUEST_TYPE}_tabsHeader`}
                            />
                        )}
                    >
                        <TopTab.Screen name={CONST.TAB_REQUEST.MANUAL}>
                            {() => (
                                <View
                                    id={CONST.TAB_REQUEST.MANUAL}
                                    style={{flex: 1}}
                                >
                                    <IOURequestStepAmount
                                        shouldKeepUserInput
                                        route={route}
                                    />
                                </View>
                            )}
                        </TopTab.Screen>
                        <TopTab.Screen name={CONST.TAB_REQUEST.SCAN}>
                            {() => (
                                <View
                                    id={CONST.TAB_REQUEST.SCAN}
                                    style={{flex: 1}}
                                >
                                    <IOURequestStepScan route={route} />
                                </View>
                            )}
                        </TopTab.Screen>
                        {shouldDisplayDistanceRequest && (
                            <TopTab.Screen name={CONST.TAB_REQUEST.DISTANCE}>
                                {() => (
                                    <View
                                        id={CONST.TAB_REQUEST.DISTANCE}
                                        style={{flex: 1}}
                                    >
                                        <IOURequestStepDistance route={route} />
                                    </View>
                                )}
                            </TopTab.Screen>
                        )}
                    </OnyxTabNavigator>
                ) : (
                    <IOURequestStepAmount route={route} />
                )}
            </View>
        </DragAndDropProvider>
    )}
</ScreenWrapper>

Update the below in src/components/ScreenWrapper.tsx:

Line 7: import type {OnyxEntry} from 'react-native-onyx';
Line 22: import type {SelectedTabRequest} from '@src/types/onyx';
Line 105:
/** The tab to select by default (whatever the user visited last) */
selectedTab?: OnyxEntry<SelectedTabRequest>;
Line 134: selectedTab,
Line 251: <FocusTrapForScreens selectedTab={selectedTab}>

Update the below in src/components/FocusTrap/FocusTrapForScreen/FocusTrapProps.ts:

import type { SelectedTabRequest } from "@src/types/onyx";
import type { OnyxEntry } from "react-native-onyx";

type FocusTrapForScreenProps = {
    children: React.ReactNode;
    selectedTab?: OnyxEntry<SelectedTabRequest>;
};

export default FocusTrapForScreenProps;

Update the below in src/components/FocusTrap/FocusTrapForScreen/index.web.tsx:

Line 12: function FocusTrapForScreen({children, selectedTab}: FocusTrapProps) {
Line 16: const [containerElements, setContainerElements] = useState<HTMLElement[]>([]);
Line 36: 
useEffect(() => {
    if (selectedTab) {
        const elements = [
            document.getElementById(`${CONST.TAB.IOU_REQUEST_TYPE}_header`),
            document.getElementById(`${CONST.TAB.IOU_REQUEST_TYPE}_tabsHeader`),
            document.getElementById(selectedTab),
        ];
        setContainerElements(() => elements.filter((el) => Boolean(el)));
    }
}, [selectedTab]);
Line 70: containerElements={isActive && containerElements?.length ? containerElements : undefined}

Update the below in src/components/TabSelector/TabSelector.tsx:

Line 17: id?: string;
Line 57: function TabSelector({state, navigation, onTabPress = () => {}, position, id}: TabSelectorProps) {
Line 87:
<View
    style={styles.tabSelector}
    id={id}
>

What alternative solutions did you explore? (Optional)

  1. We can fix this issue also by not rendering the contents of other screens i.e. when the Manual screen is in view, the contents of the Split & Distance screens shouldn't be rendered.
  1. Since the TAB navigation focus is already handled by focus-trap library, we can remove the below code block in src/pages/iou/request/IOURequestStartPage.tsx.

    useFocusEffect(
    useCallback(() => {
        const handler = (event: KeyboardEvent) => {
            if (event.code !== CONST.KEYBOARD_SHORTCUTS.TAB.shortcutKey) {
                return;
            }
            event.preventDefault();
            event.stopPropagation();
        };
        KeyDownPressListener.addKeyDownPressListener(handler);
    
        return () => KeyDownPressListener.removeKeyDownPressListener(handler);
    }, []),
    );

Update the below in src/pages/iou/request/IOURequestStartPage.tsx:

<AccessOrNotFoundWrapper
    reportID={reportID}
    iouType={iouType}
    policyID={policy?.id}
    accessVariants={[CONST.IOU.ACCESS_VARIANTS.CREATE]}
    allPolicies={allPolicies}
>
    <DragAndDropProvider
        setIsDraggingOver={setIsDraggingOver}
        isDisabled={selectedTab !== CONST.TAB_REQUEST.SCAN}
    >
        <View style={[styles.flex1]}>
            <View id={`${CONST.TAB.IOU_REQUEST_TYPE}_header`}>
                <HeaderWithBackButton
                    title={tabTitles[iouType]}
                    onBackButtonPress={navigateBack}
                />
            </View>
            {iouType !== CONST.IOU.TYPE.SEND && iouType !== CONST.IOU.TYPE.PAY && iouType !== CONST.IOU.TYPE.INVOICE ? (
                <OnyxTabNavigator
                    id={CONST.TAB.IOU_REQUEST_TYPE}
                    onTabSelected={resetIOUTypeIfChanged}
                    tabBar={(props) => (
                        <TabSelector
                            {...props}
                            id={`${CONST.TAB.IOU_REQUEST_TYPE}_tabsHeader`}
                        />
                    )}
                >
                    <TopTab.Screen name={CONST.TAB_REQUEST.MANUAL}>
                        {() => (
                            <View
                                id={CONST.TAB_REQUEST.MANUAL}
                                style={{flex: 1}}
                            >
                                <IOURequestStepAmount
                                    shouldKeepUserInput
                                    route={route}
                                />
                            </View>
                        )}
                    </TopTab.Screen>
                    <TopTab.Screen name={CONST.TAB_REQUEST.SCAN}>
                        {() => (
                            <View
                                id={CONST.TAB_REQUEST.SCAN}
                                style={{flex: 1}}
                            >
                                <IOURequestStepScan route={route} />
                            </View>
                        )}
                    </TopTab.Screen>
                    {shouldDisplayDistanceRequest && (
                        <TopTab.Screen name={CONST.TAB_REQUEST.DISTANCE}>
                            {() => (
                                <View
                                    id={CONST.TAB_REQUEST.DISTANCE}
                                    style={{flex: 1}}
                                >
                                    <IOURequestStepDistance route={route} />
                                </View>
                            )}
                        </TopTab.Screen>
                    )}
                </OnyxTabNavigator>
            ) : (
                <IOURequestStepAmount route={route} />
            )}
        </View>
    </DragAndDropProvider>
</AccessOrNotFoundWrapper>

Update the below in src/components/FocusTrap/FocusTrapForScreen/index.web.tsx:

Line no 10: import CONST from '@src/CONST';
Line no: 65:
containerElements={
    isActive && !!TOP_TAB_SCREENS.find((screen) => screen === route.name)
        ? [
                document.getElementById(`${CONST.TAB.IOU_REQUEST_TYPE}_header`),
                document.getElementById(`${CONST.TAB.IOU_REQUEST_TYPE}_tabsHeader`),
                document.getElementById(route.name),
            ]
        : undefined
}

Update the below in src/components/TabSelector/TabSelector.tsx:

Line no 17: id?: string;
Line no 57: function TabSelector({state, navigation, onTabPress = () => {}, position, id}: TabSelectorProps) {
Line no 87: 
<View
    style={styles.tabSelector}
    id={id}
>

Update the below in src/pages/iou/request/step/IOURequestStepAmount.tsx:

Line no 314: 
// shouldShowWrapper={!!backTo || isEditing}
shouldShowWrapper
hideHeader

Update the below in src/pages/iou/request/step/IOURequestStepDistance.tsx:

Line no 314: 
// shouldShowWrapper={!isCreatingNewRequest}
shouldShowWrapper
hideHeader

Update the below in src/pages/iou/request/step/IOURequestStepScan/index.tsx:

Line no 314: 
// shouldShowWrapper={!!backTo}
shouldShowWrapper
hideHeader

Update the below in src/pages/iou/request/step/StepScreenDragAndDropWrapper.tsx:

Line no 29: 
/** Hide the header when the wrapper is shown */
hideHeader?: boolean;
Line no 34:
function StepScreenDragAndDropWrapper({testID, hideHeader, headerTitle, onBackButtonPress, onEntryTransitionEnd, children, shouldShowWrapper}: StepScreenDragAndDropWrapperProps) {
Line no 55:
{!hideHeader ? (
    <HeaderWithBackButton
        title={headerTitle}
        onBackButtonPress={onBackButtonPress}
    />
) : null}

Update the below in src/pages/iou/request/step/StepScreenWrapper.tsx:

Line no 36: 
/** Hide the header when the wrapper is shown */
hideHeader?: boolean;
Line no 50: hideHeader,
Line no 68:
{!hideHeader ? (
    <HeaderWithBackButton
        title={headerTitle}
        onBackButtonPress={onBackButtonPress}
    />
) : null}

The id & other props are passed directly in the above changes for the purpose of creating a PoC. The additional ScreenWrapper in the IOURequestStartPage page is also removed with the above approach.

melvin-bot[bot] commented 1 month ago

📣 @vishnu-karuppusamy! 📣 Hey, it seems we don’t have your contributor details yet! You'll only have to do this once, and this is how we'll hire you on Upwork. Please follow these steps:

  1. Make sure you've read and understood the contributing guidelines.
  2. Get the email address used to login to your Expensify account. If you don't already have an Expensify account, create one here. If you have multiple accounts (e.g. one for testing), please use your main account email.
  3. Get the link to your Upwork profile. It's necessary because we only pay via Upwork. You can access it by logging in, and then clicking on your name. It'll look like this. If you don't already have an account, sign up for one here.
  4. Copy the format below and paste it in a comment on this issue. Replace the placeholder text with your actual details. Screen Shot 2022-11-16 at 4 42 54 PM Format:
    Contributor details
    Your Expensify account email: <REPLACE EMAIL HERE>
    Upwork Profile Link: <REPLACE LINK HERE>
vishnu-karuppusamy commented 1 month ago

Contributor details Your Expensify account email: vishnu566662@gmail.com Upwork Profile Link: https://www.upwork.com/freelancers/~01fded0233eaf38db6

melvin-bot[bot] commented 1 month ago

✅ Contributor details stored successfully. Thank you for contributing to Expensify!

OfstadC commented 1 month ago

@rayane-djouah could you please provide an update here by EOD?

rayane-djouah commented 1 month ago

I'm reviewing now

rayane-djouah commented 1 month ago

I've locally reverted the changes from PR 39520 and confirmed that it is responsible for the bug. @vishnu-karuppusamy - Thank you for your proposal. Can you identify which specific change in PR 39520 caused this bug?

I also have a few questions:

When a click is made on the top empty area on the RHP (like the empty header area), the focus gets initiated on the common FocusTrap wrapper. Pressing SHIFT+TAB focuses the last element on the DOM tree which is the Next button of the Distance screen. (In the issue repro video, we can observe that the Next button of the Distance screen is focused)

Could you clarify the cause of the current incorrect TAB navigation behavior on these "request start" pages? When the TAB key is pressed on the Manual tab, the focus is stuck on the "Next" button, and it does not shift to the tab switching buttons, currency switcher, or the back button. Additionally, when clicking on another tab and then pressing the TAB key, the focus is stuck on that tab button (e.g., the Distance button).

Video https://github.com/Expensify/App/assets/77965000/6f4b88b8-7afa-4373-b17b-8e2850aa7861

In contrast, the tab navigation works correctly in the assign task flow as seen here:

Video https://github.com/Expensify/App/assets/77965000/c5c36b31-9641-4b50-9581-169ee70a5456

Because of the translating nature of the Tabs component OnyxTabNavigator, the tabs (Manual, Scan, Distance) are translated to the left by 750px when the Next button of the Distance screen is focused. This is the reason behind missing of the tabs.

Could you elaborate more on this translation behavior?

Although your proposal addresses the "Tabs disappear when changing from Scan to Distance via SHIFT+TAB" bug, I believe we should also correct the tab navigation functionality on these pages as part of this issue.

After applying your changes (wrapping the tab screens with ScreenWrapper), the focus is trapped on a single button of the tab screen, as shown here:

Video https://github.com/Expensify/App/assets/77965000/faecd4ce-a343-4154-911a-b28cfe6c6ebd

Could you update your proposal to ensure that the tab navigation functions correctly on these screens? Thank you!

melvin-bot[bot] commented 1 month ago

@tgolen, @OfstadC, @rayane-djouah Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

rayane-djouah commented 1 month ago

Not overdue Melvin

tsa321 commented 1 month ago

Proposal

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

tab key navigation is broken/disabled in create IOU request RHP

What is the root cause of that problem?

In IOURequestStartPage we disable tab key navigation by this code:

https://github.com/Expensify/App/blob/b33542383ac2cb8ea1e922aa12dd2265efccd0ab/src/pages/iou/request/IOURequestStartPage.tsx#L79-L92

After removing the code, when iouerqueststartpage rendered, all tab screen content are also rendered, which make tab key navigation jump to other tab screen.

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

We must remove the code above that preventing tab key navigation.

Then in here:

https://github.com/Expensify/App/blob/b33542383ac2cb8ea1e922aa12dd2265efccd0ab/src/pages/iou/request/IOURequestStartPage.tsx#L154-L163

We set the content of tab screen to be null if selectedTab is difference than the tab screen names.

The code could be:

<TopTab.Screen name={CONST.TAB_REQUEST.MANUAL}>
        {() => (selectedTab === CONST.TAB_REQUEST.MANUAL) ? (
            <IOURequestStepAmount
                shouldKeepUserInput
                route={route}
            />
        ) : null}
    </TopTab.Screen>
    <TopTab.Screen name={CONST.TAB_REQUEST.SCAN}>{() => (selectedTab === CONST.TAB_REQUEST.SCAN) ? <IOURequestStepScan route={route} /> : null}</TopTab.Screen>
    {shouldDisplayDistanceRequest && <TopTab.Screen name={CONST.TAB_REQUEST.DISTANCE}>{() => selectedTab === CONST.TAB_REQUEST.DISTANCE ? <IOURequestStepDistance route={route} /> : null}</TopTab.Screen>}

To prevent re-rendering instead of returning null, we can use css styling to set the visibility of the content.

rayane-djouah commented 1 month ago

@tsa321 - Thank you for your proposal. Your proposal focuses on the disabled tab navigation but doesn't explain the cause of this bug. The code that you suggest to remove was added in this PR: https://github.com/Expensify/App/pull/35154 to fix this bug: https://github.com/Expensify/App/issues/36513. We need to ensure that we don't reintroduce the bug.

We set the content of the tab screen to be null if the selectedTab is different from the tab screen names.

I don't think that this solution is good for app performance because the tab screens' content will be rerendered on each tab switch.

When I tested your solution, the app crashed with a console error:

Screenshot Screenshot 2024-06-18 at 11:03:14 PM
tsa321 commented 1 month ago

@rayane-djouah I am sorry there must be an error when I beautify the code.

please try this code:

<TopTab.Screen name={CONST.TAB_REQUEST.MANUAL}>
        {() => (selectedTab === CONST.TAB_REQUEST.MANUAL) ? (
            <IOURequestStepAmount
                shouldKeepUserInput
                route={route}
            />
        ) : null}
    </TopTab.Screen>
    <TopTab.Screen name={CONST.TAB_REQUEST.SCAN}>{() => (selectedTab === CONST.TAB_REQUEST.SCAN) ? <IOURequestStepScan route={route} /> : null}</TopTab.Screen>
    {shouldDisplayDistanceRequest && <TopTab.Screen name={CONST.TAB_REQUEST.DISTANCE}>{() => selectedTab === CONST.TAB_REQUEST.DISTANCE ? <IOURequestStepDistance route={route} /> : null}</TopTab.Screen>}

Your proposal focuses on the disabled tab navigation but doesn't explain the cause of this bug.

I have explained briefly in RCA:

After removing the code, when iouerqueststartpage rendered, all tab screen content are also rendered, which make tab key navigation jump to other tab screen. I should mention about tab bar buttons disappears too.

The code that you suggest to remove was added in this PR: https://github.com/Expensify/App/pull/35154 to fix this bug: https://github.com/Expensify/App/issues/36513. We need to ensure that we don't reintroduce the bug.

I think what you mean is: to fix https://github.com/Expensify/App/issues/26326 and not #36513 , right?

It is working fine now using my proposal:

https://github.com/Expensify/App/assets/114975543/de1f1644-bc29-4766-b47d-bf8a05545edf

vishnu-karuppusamy commented 1 month ago

@rayane-djouah thanks for the reply. Please find the below explanation for the questions raised.

Could you clarify the cause of the current incorrect TAB navigation behavior on these "request start" pages? When the TAB key is pressed on the Manual tab, the focus is stuck on the "Next" button, and it does not shift to the tab switching buttons, currency switcher, or the back button. Additionally, when clicking on another tab and then pressing the TAB key, the focus is stuck on that tab button (e.g., the Distance button).

In contrast, the tab navigation works correctly in the assign task flow as seen here:

Irrespective of the pages, the TAB navigation behavior remains the same i.e. pressing TAB will move focus to the next interactive element in the DOM tree and SHIFT+TAB will move focus to the previous interactive element. In assign task flow, all the interactive elements (back button, title & description input and next button) are in the same DOM tree. Hence the TAB navigation behaviour works as expected.

In the request start pages, all the tabs content (Manuel, Split & Distance) are rendered simultaneously in the same DOM tree. So the TAB navigation behavior follows the below order.

  1. RHP's header back button
  2. All the tabBars buttons (Manual, Split & Distance)
  3. Interactive elements in the Manual tab such as currency selection dropdown, amount input field & Next button.
  4. Interactive elements in the Split tab such as choose file button & so on.
  5. Interactive elements in the Distance tab such as Start & Stop menu items, Mapbox & Next button.

Issue root cause explanation:

In-order to have correct TAB navigation behavior, I've updated the initial proposal as follows.

tsa321 commented 1 month ago

@vishnu-karuppusamy I think what you suggested above is similar to my proposal and it is really different with your original proposal.

rayane-djouah commented 1 month ago

@vishnu-karuppusamy, @tsa321, please follow the rule from CONTRIBUTING.md:

  • If you want to make an entirely new proposal or update an existing proposal, please go back and edit your original proposal, then post a new comment to the issue in this format to alert everyone that it has been updated:
    ## Proposal
    [Updated](link to proposal)

    And include brief details of what has been updated.

rayane-djouah commented 1 month ago

@tsa321 - Setting the content of tab screen to null if selectedTab is different than the tab screen names cause the tab screen to re-render on every tab change causing performance issue:

Video https://github.com/Expensify/App/assets/77965000/87671bb6-1e41-4517-8220-883ee8134c48
rayane-djouah commented 1 month ago

I think what you mean is: to fix https://github.com/Expensify/App/issues/26326 and not https://github.com/Expensify/App/issues/36513 , right?

Correct. @vishnu-karuppusamy, @tsa321, I recommend you to read through https://github.com/Expensify/App/issues/26326 which is a similar bug.

rayane-djouah commented 1 month ago

@vishnu-karuppusamy - The idea of setting the hidden style to tab screen content if it's not focused is working correctly, but I think that there is a better solution than that. I think that the a better solution is to use focus trap functionality to fix this issue.

@vishnu-karuppusamy - I dont't understand something in your proposal: IOURequestStepAmount, IOURequestStepScan, and IOURequestStepDistance all have a ScreenWrapper under the hood, I don't see why we need to wrap them with a ScreenWrapper.

rayane-djouah commented 1 month ago

@vishnu-karuppusamy, @tsa321, upon investigating I found that we have already this condition to activate focus trap for currently shown tab only, but why it's not working?

https://github.com/Expensify/App/blob/362953d307fb97ff56e90cb5458f887b4b4132b1/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx#L24-L27

rayane-djouah commented 1 month ago

@vishnu-karuppusamy, @tsa321, I'm looking for a proposal that: 1- Thoroughly explains the root cause of this bug. 2- Removes this code to ensure that the tab navigation functions correctly. 3- Use focus trap to prevent focusing on elements of tab screens that are not visible.

Note: This bug is also happening in NewChatSelectorPage.

vishnu-karuppusamy commented 1 month ago

@vishnu-karuppusamy - The idea of setting the hidden style to tab screen content if it's not focused is working correctly, but I think that there is a better solution than that. I think that the a better solution is to use focus trap functionality to fix this issue.

@vishnu-karuppusamy - I dont't understand something in your proposal: IOURequestStepAmount, IOURequestStepScan, and IOURequestStepDistance all have a ScreenWrapper under the hood, I don't see why we need to wrap them with a ScreenWrapper.

Yes, I'm aware that IOURequestStepAmount, IOURequestStepScan, and IOURequestStepDistance all have a ScreenWrapper under the hood. But the RHP's header section and the tab button (Manual, Split & Distance) are not a part of each page's TAB navigation DOM tree. So we need to have a common DOM under a ScreenWrapper to cycle through interactive elements.

rayane-djouah commented 4 weeks ago

@vishnu-karuppusamy - I've tested wrapping IOURequestStepAmount, IOURequestStepScan, and IOURequestStepDistance with ScreenWrapper, but it does not fix the bug; it is also not making sense to me.

rayane-djouah commented 4 weeks ago

@vishnu-karuppusamy, @tsa321, please update your proposals based on my comments and tag me again once it's ready for another review

melvin-bot[bot] commented 4 weeks ago

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

rayane-djouah commented 4 weeks ago

Still looking for better proposals

vishnu-karuppusamy commented 4 weeks ago

Proposal

Updated

@rayane-djouah Updated the below sections:

  1. What changes do you think we should make in order to solve the problem?
  2. What alternative solutions did you explore? (Optional)
tsa321 commented 3 weeks ago

@rayane-djouah: If, for example (just for example) the alternative proposal from @vishnu-karuppusamy is accepted, I would argue based on:

https://github.com/Expensify/App/blob/b021195b864211efbaaefe188226b2830b91b7d8/contributingGuides/CONTRIBUTING.md

After you reproduce the issue, complete the proposal template here and post it as a comment in the corresponding GitHub issue (linked in the Upwork job). Note: Before submitting a proposal on an issue, be sure to read any other existing proposals. ALL NEW PROPOSALS MUST BE DIFFERENT FROM EXISTING PROPOSALS. The difference should be important, meaningful or considerable.

The alternative solution differs significantly from his initial proposal and closely aligns with mine.

rayane-djouah commented 3 weeks ago

I will review tommorow

OfstadC commented 3 weeks ago

Friendly bump @rayane-djouah 😃

rayane-djouah commented 3 weeks ago

@vishnu-karuppusamy - ScreenWrapper should be included on all pages by our guidelines, Also removing ScreenWrapper from IOURequestStartPage causes the elements behind the right-hand panel to be focusable:

Video https://github.com/Expensify/App/assets/77965000/9aa9ae3b-5eb3-494a-b910-badc8aef437f

Also, I didn't understand the purpose of the other proposed changes.

rayane-djouah commented 3 weeks ago

Still looking for better proposals

vishnu-karuppusamy commented 3 weeks ago

@vishnu-karuppusamy - ScreenWrapper should be included on all pages by our guidelines, Also removing ScreenWrapper from IOURequestStartPage causes the elements behind the right-hand panel to be focusable:

Video Screen.Recording.2024-06-26.at.1.18.50.AM.mov Also, I didn't understand the purpose of the other proposed changes.

@rayane-djouah with the proposed updates, the common ScreenWrapper for all the tabs is removed. But each tab has its own ScreenWrapper which is enabled based on the selection.

The major difference from the initial proposal is that we are utilizing the prop containerElements from the focus-trap-react library. In the proposal the fix is only applied for the IOURequestStartPage, if needed, I can propose the same for the chat page as well.

https://github.com/Expensify/App/assets/133900001/932f99fe-a5d2-407f-b994-be0f1043e821

vishnu-karuppusamy commented 3 weeks ago

@vishnu-karuppusamy - I dont't understand something in your proposal: IOURequestStepAmount, IOURequestStepScan, and IOURequestStepDistance all have a ScreenWrapper under the hood, I don't see why we need to wrap them with a ScreenWrapper.

@rayane-djouah Based on your previous reply, I thought you suggested removing the wrapping ScreenWrapper if it's unnecessary.

rayane-djouah commented 3 weeks ago

@rayane-djouah with the proposed updates, the common ScreenWrapper for all the tabs is removed. But each tab has its own ScreenWrapper which is enabled based on the selection.

We still need the ScreenWrapper for the right-hand panel to prevent this bug

@rayane-djouah Based on your previous reply, I thought you suggested removing the wrapping ScreenWrapper if it's unnecessary.

You've proposed that we wrap each tab screen with a screen wrapper, and I've commented that they are already wrapped under the hood. I didn't meant the outer ScreenWrapper

The major difference from the initial proposal is that we are utilizing the prop containerElements from the focus-trap-react library. In the proposal the fix is only applied for the IOURequestStartPage, if needed, I can propose the same for the chat page as well.

Can you please elaborate more on this solution? and its relation with the RCA?

melvin-bot[bot] commented 3 weeks ago

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

melvin-bot[bot] commented 3 weeks ago

@tgolen @OfstadC @rayane-djouah 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!

rayane-djouah commented 3 weeks ago

Posted in Slack to get more 👀: https://expensify.enterprise.slack.com/archives/C01GTK53T8Q/p1719429382691979

OfstadC commented 2 weeks ago

Any update @rayane-djouah ? 😃

rayane-djouah commented 2 weeks ago

Waiting on proposals

rayane-djouah commented 2 weeks ago

@OfstadC - can we consider raising the bounty to get more proposals?