Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: default the selected tab to scan #47310

Merged
merged 3 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 31 additions & 35 deletions src/libs/Navigation/OnyxTabNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import {createMaterialTopTabNavigator} from '@react-navigation/material-top-tabs
import type {EventMapCore, NavigationState, ScreenListeners} from '@react-navigation/native';
import {useRoute} from '@react-navigation/native';
import React, {useCallback, useContext, useEffect, useState} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import FocusTrapContainerElement from '@components/FocusTrap/FocusTrapContainerElement';
import type {TabSelectorProps} from '@components/TabSelector/TabSelector';
import useThemeStyles from '@hooks/useThemeStyles';
Expand All @@ -13,40 +12,36 @@ import Tab from '@userActions/Tab';
import ONYXKEYS from '@src/ONYXKEYS';
import type {SelectedTabRequest} from '@src/types/onyx';
import type ChildrenProps from '@src/types/utils/ChildrenProps';
import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
import {defaultScreenOptions} from './OnyxTabNavigatorConfig';

type OnyxTabNavigatorOnyxProps = {
selectedTab: OnyxEntry<SelectedTabRequest>;
};

type OnyxTabNavigatorProps = OnyxTabNavigatorOnyxProps &
ChildrenProps & {
/** ID of the tab component to be saved in onyx */
id: string;
type OnyxTabNavigatorProps = ChildrenProps & {
/** ID of the tab component to be saved in onyx */
id: string;

/** Name of the selected tab */
selectedTab?: SelectedTabRequest;
/** Name of the selected tab */
defaultSelectedTab?: SelectedTabRequest;

/** A function triggered when a tab has been selected */
onTabSelected?: (newIouType: IOURequestType) => void;
/** A function triggered when a tab has been selected */
onTabSelected?: (newIouType: IOURequestType) => void;

tabBar: (props: TabSelectorProps) => React.ReactNode;
tabBar: (props: TabSelectorProps) => React.ReactNode;

screenListeners?: ScreenListeners<NavigationState, MaterialTopTabNavigationEventMap>;
screenListeners?: ScreenListeners<NavigationState, MaterialTopTabNavigationEventMap>;

/** Callback to register the focus trap container elements of the current active tab.
* Use this in the parent component to get the focus trap container element of the active tab,
* then pass it to the ScreenWrapper so that only focusable elements of the active tab are included in the focus trap
* Check the `IOURequestStartPage.tsx` and `NewChatSelectorPage.tsx` components for example usage
*/
onActiveTabFocusTrapContainerElementChanged?: (containerElement: HTMLElement | null) => void;
/** Callback to register the focus trap container elements of the current active tab.
* Use this in the parent component to get the focus trap container element of the active tab,
* then pass it to the ScreenWrapper so that only focusable elements of the active tab are included in the focus trap
* Check the `IOURequestStartPage.tsx` and `NewChatSelectorPage.tsx` components for example usage
*/
onActiveTabFocusTrapContainerElementChanged?: (containerElement: HTMLElement | null) => void;

/** Callback to register the focus trap container elements of the tab bar.
* This callback is useful when the custom-rendered tab bar is supporting the focus trap container element registration (which is the case of `TabSelector.tsx` component).
* Together, with the `onActiveTabFocusTrapContainerElementChanged` callback, we can manage the focus trap of the tab navigator in the parent component.
*/
onTabBarFocusTrapContainerElementChanged?: (containerElement: HTMLElement | null) => void;
};
/** Callback to register the focus trap container elements of the tab bar.
* This callback is useful when the custom-rendered tab bar is supporting the focus trap container element registration (which is the case of `TabSelector.tsx` component).
* Together, with the `onActiveTabFocusTrapContainerElementChanged` callback, we can manage the focus trap of the tab navigator in the parent component.
*/
onTabBarFocusTrapContainerElementChanged?: (containerElement: HTMLElement | null) => void;
};

// eslint-disable-next-line rulesdir/no-inline-named-export
const TopTab = createMaterialTopTabNavigator();
Expand All @@ -60,7 +55,7 @@ const TabFocusTrapContext = React.createContext<(tabName: string, containerEleme
// It also takes 2 more optional callbacks to manage the focus trap container elements of the tab bar and the active tab
function OnyxTabNavigator({
id,
selectedTab,
defaultSelectedTab,
tabBar: TabBar,
children,
onTabBarFocusTrapContainerElementChanged,
Expand All @@ -71,6 +66,7 @@ function OnyxTabNavigator({
}: OnyxTabNavigatorProps) {
// Mapping of tab name to focus trap container element
const [focusTrapContainerElementMapping, setFocusTrapContainerElementMapping] = useState<Record<string, HTMLElement>>({});
const [selectedTab, selectedTabResult] = useOnyx(`${ONYXKEYS.COLLECTION.SELECTED_TAB}${id}`);

// This callback is used to register the focus trap container element of each avaiable tab screen
const setTabFocusTrapContainerElement = useCallback((tabName: string, containerElement: HTMLElement | null) => {
Expand Down Expand Up @@ -107,13 +103,17 @@ function OnyxTabNavigator({
onActiveTabFocusTrapContainerElementChanged?.(selectedTab ? focusTrapContainerElementMapping[selectedTab] : null);
}, [selectedTab, focusTrapContainerElementMapping, onActiveTabFocusTrapContainerElementChanged]);

if (isLoadingOnyxValue(selectedTabResult)) {
return null;
}
Comment on lines +106 to +108
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, this issue #50098 was a missed case in this PR. More details can be found in this proposal: #50098 (comment)


dominictb marked this conversation as resolved.
Show resolved Hide resolved
return (
<TabFocusTrapContext.Provider value={setTabFocusTrapContainerElement}>
<TopTab.Navigator
/* eslint-disable-next-line react/jsx-props-no-spreading */
{...rest}
id={id}
initialRouteName={selectedTab}
initialRouteName={selectedTab ?? defaultSelectedTab}
backBehavior="initialRoute"
keyboardDismissMode="none"
tabBar={TabBarWithFocusTrapInclusion}
Expand Down Expand Up @@ -176,10 +176,6 @@ function TabScreenWithFocusTrapWrapper({children}: {children?: React.ReactNode})

OnyxTabNavigator.displayName = 'OnyxTabNavigator';

export default withOnyx<OnyxTabNavigatorProps, OnyxTabNavigatorOnyxProps>({
selectedTab: {
key: ({id}) => `${ONYXKEYS.COLLECTION.SELECTED_TAB}${id}`,
},
})(OnyxTabNavigator);
export default OnyxTabNavigator;

export {TabScreenWithFocusTrapWrapper, TopTab};
1 change: 1 addition & 0 deletions src/pages/iou/request/IOURequestStartPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ function IOURequestStartPage({
{iouType !== CONST.IOU.TYPE.SEND && iouType !== CONST.IOU.TYPE.PAY && iouType !== CONST.IOU.TYPE.INVOICE ? (
<OnyxTabNavigator
id={CONST.TAB.IOU_REQUEST_TYPE}
defaultSelectedTab={CONST.TAB_REQUEST.SCAN}
onTabSelected={resetIOUTypeIfChanged}
tabBar={TabSelector}
onTabBarFocusTrapContainerElementChanged={setTabBarContainerElement}
Expand Down
Loading