From 1e7e0bf6a952397f07e230b0a77f06a7a04ef9c1 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 18 Jun 2024 09:54:01 +0200 Subject: [PATCH 001/257] Replace FullScreenNavigator with SplitNavigator --- .../Navigators/FullScreenNavigator.tsx | 49 ++++++-------- .../index.native.tsx | 36 ----------- .../createCustomFullScreenNavigator/types.ts | 8 --- .../SplitRouter.ts} | 29 ++++----- .../createSplitNavigator/index.tsx | 64 +++++++++++++++++++ .../createSplitNavigator/types.ts | 11 ++++ .../useNavigationReset/index.native.ts | 1 + .../useNavigationReset/index.ts | 14 ++++ .../usePrepareSplitNavigatorChildren.ts | 23 +++++++ 9 files changed, 144 insertions(+), 91 deletions(-) delete mode 100644 src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.native.tsx delete mode 100644 src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/types.ts rename src/libs/Navigation/AppNavigator/{createCustomFullScreenNavigator/CustomFullScreenRouter.tsx => createSplitNavigator/SplitRouter.ts} (74%) create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts diff --git a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx index 2f513fe804bb..c25ad91e4a45 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx @@ -1,18 +1,12 @@ import React from 'react'; -import {View} from 'react-native'; -import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import useStyleUtils from '@hooks/useStyleUtils'; -import useThemeStyles from '@hooks/useThemeStyles'; -import createCustomFullScreenNavigator from '@libs/Navigation/AppNavigator/createCustomFullScreenNavigator'; -import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; +import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; const loadWorkspaceInitialPage = () => require('../../../../pages/workspace/WorkspaceInitialPage').default; -const RootStack = createCustomFullScreenNavigator(); +const RootStack = createSplitNavigator(); type Screens = Partial React.ComponentType>>; @@ -34,30 +28,23 @@ const CENTRAL_PANE_WORKSPACE_SCREENS = { } satisfies Screens; function FullScreenNavigator() { - const styles = useThemeStyles(); - const StyleUtils = useStyleUtils(); - const {shouldUseNarrowLayout} = useResponsiveLayout(); - const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); - return ( - - - - - {Object.entries(CENTRAL_PANE_WORKSPACE_SCREENS).map(([screenName, componentGetter]) => ( - - ))} - - - + + + {Object.entries(CENTRAL_PANE_WORKSPACE_SCREENS).map(([screenName, componentGetter]) => ( + + ))} + ); } diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.native.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.native.tsx deleted file mode 100644 index 2f61f1519df0..000000000000 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.native.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native'; -import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; -import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; -import {StackView} from '@react-navigation/stack'; -import CustomFullScreenRouter from './CustomFullScreenRouter'; -import type {FullScreenNavigatorProps, FullScreenNavigatorRouterOptions} from './types'; - -function CustomFullScreenNavigator(props: FullScreenNavigatorProps) { - const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< - StackNavigationState, - FullScreenNavigatorRouterOptions, - StackActionHelpers, - StackNavigationOptions, - StackNavigationEventMap - >(CustomFullScreenRouter, { - children: props.children, - screenOptions: props.screenOptions, - initialRouteName: props.initialRouteName, - }); - - return ( - - - - ); -} - -CustomFullScreenNavigator.displayName = 'CustomFullScreenNavigator'; - -export default createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, typeof CustomFullScreenNavigator>(CustomFullScreenNavigator); diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/types.ts b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/types.ts deleted file mode 100644 index 7e7808c003d7..000000000000 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; -import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; - -type FullScreenNavigatorRouterOptions = StackRouterOptions; - -type FullScreenNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap>; - -export type {FullScreenNavigatorProps, FullScreenNavigatorRouterOptions}; diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts similarity index 74% rename from src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx rename to src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts index 7dc66d06fd4a..9a81978f46e7 100644 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts @@ -1,19 +1,17 @@ import type {ParamListBase, PartialState, RouterConfigOptions, StackNavigationState} from '@react-navigation/native'; import {StackRouter} from '@react-navigation/native'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import SCREENS from '@src/SCREENS'; -import type {FullScreenNavigatorRouterOptions} from './types'; +import type {SplitNavigatorRouterOptions} from './types'; type StackState = StackNavigationState | PartialState>; const isAtLeastOneInState = (state: StackState, screenName: string): boolean => state.routes.some((route) => route.name === screenName); -function adaptStateIfNecessary(state: StackState) { +function adaptStateIfNecessary(state: StackState, sidebarScreen: keyof ParamListBase, initialCentralPaneScreen: keyof ParamListBase) { const isNarrowLayout = getIsNarrowLayout(); const workspaceCentralPane = state.routes.at(-1); - - // There should always be WORKSPACE.INITIAL screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings. - if (!isAtLeastOneInState(state, SCREENS.WORKSPACE.INITIAL)) { + // There should always be sidebarScreen screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings. + if (!isAtLeastOneInState(state, sidebarScreen)) { // @ts-expect-error Updating read only property // noinspection JSConstantReassignment state.stale = true; // eslint-disable-line @@ -22,24 +20,24 @@ function adaptStateIfNecessary(state: StackState) { if (state.stale === true) { // Unshift the root screen to fill left pane. state.routes.unshift({ - name: SCREENS.WORKSPACE.INITIAL, + name: sidebarScreen, params: workspaceCentralPane?.params, }); } } // If the screen is wide, there should be at least two screens inside: - // - WORKSPACE.INITIAL to cover left pane. - // - WORKSPACE.PROFILE (first workspace settings screen) to cover central pane. + // - sidebarScreen to cover left pane. + // - initialCentralPaneScreen to cover central pane. if (!isNarrowLayout) { - if (state.routes.length === 1 && state.routes[0].name === SCREENS.WORKSPACE.INITIAL) { + if (state.routes.length === 1 && state.routes[0].name === sidebarScreen) { // @ts-expect-error Updating read only property // noinspection JSConstantReassignment state.stale = true; // eslint-disable-line // Push the default settings central pane screen. if (state.stale === true) { state.routes.push({ - name: SCREENS.WORKSPACE.PROFILE, + name: initialCentralPaneScreen, params: state.routes.at(0)?.params, }); } @@ -49,14 +47,13 @@ function adaptStateIfNecessary(state: StackState) { } } -function CustomFullScreenRouter(options: FullScreenNavigatorRouterOptions) { +function SplitRouter(options: SplitNavigatorRouterOptions) { const stackRouter = StackRouter(options); - return { ...stackRouter, getInitialState({routeNames, routeParamList, routeGetIdList}: RouterConfigOptions) { const initialState = stackRouter.getInitialState({routeNames, routeParamList, routeGetIdList}); - adaptStateIfNecessary(initialState); + adaptStateIfNecessary(initialState, options.sidebarScreen, options.initialCentralPaneScreen); // If we needed to modify the state we need to rehydrate it to get keys for new routes. if (initialState.stale) { @@ -66,11 +63,11 @@ function CustomFullScreenRouter(options: FullScreenNavigatorRouterOptions) { return initialState; }, getRehydratedState(partialState: StackState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): StackNavigationState { - adaptStateIfNecessary(partialState); + adaptStateIfNecessary(partialState, options.sidebarScreen, options.initialCentralPaneScreen); const state = stackRouter.getRehydratedState(partialState, {routeNames, routeParamList, routeGetIdList}); return state; }, }; } -export default CustomFullScreenRouter; +export default SplitRouter; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx new file mode 100644 index 000000000000..17ab209cfae8 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx @@ -0,0 +1,64 @@ +import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native'; +import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; +import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; +import {StackView} from '@react-navigation/stack'; +import React from 'react'; +import {View} from 'react-native'; +import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useStyleUtils from '@hooks/useStyleUtils'; +import useThemeStyles from '@hooks/useThemeStyles'; +import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; +import SplitRouter from './SplitRouter'; +import type {SplitNavigatorProps, SplitNavigatorRouterOptions} from './types'; +import useNavigationReset from './useNavigationReset'; +import usePrepareSplitNavigatorChildren from './usePrepareSplitNavigatorChildren'; + +function SplitNavigator(props: SplitNavigatorProps) { + const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); + const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); + + const children = usePrepareSplitNavigatorChildren(props.children, props.sidebarScreen, screenOptions.homeScreen); + + const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< + StackNavigationState, + SplitNavigatorRouterOptions, + StackActionHelpers, + StackNavigationOptions, + StackNavigationEventMap + >(SplitRouter, { + children, + screenOptions: screenOptions.centralPaneNavigator, + initialRouteName: props.initialRouteName, + sidebarScreen: props.sidebarScreen, + initialCentralPaneScreen: props.initialCentralPaneScreen, + }); + + useNavigationReset(navigation, shouldUseNarrowLayout); + + return ( + + + + + + + + ); +} + +SplitNavigator.displayName = 'SplitNavigator'; + +export default function () { + return createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, React.ComponentType>>( + SplitNavigator, + )(); +} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts new file mode 100644 index 000000000000..3b41f6f7a96d --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts @@ -0,0 +1,11 @@ +import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; +import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; + +type SplitNavigatorRouterOptions = StackRouterOptions & {initialCentralPaneScreen: string; sidebarScreen: string}; + +type SplitNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> & { + initialCentralPaneScreen: Extract; + sidebarScreen: Extract; +}; + +export type {SplitNavigatorProps, SplitNavigatorRouterOptions}; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts new file mode 100644 index 000000000000..5d5d30356781 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts @@ -0,0 +1 @@ +export default function useNavigationReset() {} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts new file mode 100644 index 000000000000..238fc1ca2928 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts @@ -0,0 +1,14 @@ +import type {NavigationHelpers, ParamListBase} from '@react-navigation/native'; +import {useEffect} from 'react'; +import navigationRef from '@libs/Navigation/navigationRef'; + +export default function useNavigationReset(navigation: NavigationHelpers, isSmallScreenWidth: boolean) { + useEffect(() => { + if (!navigationRef.isReady()) { + return; + } + // We need to separately reset state of this navigator to trigger getRehydratedState. + navigation.reset(navigation.getState()); + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps + }, [isSmallScreenWidth]); +} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts new file mode 100644 index 000000000000..ad05d1079328 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts @@ -0,0 +1,23 @@ +import type {StackNavigationOptions} from '@react-navigation/stack'; +import {Children, isValidElement, useMemo} from 'react'; +import type {ReactNode} from 'react'; + +export default function usePrepareSplitNavigatorChildren(screensNode: ReactNode, sidebarScreenName: string, sidebarScreenOptions: StackNavigationOptions) { + return useMemo( + () => + Children.toArray(screensNode).map((screen: ReactNode) => { + if (isValidElement(screen) && screen?.props?.name === sidebarScreenName) { + // If we found the element we wanted, clone it with the provided prop changes. + return { + ...screen, + props: { + ...screen.props, + options: sidebarScreenOptions, + }, + }; + } + return screen; + }), + [screensNode, sidebarScreenName, sidebarScreenOptions], + ); +} From 822327fca5d2e741b014a8289dc7564c75e5c71d Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 18 Jun 2024 09:56:25 +0200 Subject: [PATCH 002/257] Fix types in adaptStateIfNecessary --- .../Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts index 9a81978f46e7..526dd8197cd7 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts @@ -7,7 +7,7 @@ type StackState = StackNavigationState | PartialState state.routes.some((route) => route.name === screenName); -function adaptStateIfNecessary(state: StackState, sidebarScreen: keyof ParamListBase, initialCentralPaneScreen: keyof ParamListBase) { +function adaptStateIfNecessary(state: StackState, sidebarScreen: string, initialCentralPaneScreen: string) { const isNarrowLayout = getIsNarrowLayout(); const workspaceCentralPane = state.routes.at(-1); // There should always be sidebarScreen screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings. From 4708b331584cd898adb2a0f63538c4675ca55f53 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 19 Jun 2024 11:49:28 +0200 Subject: [PATCH 003/257] Rename Split to SplitStack --- .../Navigators/FullScreenNavigator.tsx | 4 ++-- .../createSplitNavigator/types.ts | 11 ---------- .../SplitStackRouter.ts} | 6 +++--- .../index.tsx | 20 +++++++++---------- .../createSplitStackNavigator/types.ts | 16 +++++++++++++++ .../useNavigationReset/index.native.ts | 0 .../useNavigationReset/index.ts | 0 .../usePrepareSplitStackNavigatorChildren.ts} | 2 +- 8 files changed, 32 insertions(+), 27 deletions(-) delete mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts rename src/libs/Navigation/AppNavigator/{createSplitNavigator/SplitRouter.ts => createSplitStackNavigator/SplitStackRouter.ts} (95%) rename src/libs/Navigation/AppNavigator/{createSplitNavigator => createSplitStackNavigator}/index.tsx (78%) create mode 100644 src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts rename src/libs/Navigation/AppNavigator/{createSplitNavigator => createSplitStackNavigator}/useNavigationReset/index.native.ts (100%) rename src/libs/Navigation/AppNavigator/{createSplitNavigator => createSplitStackNavigator}/useNavigationReset/index.ts (100%) rename src/libs/Navigation/AppNavigator/{createSplitNavigator/usePrepareSplitNavigatorChildren.ts => createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts} (84%) diff --git a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx index c25ad91e4a45..c87ac31cba23 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx @@ -1,12 +1,12 @@ import React from 'react'; -import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; +import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; const loadWorkspaceInitialPage = () => require('../../../../pages/workspace/WorkspaceInitialPage').default; -const RootStack = createSplitNavigator(); +const RootStack = createSplitStackNavigator(); type Screens = Partial React.ComponentType>>; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts deleted file mode 100644 index 3b41f6f7a96d..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; -import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; - -type SplitNavigatorRouterOptions = StackRouterOptions & {initialCentralPaneScreen: string; sidebarScreen: string}; - -type SplitNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> & { - initialCentralPaneScreen: Extract; - sidebarScreen: Extract; -}; - -export type {SplitNavigatorProps, SplitNavigatorRouterOptions}; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts similarity index 95% rename from src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts rename to src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts index 526dd8197cd7..794085568dda 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts @@ -1,7 +1,7 @@ import type {ParamListBase, PartialState, RouterConfigOptions, StackNavigationState} from '@react-navigation/native'; import {StackRouter} from '@react-navigation/native'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import type {SplitNavigatorRouterOptions} from './types'; +import type {SplitStackNavigatorRouterOptions} from './types'; type StackState = StackNavigationState | PartialState>; @@ -47,7 +47,7 @@ function adaptStateIfNecessary(state: StackState, sidebarScreen: string, initial } } -function SplitRouter(options: SplitNavigatorRouterOptions) { +function SplitStackRouter(options: SplitStackNavigatorRouterOptions) { const stackRouter = StackRouter(options); return { ...stackRouter, @@ -70,4 +70,4 @@ function SplitRouter(options: SplitNavigatorRouterOptions) { }; } -export default SplitRouter; +export default SplitStackRouter; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx similarity index 78% rename from src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx rename to src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index 17ab209cfae8..11a621b4d098 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -9,26 +9,26 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; -import SplitRouter from './SplitRouter'; -import type {SplitNavigatorProps, SplitNavigatorRouterOptions} from './types'; +import SplitStackRouter from './SplitStackRouter'; +import type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions} from './types'; import useNavigationReset from './useNavigationReset'; -import usePrepareSplitNavigatorChildren from './usePrepareSplitNavigatorChildren'; +import usePrepareSplitStackNavigatorChildren from './usePrepareSplitStackNavigatorChildren'; -function SplitNavigator(props: SplitNavigatorProps) { +function SplitStackNavigator(props: SplitStackNavigatorProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); - const children = usePrepareSplitNavigatorChildren(props.children, props.sidebarScreen, screenOptions.homeScreen); + const children = usePrepareSplitStackNavigatorChildren(props.children, props.sidebarScreen, screenOptions.homeScreen); const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< StackNavigationState, - SplitNavigatorRouterOptions, + SplitStackNavigatorRouterOptions, StackActionHelpers, StackNavigationOptions, StackNavigationEventMap - >(SplitRouter, { + >(SplitStackRouter, { children, screenOptions: screenOptions.centralPaneNavigator, initialRouteName: props.initialRouteName, @@ -55,10 +55,10 @@ function SplitNavigator(props: SplitNavigatorPr ); } -SplitNavigator.displayName = 'SplitNavigator'; +SplitStackNavigator.displayName = 'SplitStackNavigator'; export default function () { - return createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, React.ComponentType>>( - SplitNavigator, + return createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, React.ComponentType>>( + SplitStackNavigator, )(); } diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts new file mode 100644 index 000000000000..e721ca6301ed --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts @@ -0,0 +1,16 @@ +import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; +import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; + +type SplitStackNavigatorRouterOptions = StackRouterOptions & {initialCentralPaneScreen: string; sidebarScreen: string}; + +type SplitStackNavigatorProps = DefaultNavigatorOptions< + ParamListBase, + StackNavigationState, + StackNavigationOptions, + StackNavigationEventMap +> & { + initialCentralPaneScreen: Extract; + sidebarScreen: Extract; +}; + +export type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions}; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts rename to src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts rename to src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts similarity index 84% rename from src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts rename to src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts index ad05d1079328..d32e6b30f876 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts @@ -2,7 +2,7 @@ import type {StackNavigationOptions} from '@react-navigation/stack'; import {Children, isValidElement, useMemo} from 'react'; import type {ReactNode} from 'react'; -export default function usePrepareSplitNavigatorChildren(screensNode: ReactNode, sidebarScreenName: string, sidebarScreenOptions: StackNavigationOptions) { +export default function usePrepareSplitStackNavigatorChildren(screensNode: ReactNode, sidebarScreenName: string, sidebarScreenOptions: StackNavigationOptions) { return useMemo( () => Children.toArray(screensNode).map((screen: ReactNode) => { From 97a4c076bb70a2daf465f7c691e19a6cc45b25b1 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 19 Jun 2024 11:55:32 +0200 Subject: [PATCH 004/257] Rename useNavigationReset to useHandleScreenResize --- .../AppNavigator/createSplitStackNavigator/index.tsx | 4 ++-- .../useHandleScreenResize/index.native.ts | 1 + .../{useNavigationReset => useHandleScreenResize}/index.ts | 7 +++++-- .../useNavigationReset/index.native.ts | 1 - 4 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 src/libs/Navigation/AppNavigator/createSplitStackNavigator/useHandleScreenResize/index.native.ts rename src/libs/Navigation/AppNavigator/createSplitStackNavigator/{useNavigationReset => useHandleScreenResize}/index.ts (67%) delete mode 100644 src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index 11a621b4d098..d8914dcd0b80 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -11,7 +11,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; import SplitStackRouter from './SplitStackRouter'; import type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions} from './types'; -import useNavigationReset from './useNavigationReset'; +import useHandleScreenResize from './useHandleScreenResize'; import usePrepareSplitStackNavigatorChildren from './usePrepareSplitStackNavigatorChildren'; function SplitStackNavigator(props: SplitStackNavigatorProps) { @@ -36,7 +36,7 @@ function SplitStackNavigator(props: SplitStackN initialCentralPaneScreen: props.initialCentralPaneScreen, }); - useNavigationReset(navigation, shouldUseNarrowLayout); + useHandleScreenResize(navigation); return ( diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useHandleScreenResize/index.native.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useHandleScreenResize/index.native.ts new file mode 100644 index 000000000000..4ac0a1ae5595 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useHandleScreenResize/index.native.ts @@ -0,0 +1 @@ +export default function useHandleScreenResize() {} diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useHandleScreenResize/index.ts similarity index 67% rename from src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts rename to src/libs/Navigation/AppNavigator/createSplitStackNavigator/useHandleScreenResize/index.ts index 238fc1ca2928..e6ae505cb560 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useHandleScreenResize/index.ts @@ -1,8 +1,11 @@ import type {NavigationHelpers, ParamListBase} from '@react-navigation/native'; import {useEffect} from 'react'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import navigationRef from '@libs/Navigation/navigationRef'; -export default function useNavigationReset(navigation: NavigationHelpers, isSmallScreenWidth: boolean) { +export default function useHandleScreenResize(navigation: NavigationHelpers) { + const {shouldUseNarrowLayout} = useResponsiveLayout(); + useEffect(() => { if (!navigationRef.isReady()) { return; @@ -10,5 +13,5 @@ export default function useNavigationReset(navigation: NavigationHelpers Date: Wed, 19 Jun 2024 12:22:48 +0200 Subject: [PATCH 005/257] Rename initialCentralPaneScreen to defaultCentralScreen --- .../AppNavigator/Navigators/FullScreenNavigator.tsx | 2 +- .../createSplitStackNavigator/SplitStackRouter.ts | 10 +++++----- .../AppNavigator/createSplitStackNavigator/index.tsx | 2 +- .../AppNavigator/createSplitStackNavigator/types.ts | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx index c87ac31cba23..0024941d3ebc 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/FullScreenNavigator.tsx @@ -31,7 +31,7 @@ function FullScreenNavigator() { return ( | PartialState state.routes.some((route) => route.name === screenName); -function adaptStateIfNecessary(state: StackState, sidebarScreen: string, initialCentralPaneScreen: string) { +function adaptStateIfNecessary(state: StackState, sidebarScreen: string, defaultCentralScreen: string) { const isNarrowLayout = getIsNarrowLayout(); const workspaceCentralPane = state.routes.at(-1); // There should always be sidebarScreen screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings. @@ -28,7 +28,7 @@ function adaptStateIfNecessary(state: StackState, sidebarScreen: string, initial // If the screen is wide, there should be at least two screens inside: // - sidebarScreen to cover left pane. - // - initialCentralPaneScreen to cover central pane. + // - defaultCentralScreen to cover central pane. if (!isNarrowLayout) { if (state.routes.length === 1 && state.routes[0].name === sidebarScreen) { // @ts-expect-error Updating read only property @@ -37,7 +37,7 @@ function adaptStateIfNecessary(state: StackState, sidebarScreen: string, initial // Push the default settings central pane screen. if (state.stale === true) { state.routes.push({ - name: initialCentralPaneScreen, + name: defaultCentralScreen, params: state.routes.at(0)?.params, }); } @@ -53,7 +53,7 @@ function SplitStackRouter(options: SplitStackNavigatorRouterOptions) { ...stackRouter, getInitialState({routeNames, routeParamList, routeGetIdList}: RouterConfigOptions) { const initialState = stackRouter.getInitialState({routeNames, routeParamList, routeGetIdList}); - adaptStateIfNecessary(initialState, options.sidebarScreen, options.initialCentralPaneScreen); + adaptStateIfNecessary(initialState, options.sidebarScreen, options.defaultCentralScreen); // If we needed to modify the state we need to rehydrate it to get keys for new routes. if (initialState.stale) { @@ -63,7 +63,7 @@ function SplitStackRouter(options: SplitStackNavigatorRouterOptions) { return initialState; }, getRehydratedState(partialState: StackState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): StackNavigationState { - adaptStateIfNecessary(partialState, options.sidebarScreen, options.initialCentralPaneScreen); + adaptStateIfNecessary(partialState, options.sidebarScreen, options.defaultCentralScreen); const state = stackRouter.getRehydratedState(partialState, {routeNames, routeParamList, routeGetIdList}); return state; }, diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index d8914dcd0b80..ea3c8ecad21b 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -33,7 +33,7 @@ function SplitStackNavigator(props: SplitStackN screenOptions: screenOptions.centralPaneNavigator, initialRouteName: props.initialRouteName, sidebarScreen: props.sidebarScreen, - initialCentralPaneScreen: props.initialCentralPaneScreen, + defaultCentralScreen: props.defaultCentralScreen, }); useHandleScreenResize(navigation); diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts index e721ca6301ed..5e62b4e710a6 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts @@ -1,7 +1,7 @@ import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; -type SplitStackNavigatorRouterOptions = StackRouterOptions & {initialCentralPaneScreen: string; sidebarScreen: string}; +type SplitStackNavigatorRouterOptions = StackRouterOptions & {defaultCentralScreen: string; sidebarScreen: string}; type SplitStackNavigatorProps = DefaultNavigatorOptions< ParamListBase, @@ -9,7 +9,7 @@ type SplitStackNavigatorProps = DefaultNavigato StackNavigationOptions, StackNavigationEventMap > & { - initialCentralPaneScreen: Extract; + defaultCentralScreen: Extract; sidebarScreen: Extract; }; From 8ca90ba7c13553fdeefd12634a3496735c40a5a5 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 19 Jun 2024 13:45:01 +0200 Subject: [PATCH 006/257] Rename FullScreenNavigator to WorkspaceNavigator --- src/NAVIGATORS.ts | 1 + .../Navigation/AppNavigator/AuthScreens.tsx | 6 +-- ...enNavigator.tsx => WorkspaceNavigator.tsx} | 12 +++--- .../CustomRouter.ts | 4 +- .../AppNavigator/getActionsFromPartialDiff.ts | 2 +- .../AppNavigator/getPartialStateDiff.ts | 8 ++-- src/libs/Navigation/Navigation.ts | 2 +- src/libs/Navigation/dismissModal.ts | 2 +- src/libs/Navigation/dismissModalWithReport.ts | 2 +- .../Navigation/getTopmostFullScreenRoute.ts | 10 ++--- src/libs/Navigation/linkTo/index.ts | 12 +++--- ....ts => WORKSPACE_SCREEN_TO_RHP_MAPPING.ts} | 6 +-- src/libs/Navigation/linkingConfig/config.ts | 2 +- .../linkingConfig/getAdaptedStateFromPath.ts | 42 +++++++++---------- .../getMatchingBottomTabRouteForState.ts | 4 +- src/libs/Navigation/types.ts | 10 ++--- src/pages/workspace/WorkspaceInitialPage.tsx | 4 +- src/pages/workspace/WorkspaceMembersPage.tsx | 4 +- .../workspace/WorkspaceMoreFeaturesPage.tsx | 4 +- .../categories/WorkspaceCategoriesPage.tsx | 4 +- .../distanceRates/PolicyDistanceRatesPage.tsx | 4 +- .../invoices/WorkspaceInvoicesPage.tsx | 5 ++- .../workspace/tags/WorkspaceTagsPage.tsx | 4 +- .../workspace/taxes/WorkspaceTaxesPage.tsx | 4 +- src/pages/workspace/withPolicy.tsx | 4 +- .../WorkspaceAutoReportingFrequencyPage.tsx | 4 +- ...orkspaceAutoReportingMonthlyOffsetPage.tsx | 4 +- .../workflows/WorkspaceWorkflowsPage.tsx | 4 +- 28 files changed, 88 insertions(+), 86 deletions(-) rename src/libs/Navigation/AppNavigator/Navigators/{FullScreenNavigator.tsx => WorkspaceNavigator.tsx} (89%) rename src/libs/Navigation/linkingConfig/{FULL_SCREEN_TO_RHP_MAPPING.ts => WORKSPACE_SCREEN_TO_RHP_MAPPING.ts} (98%) diff --git a/src/NAVIGATORS.ts b/src/NAVIGATORS.ts index 0b4a86c99247..cb829856da7f 100644 --- a/src/NAVIGATORS.ts +++ b/src/NAVIGATORS.ts @@ -12,4 +12,5 @@ export default { WELCOME_VIDEO_MODAL_NAVIGATOR: 'WelcomeVideoModalNavigator', EXPLANATION_MODAL_NAVIGATOR: 'ExplanationModalNavigator', FULL_SCREEN_NAVIGATOR: 'FullScreenNavigator', + WORKSPACE_NAVIGATOR: 'WorkspaceNavigator', } as const; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index f5f35fd21025..5029536782ea 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -61,11 +61,11 @@ import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions'; import BottomTabNavigator from './Navigators/BottomTabNavigator'; import ExplanationModalNavigator from './Navigators/ExplanationModalNavigator'; import FeatureTrainingModalNavigator from './Navigators/FeatureTrainingModalNavigator'; -import FullScreenNavigator from './Navigators/FullScreenNavigator'; import LeftModalNavigator from './Navigators/LeftModalNavigator'; import OnboardingModalNavigator from './Navigators/OnboardingModalNavigator'; import RightModalNavigator from './Navigators/RightModalNavigator'; import WelcomeVideoModalNavigator from './Navigators/WelcomeVideoModalNavigator'; +import WorkspaceNavigator from './Navigators/WorkspaceNavigator'; type AuthScreensProps = { /** Session of currently logged in user */ @@ -510,9 +510,9 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie listeners={modalScreenListenersWithCancelSearch} /> require('../../../../pages/workspace/WorkspaceInitialPage').default; -const RootStack = createSplitStackNavigator(); +const RootStack = createSplitStackNavigator(); -type Screens = Partial React.ComponentType>>; +type Screens = Partial React.ComponentType>>; const CENTRAL_PANE_WORKSPACE_SCREENS = { [SCREENS.WORKSPACE.PROFILE]: () => require('../../../../pages/workspace/WorkspaceProfilePage').default, @@ -27,7 +27,7 @@ const CENTRAL_PANE_WORKSPACE_SCREENS = { [SCREENS.WORKSPACE.RULES]: () => require('../../../../pages/workspace/rules/PolicyRulesPage').default, } satisfies Screens; -function FullScreenNavigator() { +function WorkspaceNavigator() { return ( ) { // This solutions is heuristics and will work for our cases. We may need to improve it in the future if we will have more cases to handle. if (topmostBottomTabRoute && !isNarrowLayout) { - const fullScreenRoute = state.routes.find((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR); + const fullScreenRoute = state.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR); // If there is fullScreenRoute we don't need to add anything. if (fullScreenRoute) { @@ -66,7 +66,7 @@ function compareAndAdaptState(state: StackNavigationState) { return; } - const templateFullScreenRoute = templateState.routes.find((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR); + const templateFullScreenRoute = templateState.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR); // If templateFullScreenRoute is defined, and full screen route is not in the state, we need to add it. if (templateFullScreenRoute) { diff --git a/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts b/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts index 9685f4fc0339..d66eb313cbb1 100644 --- a/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts +++ b/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts @@ -13,7 +13,7 @@ function getActionsFromPartialDiff(diff: GetPartialStateDiffReturnType): Navigat const bottomTabDiff = diff[NAVIGATORS.BOTTOM_TAB_NAVIGATOR]; const centralPaneDiff = diff[NAVIGATORS.CENTRAL_PANE_NAVIGATOR]; - const fullScreenDiff = diff[NAVIGATORS.FULL_SCREEN_NAVIGATOR]; + const fullScreenDiff = diff[NAVIGATORS.WORKSPACE_NAVIGATOR]; // There is only one bottom tab navigator so we can just push this route. if (bottomTabDiff) { diff --git a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts index 17a8ee158219..cac65b833bde 100644 --- a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts +++ b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts @@ -9,7 +9,7 @@ import NAVIGATORS from '@src/NAVIGATORS'; type GetPartialStateDiffReturnType = { [NAVIGATORS.BOTTOM_TAB_NAVIGATOR]?: NavigationPartialRoute; [NAVIGATORS.CENTRAL_PANE_NAVIGATOR]?: NavigationPartialRoute; - [NAVIGATORS.FULL_SCREEN_NAVIGATOR]?: NavigationPartialRoute; + [NAVIGATORS.WORKSPACE_NAVIGATOR]?: NavigationPartialRoute; }; /** @@ -62,10 +62,10 @@ function getPartialStateDiff(state: State, templateState: St // This one is heuristic and may need to be improved if we will be able to navigate from modal screen with full screen in background to another modal screen with full screen in background. // For now this simple check is enough. - if (metainfo.isFullScreenNavigatorMandatory) { + if (metainfo.isWorkspaceNavigatorMandatory) { const stateTopmostFullScreen = getTopmostFullScreenRoute(state); const templateStateTopmostFullScreen = getTopmostFullScreenRoute(templateState); - const fullScreenDiff = templateState.routes.filter((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR).at(-1) as NavigationPartialRoute; + const fullScreenDiff = templateState.routes.filter((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR).at(-1) as NavigationPartialRoute; if ( // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing @@ -75,7 +75,7 @@ function getPartialStateDiff(state: State, templateState: St (stateTopmostFullScreen.name !== templateStateTopmostFullScreen.name || !shallowCompare(stateTopmostFullScreen.params as Record | undefined, templateStateTopmostFullScreen.params as Record | undefined))) ) { - diff[NAVIGATORS.FULL_SCREEN_NAVIGATOR] = fullScreenDiff; + diff[NAVIGATORS.WORKSPACE_NAVIGATOR] = fullScreenDiff; } } diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index d5e9c5229a89..22a9bf6fc042 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -90,7 +90,7 @@ function getActiveRouteIndex(stateOrRoute: StateOrRoute, index?: number): number if ( 'name' in stateOrRoute && - (stateOrRoute.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR) + (stateOrRoute.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.WORKSPACE_NAVIGATOR) ) { return 0; } diff --git a/src/libs/Navigation/dismissModal.ts b/src/libs/Navigation/dismissModal.ts index dd0e512ea33d..ea00a8646c85 100644 --- a/src/libs/Navigation/dismissModal.ts +++ b/src/libs/Navigation/dismissModal.ts @@ -18,7 +18,7 @@ function dismissModal(navigationRef: NavigationContainerRef) const state = navigationRef.getState(); const lastRoute = state.routes.at(-1); switch (lastRoute?.name) { - case NAVIGATORS.FULL_SCREEN_NAVIGATOR: + case NAVIGATORS.WORKSPACE_NAVIGATOR: case NAVIGATORS.LEFT_MODAL_NAVIGATOR: case NAVIGATORS.RIGHT_MODAL_NAVIGATOR: case NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR: diff --git a/src/libs/Navigation/dismissModalWithReport.ts b/src/libs/Navigation/dismissModalWithReport.ts index 854b2e586caf..2c24d13c3ac4 100644 --- a/src/libs/Navigation/dismissModalWithReport.ts +++ b/src/libs/Navigation/dismissModalWithReport.ts @@ -34,7 +34,7 @@ function dismissModalWithReport(targetReport: OnyxEntry, navigationRef: const state = navigationRef.getState(); const lastRoute = state.routes.at(-1); switch (lastRoute?.name) { - case NAVIGATORS.FULL_SCREEN_NAVIGATOR: + case NAVIGATORS.WORKSPACE_NAVIGATOR: case NAVIGATORS.LEFT_MODAL_NAVIGATOR: case NAVIGATORS.RIGHT_MODAL_NAVIGATOR: case SCREENS.NOT_FOUND: diff --git a/src/libs/Navigation/getTopmostFullScreenRoute.ts b/src/libs/Navigation/getTopmostFullScreenRoute.ts index fcc28ce76926..ae17b0094f42 100644 --- a/src/libs/Navigation/getTopmostFullScreenRoute.ts +++ b/src/libs/Navigation/getTopmostFullScreenRoute.ts @@ -1,13 +1,13 @@ import NAVIGATORS from '@src/NAVIGATORS'; -import type {FullScreenName, NavigationPartialRoute, RootStackParamList, State} from './types'; +import type {NavigationPartialRoute, RootStackParamList, State, WorkspaceScreenName} from './types'; // Get the name of topmost fullscreen route in the navigation stack. -function getTopmostFullScreenRoute(state: State): NavigationPartialRoute | undefined { +function getTopmostFullScreenRoute(state: State): NavigationPartialRoute | undefined { if (!state) { return; } - const topmostFullScreenRoute = state.routes.filter((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR).at(-1); + const topmostFullScreenRoute = state.routes.filter((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR).at(-1); if (!topmostFullScreenRoute) { return; @@ -15,13 +15,13 @@ function getTopmostFullScreenRoute(state: State): Navigation if (topmostFullScreenRoute.state) { // There will be at least one route in the fullscreen navigator. - const {name, params} = topmostFullScreenRoute.state.routes.at(-1) as NavigationPartialRoute; + const {name, params} = topmostFullScreenRoute.state.routes.at(-1) as NavigationPartialRoute; return {name, params}; } if (!!topmostFullScreenRoute.params && 'screen' in topmostFullScreenRoute.params) { - return {name: topmostFullScreenRoute.params.screen as FullScreenName, params: topmostFullScreenRoute.params.params}; + return {name: topmostFullScreenRoute.params.screen as WorkspaceScreenName, params: topmostFullScreenRoute.params.params}; } } diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 3ca41846d2b4..9f474c1e7055 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -57,10 +57,10 @@ export default function linkTo(navigation: NavigationContainerRef, metainfo); const diffActions = getActionsFromPartialDiff(diff); for (const diffAction of diffActions) { @@ -142,7 +142,7 @@ export default function linkTo(navigation: NavigationContainerRef> = { +const WORKSPACE_SCREEN_TO_RHP_MAPPING: Partial> = { [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.ADDRESS, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE], [SCREENS.WORKSPACE.MEMBERS]: [ SCREENS.WORKSPACE.INVITE, @@ -215,4 +215,4 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { ], }; -export default FULL_SCREEN_TO_RHP_MAPPING; +export default WORKSPACE_SCREEN_TO_RHP_MAPPING; diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index d3d575f961a8..7c893aeca74d 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1241,7 +1241,7 @@ const config: LinkingOptions['config'] = { }, }, - [NAVIGATORS.FULL_SCREEN_NAVIGATOR]: { + [NAVIGATORS.WORKSPACE_NAVIGATOR]: { screens: { [SCREENS.WORKSPACE.INITIAL]: { path: ROUTES.WORKSPACE_INITIAL.route, diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index c84213918f70..50c3bdf50761 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -4,7 +4,7 @@ import pick from 'lodash/pick'; import type {TupleToUnion} from 'type-fest'; import {isAnonymousUser} from '@libs/actions/Session'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import type {BottomTabName, CentralPaneName, FullScreenName, NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; +import type {BottomTabName, CentralPaneName, NavigationPartialRoute, RootStackParamList, WorkspaceScreenName} from '@libs/Navigation/types'; import {isCentralPaneName} from '@libs/NavigationUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; @@ -16,10 +16,10 @@ import type {Screen} from '@src/SCREENS'; import SCREENS from '@src/SCREENS'; import CENTRAL_PANE_TO_RHP_MAPPING from './CENTRAL_PANE_TO_RHP_MAPPING'; import config, {normalizedConfigs} from './config'; -import FULL_SCREEN_TO_RHP_MAPPING from './FULL_SCREEN_TO_RHP_MAPPING'; import getMatchingBottomTabRouteForState from './getMatchingBottomTabRouteForState'; import getMatchingCentralPaneRouteForState from './getMatchingCentralPaneRouteForState'; import replacePathInNestedState from './replacePathInNestedState'; +import WORKSPACE_SCREEN_TO_RHP_MAPPING from './WORKSPACE_SCREEN_TO_RHP_MAPPING'; const RHP_SCREENS_OPENED_FROM_LHN = [ SCREENS.SETTINGS.SHARE_CODE, @@ -39,7 +39,7 @@ type Metainfo = { // If the screens in the bottom tab and central pane are not mandatory for this state, we want to have this information. // It will help us later with creating proper diff betwen current and desired state. isCentralPaneAndBottomTabMandatory: boolean; - isFullScreenNavigatorMandatory: boolean; + isWorkspaceNavigatorMandatory: boolean; }; type GetAdaptedStateReturnType = { @@ -78,12 +78,12 @@ function createBottomTabNavigator(route: NavigationPartialRoute, }; } -function createFullScreenNavigator(route?: NavigationPartialRoute): NavigationPartialRoute { +function createWorkspaceNavigator(route?: NavigationPartialRoute): NavigationPartialRoute { const routes = []; const policyID = route?.params && 'policyID' in route.params ? route.params.policyID : undefined; - // Both routes in FullScreenNavigator should store a policyID in params, so here this param is also passed to the screen displayed in LHN in FullScreenNavigator + // Both routes in WorkspaceNavigator should store a policyID in params, so here this param is also passed to the screen displayed in LHN in WorkspaceNavigator routes.push({ name: SCREENS.WORKSPACE.INITIAL, params: { @@ -95,7 +95,7 @@ function createFullScreenNavigator(route?: NavigationPartialRoute | undefined { +function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): NavigationPartialRoute | undefined { // Check for backTo param. One screen with different backTo value may need diferent screens visible under the overlay. if (route.params && 'backTo' in route.params && typeof route.params.backTo === 'string') { const stateForBackTo = getStateFromPath(route.params.backTo, config); @@ -125,15 +125,15 @@ function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): Navigat } // If we know that backTo targets the root route (full screen) we want to use it. - const fullScreenNavigator = stateForBackTo.routes.find((rt) => rt.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR); + const fullScreenNavigator = stateForBackTo.routes.find((rt) => rt.name === NAVIGATORS.WORKSPACE_NAVIGATOR); if (fullScreenNavigator && fullScreenNavigator.state) { - return fullScreenNavigator as NavigationPartialRoute; + return fullScreenNavigator as NavigationPartialRoute; } // If we know that backTo targets a central pane screen we want to use it. const centralPaneScreen = stateForBackTo.routes.find((rt) => isCentralPaneName(rt.name)); if (centralPaneScreen) { - return centralPaneScreen as NavigationPartialRoute; + return centralPaneScreen as NavigationPartialRoute; } } } @@ -148,11 +148,11 @@ function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): Navigat } // Check for FullScreenNavigator - for (const [fullScreenName, RHPNames] of Object.entries(FULL_SCREEN_TO_RHP_MAPPING)) { + for (const [workspaceScreenName, RHPNames] of Object.entries(WORKSPACE_SCREEN_TO_RHP_MAPPING)) { if (RHPNames.includes(route.name)) { - const paramsFromRoute = getParamsFromRoute(fullScreenName); + const paramsFromRoute = getParamsFromRoute(workspaceScreenName); - return createFullScreenNavigator({name: fullScreenName as FullScreenName, params: pick(route.params, paramsFromRoute)}); + return createWorkspaceNavigator({name: workspaceScreenName as WorkspaceScreenName, params: pick(route.params, paramsFromRoute)}); } } @@ -168,13 +168,13 @@ function getAdaptedState(state: PartialState const isNarrowLayout = getIsNarrowLayout(); const metainfo = { isCentralPaneAndBottomTabMandatory: true, - isFullScreenNavigatorMandatory: true, + isWorkspaceNavigatorMandatory: true, }; // We need to check what is defined to know what we need to add. const bottomTabNavigator = state.routes.find((route) => route.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR); const centralPaneNavigator = state.routes.find((route) => isCentralPaneName(route.name)); - const fullScreenNavigator = state.routes.find((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR); + const WorkspaceNavigator = state.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR); const rhpNavigator = state.routes.find((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR); const lhpNavigator = state.routes.find((route) => route.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR); const onboardingModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR); @@ -198,17 +198,17 @@ function getAdaptedState(state: PartialState // This may happen if this RHP doesn't have a route that should be under the overlay defined. if (!matchingRootRoute || isRHPScreenOpenedFromLHN) { metainfo.isCentralPaneAndBottomTabMandatory = false; - metainfo.isFullScreenNavigatorMandatory = false; + metainfo.isWorkspaceNavigatorMandatory = false; // If matchingRootRoute is undefined and it's a narrow layout, don't add a report screen under the RHP. matchingRootRoute = matchingRootRoute ?? (!isNarrowLayout ? {name: SCREENS.REPORT} : undefined); } - // If the root route is type of FullScreenNavigator, the default bottom tab will be added. + // If the root route is type of WorkspaceNavigator, the default bottom tab will be added. const matchingBottomTabRoute = getMatchingBottomTabRouteForState({routes: matchingRootRoute ? [matchingRootRoute] : []}); routes.push(createBottomTabNavigator(matchingBottomTabRoute, policyID)); // When we open a screen in RHP from FullScreenNavigator, we need to add the appropriate screen in CentralPane. // Then, when we close FullScreenNavigator, we will be redirected to the correct page in CentralPane. - if (matchingRootRoute?.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR) { + if (matchingRootRoute?.name === NAVIGATORS.WORKSPACE_NAVIGATOR) { routes.push({name: SCREENS.SETTINGS.WORKSPACES}); } @@ -231,7 +231,7 @@ function getAdaptedState(state: PartialState // There is no screen in these navigators that would have mandatory central pane, bottom tab or fullscreen navigator. metainfo.isCentralPaneAndBottomTabMandatory = false; - metainfo.isFullScreenNavigatorMandatory = false; + metainfo.isWorkspaceNavigatorMandatory = false; const routes = []; routes.push( createBottomTabNavigator( @@ -269,7 +269,7 @@ function getAdaptedState(state: PartialState metainfo, }; } - if (fullScreenNavigator) { + if (WorkspaceNavigator) { // Routes // - default bottom tab // - default central pane on desktop layout @@ -289,7 +289,7 @@ function getAdaptedState(state: PartialState name: SCREENS.SETTINGS.WORKSPACES, }); - routes.push(fullScreenNavigator); + routes.push(WorkspaceNavigator); return { adaptedState: getRoutesWithIndex(routes), diff --git a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts index 7b213fdfeb6e..1db77f9917ff 100644 --- a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts +++ b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts @@ -8,9 +8,9 @@ import {CENTRAL_PANE_TO_TAB_MAPPING} from './TAB_TO_CENTRAL_PANE_MAPPING'; function getMatchingBottomTabRouteForState(state: State, policyID?: string): NavigationPartialRoute { const paramsWithPolicyID = policyID ? {policyID} : undefined; const defaultRoute = {name: SCREENS.HOME, params: paramsWithPolicyID}; - const isFullScreenNavigatorOpened = state.routes.some((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR); + const isWorkspaceNavigatorOpened = state.routes.some((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR); - if (isFullScreenNavigatorOpened) { + if (isWorkspaceNavigatorOpened) { return {name: SCREENS.SETTINGS.ROOT, params: paramsWithPolicyID}; } diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 631796401734..ce1a062beaff 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1283,7 +1283,7 @@ type TravelNavigatorParamList = { [SCREENS.TRAVEL.MY_TRIPS]: undefined; }; -type FullScreenNavigatorParamList = { +type WorkspaceNavigatorParamList = { [SCREENS.WORKSPACE.INITIAL]: { policyID: string; backTo?: string; @@ -1463,7 +1463,7 @@ type AuthScreensParamList = CentralPaneScreensParamList & [SCREENS.NOT_FOUND]: undefined; [NAVIGATORS.LEFT_MODAL_NAVIGATOR]: NavigatorScreenParams; [NAVIGATORS.RIGHT_MODAL_NAVIGATOR]: NavigatorScreenParams; - [NAVIGATORS.FULL_SCREEN_NAVIGATOR]: NavigatorScreenParams; + [NAVIGATORS.WORKSPACE_NAVIGATOR]: NavigatorScreenParams; [NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR]: NavigatorScreenParams; [NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR]: NavigatorScreenParams; [NAVIGATORS.WELCOME_VIDEO_MODAL_NAVIGATOR]: NavigatorScreenParams; @@ -1529,7 +1529,7 @@ type RootStackParamList = PublicScreensParamList & AuthScreensParamList & LeftMo type BottomTabName = keyof BottomTabNavigatorParamList; -type FullScreenName = keyof FullScreenNavigatorParamList; +type WorkspaceScreenName = keyof WorkspaceNavigatorParamList; type CentralPaneName = keyof CentralPaneScreensParamList; @@ -1555,8 +1555,8 @@ export type { EnablePaymentsNavigatorParamList, ExplanationModalNavigatorParamList, FlagCommentNavigatorParamList, - FullScreenName, - FullScreenNavigatorParamList, + WorkspaceScreenName, + WorkspaceNavigatorParamList, LeftModalNavigatorParamList, MoneyRequestNavigatorParamList, NavigationPartialRoute, diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 3b20ccfef360..6b595f96b42e 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -26,7 +26,7 @@ import getTopmostRouteName from '@libs/Navigation/getTopmostRouteName'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; -import type {FullScreenNavigatorParamList} from '@navigation/types'; +import type {WorkspaceNavigatorParamList} from '@navigation/types'; import * as Policy from '@userActions/Policy/Policy'; import * as ReimbursementAccount from '@userActions/ReimbursementAccount'; import CONST from '@src/CONST'; @@ -66,7 +66,7 @@ type WorkspaceMenuItem = { badgeText?: string; }; -type WorkspaceInitialPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +type WorkspaceInitialPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; type PolicyFeatureStates = Record; diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 52b8a06ba931..91820f221564 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -34,7 +34,7 @@ import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; @@ -53,7 +53,7 @@ import type {WithPolicyAndFullscreenLoadingProps} from './withPolicyAndFullscree import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading'; import WorkspacePageWithSections from './WorkspacePageWithSections'; -type WorkspaceMembersPageProps = WithPolicyAndFullscreenLoadingProps & WithCurrentUserPersonalDetailsProps & StackScreenProps; +type WorkspaceMembersPageProps = WithPolicyAndFullscreenLoadingProps & WithCurrentUserPersonalDetailsProps & StackScreenProps; /** * Inverts an object, equivalent of _.invert diff --git a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx index a743140278f7..484a408289db 100644 --- a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx +++ b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx @@ -17,7 +17,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import {isControlPolicy} from '@libs/PolicyUtils'; import * as Category from '@userActions/Policy/Category'; import * as DistanceRate from '@userActions/Policy/DistanceRate'; @@ -37,7 +37,7 @@ import type {WithPolicyAndFullscreenLoadingProps} from './withPolicyAndFullscree import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading'; import ToggleSettingOptionRow from './workflows/ToggleSettingsOptionRow'; -type WorkspaceMoreFeaturesPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +type WorkspaceMoreFeaturesPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; type Item = { icon: IconAsset; diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index fa0b57ba207c..d8f3e98a7cad 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -36,7 +36,7 @@ import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import localeCompare from '@libs/LocaleCompare'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as Modal from '@userActions/Modal'; @@ -54,7 +54,7 @@ type PolicyOption = ListItem & { keyForList: string; }; -type WorkspaceCategoriesPageProps = StackScreenProps; +type WorkspaceCategoriesPageProps = StackScreenProps; function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout(); diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx index 6ce697e00fd6..3a5c09c0b621 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx @@ -25,7 +25,7 @@ import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@navigation/types'; +import type {WorkspaceNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as DistanceRate from '@userActions/Policy/DistanceRate'; import ButtonWithDropdownMenu from '@src/components/ButtonWithDropdownMenu'; @@ -36,7 +36,7 @@ import type {CustomUnit, Rate} from '@src/types/onyx/Policy'; type RateForList = ListItem & {value: string}; -type PolicyDistanceRatesPageProps = StackScreenProps; +type PolicyDistanceRatesPageProps = StackScreenProps; function PolicyDistanceRatesPage({ route: { diff --git a/src/pages/workspace/invoices/WorkspaceInvoicesPage.tsx b/src/pages/workspace/invoices/WorkspaceInvoicesPage.tsx index bbe19e63a1b5..75d1ab46fe28 100644 --- a/src/pages/workspace/invoices/WorkspaceInvoicesPage.tsx +++ b/src/pages/workspace/invoices/WorkspaceInvoicesPage.tsx @@ -4,7 +4,7 @@ import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {FullScreenNavigatorParamList} from '@navigation/types'; +import type {WorkspaceNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections'; import CONST from '@src/CONST'; @@ -13,7 +13,8 @@ import WorkspaceInvoicesNoVBAView from './WorkspaceInvoicesNoVBAView'; import WorkspaceInvoicesVBAView from './WorkspaceInvoicesVBAView'; import WorkspaceInvoiceVBASection from './WorkspaceInvoiceVBASection'; -type WorkspaceInvoicesPageProps = StackScreenProps; +type WorkspaceInvoicesPageProps = StackScreenProps; + function WorkspaceInvoicesPage({route}: WorkspaceInvoicesPageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 115944ae45c0..2c19eb70cac8 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -35,7 +35,7 @@ import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import localeCompare from '@libs/LocaleCompare'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as Modal from '@userActions/Modal'; @@ -48,7 +48,7 @@ import type {PendingAction} from '@src/types/onyx/OnyxCommon'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {PolicyTag, PolicyTagList, TagListItem} from './types'; -type WorkspaceTagsPageProps = StackScreenProps; +type WorkspaceTagsPageProps = StackScreenProps; function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout(); diff --git a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx index 31e4a5e093eb..ac0eb0294203 100644 --- a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx +++ b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx @@ -29,7 +29,7 @@ import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; -import type {FullScreenNavigatorParamList} from '@navigation/types'; +import type {WorkspaceNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading'; import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading'; @@ -39,7 +39,7 @@ import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {TaxRate} from '@src/types/onyx'; -type WorkspaceTaxesPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +type WorkspaceTaxesPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; function WorkspaceTaxesPage({ policy, diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index e1fdd2b29687..6412486ddf9d 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -3,14 +3,14 @@ import type {ComponentType, ForwardedRef, RefAttributes} from 'react'; import React, {forwardRef} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {useOnyx} from 'react-native-onyx'; -import type {AuthScreensParamList, BottomTabNavigatorParamList, FullScreenNavigatorParamList, ReimbursementAccountNavigatorParamList, SettingsNavigatorParamList} from '@navigation/types'; +import type {AuthScreensParamList, BottomTabNavigatorParamList, ReimbursementAccountNavigatorParamList, SettingsNavigatorParamList, WorkspaceNavigatorParamList} from '@navigation/types'; import * as Policy from '@userActions/Policy/Policy'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; -type NavigatorsParamList = BottomTabNavigatorParamList & AuthScreensParamList & SettingsNavigatorParamList & ReimbursementAccountNavigatorParamList & FullScreenNavigatorParamList; +type NavigatorsParamList = BottomTabNavigatorParamList & AuthScreensParamList & SettingsNavigatorParamList & ReimbursementAccountNavigatorParamList & WorkspaceNavigatorParamList; type PolicyRoute = RouteProp< NavigatorsParamList, diff --git a/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx b/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx index d026c218910f..177e2f78467c 100644 --- a/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx @@ -13,7 +13,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as Localize from '@libs/Localize'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; @@ -27,7 +27,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; type AutoReportingFrequencyKey = Exclude, 'instant'>; type Locale = ValueOf; -type WorkspaceAutoReportingFrequencyPageProps = WithPolicyOnyxProps & StackScreenProps; +type WorkspaceAutoReportingFrequencyPageProps = WithPolicyOnyxProps & StackScreenProps; type WorkspaceAutoReportingFrequencyPageItem = { text: string; diff --git a/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx b/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx index a9f96061ec0a..86b91088c030 100644 --- a/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx @@ -8,7 +8,7 @@ import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; @@ -21,7 +21,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; const DAYS_OF_MONTH = 28; -type WorkspaceAutoReportingMonthlyOffsetProps = WithPolicyOnyxProps & StackScreenProps; +type WorkspaceAutoReportingMonthlyOffsetProps = WithPolicyOnyxProps & StackScreenProps; type AutoReportingOffsetKeys = ValueOf; diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx index 17bad8a1a102..df648d0b03e0 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx @@ -25,7 +25,7 @@ import {getPaymentMethodDescription} from '@libs/PaymentUtils'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import {convertPolicyEmployeesToApprovalWorkflows, INITIAL_APPROVAL_WORKFLOW} from '@libs/WorkflowUtils'; -import type {FullScreenNavigatorParamList} from '@navigation/types'; +import type {WorkspaceNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import withPolicy from '@pages/workspace/withPolicy'; @@ -42,7 +42,7 @@ import type {ToggleSettingOptionRowProps} from './ToggleSettingsOptionRow'; import {getAutoReportingFrequencyDisplayNames} from './WorkspaceAutoReportingFrequencyPage'; import type {AutoReportingFrequencyKey} from './WorkspaceAutoReportingFrequencyPage'; -type WorkspaceWorkflowsPageProps = WithPolicyProps & StackScreenProps; +type WorkspaceWorkflowsPageProps = WithPolicyProps & StackScreenProps; function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { const {translate, preferredLocale} = useLocalize(); From 8855479637c56c4496ccb29b172c489247457067 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 7 Aug 2024 08:45:46 +0200 Subject: [PATCH 007/257] Replace FullScreenNavigatorParamList with WorkspaceNavigatorParamList --- src/pages/workspace/WorkspaceProfilePage.tsx | 4 ++-- .../workspace/expensifyCard/WorkspaceCardsListLabel.tsx | 8 ++++---- .../expensifyCard/WorkspaceExpensifyCardListPage.tsx | 4 ++-- .../expensifyCard/WorkspaceExpensifyCardPage.tsx | 4 ++-- .../WorkspaceExpensifyCardPageEmptyState.tsx | 4 ++-- .../workspace/reportFields/WorkspaceReportFieldsPage.tsx | 4 ++-- .../approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx | 4 ++-- .../approvals/WorkspaceWorkflowsApprovalsCreatePage.tsx | 4 ++-- .../approvals/WorkspaceWorkflowsApprovalsEditPage.tsx | 4 ++-- .../WorkspaceWorkflowsApprovalsExpensesFromPage.tsx | 4 ++-- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index cbd43fd17529..e99afe7ba408 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -23,7 +23,7 @@ import useThemeIllustrations from '@hooks/useThemeIllustrations'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import Parser from '@libs/Parser'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -45,7 +45,7 @@ type WorkspaceProfilePageOnyxProps = { currencyList: OnyxEntry; }; -type WorkspaceProfilePageProps = WithPolicyProps & WorkspaceProfilePageOnyxProps & StackScreenProps; +type WorkspaceProfilePageProps = WithPolicyProps & WorkspaceProfilePageOnyxProps & StackScreenProps; function WorkspaceProfilePage({policyDraft, policy: policyProp, currencyList = {}, route}: WorkspaceProfilePageProps) { const styles = useThemeStyles(); diff --git a/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx b/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx index f1075d85cfd8..685fa91ce9d0 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx @@ -1,8 +1,8 @@ import type {RouteProp} from '@react-navigation/native'; import {useRoute} from '@react-navigation/native'; -import React, {useEffect, useMemo, useRef, useState} from 'react'; -import {View} from 'react-native'; +import {useEffect, useMemo, useRef, useState} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; +import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import Button from '@components/Button'; @@ -20,7 +20,7 @@ import useWindowDimensions from '@hooks/useWindowDimensions'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import getClickedTargetLocation from '@libs/getClickedTargetLocation'; import * as PolicyUtils from '@libs/PolicyUtils'; -import type {FullScreenNavigatorParamList} from '@navigation/types'; +import type {WorkspaceNavigatorParamList} from '@navigation/types'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy/Policy'; import * as Report from '@userActions/Report'; @@ -40,7 +40,7 @@ type WorkspaceCardsListLabelProps = { }; function WorkspaceCardsListLabel({type, value, style}: WorkspaceCardsListLabelProps) { - const route = useRoute>(); + const route = useRoute>(); const policy = usePolicy(route.params.policyID); const styles = useThemeStyles(); const {windowWidth} = useWindowDimensions(); diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx index 25de151bbb6d..f2574223df48 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx @@ -17,7 +17,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import * as CardUtils from '@libs/CardUtils'; import Navigation from '@navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@navigation/types'; +import type {WorkspaceNavigatorParamList} from '@navigation/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -30,7 +30,7 @@ import WorkspaceCardListRow from './WorkspaceCardListRow'; type WorkspaceExpensifyCardListPageProps = { /** Route from navigation */ - route: RouteProp; + route: RouteProp; /** List of Expensify cards */ cardsList: OnyxEntry; diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx index bc29918fe450..5d173fa4310b 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx @@ -6,7 +6,7 @@ import {useOnyx} from 'react-native-onyx'; import useNetwork from '@hooks/useNetwork'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as Policy from '@userActions/Policy/Policy'; @@ -16,7 +16,7 @@ import type SCREENS from '@src/SCREENS'; import WorkspaceExpensifyCardListPage from './WorkspaceExpensifyCardListPage'; import WorkspaceExpensifyCardPageEmptyState from './WorkspaceExpensifyCardPageEmptyState'; -type WorkspaceExpensifyCardPageProps = StackScreenProps; +type WorkspaceExpensifyCardPageProps = StackScreenProps; function WorkspaceExpensifyCardPage({route}: WorkspaceExpensifyCardPageProps) { const policyID = route.params.policyID ?? '-1'; diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx index 7dc6293e23ea..732f9c047589 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx @@ -12,7 +12,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as CardUtils from '@libs/CardUtils'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import Navigation from '@navigation/Navigation'; import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading'; import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading'; @@ -40,7 +40,7 @@ const expensifyCardFeatures: FeatureListItem[] = [ ]; type WorkspaceExpensifyCardPageEmptyStateProps = { - route: StackScreenProps['route']; + route: StackScreenProps['route']; } & WithPolicyAndFullscreenLoadingProps; function WorkspaceExpensifyCardPageEmptyState({route, policy}: WorkspaceExpensifyCardPageEmptyStateProps) { diff --git a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx index 603e610b6f5d..9b36e648c17d 100644 --- a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx +++ b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx @@ -33,7 +33,7 @@ import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import localeCompare from '@libs/LocaleCompare'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as WorkspaceReportFieldUtils from '@libs/WorkspaceReportFieldUtils'; @@ -51,7 +51,7 @@ type ReportFieldForList = ListItem & { orderWeight?: number; }; -type WorkspaceReportFieldsPageProps = StackScreenProps; +type WorkspaceReportFieldsPageProps = StackScreenProps; function WorkspaceReportFieldsPage({ route: { diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx index 5a1a0bf7dc01..e24975484260 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx @@ -19,7 +19,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; @@ -35,7 +35,7 @@ import type {Icon} from '@src/types/onyx/OnyxCommon'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; type WorkspaceWorkflowsApprovalsApproverPageProps = WithPolicyAndFullscreenLoadingProps & - StackScreenProps; + StackScreenProps; type SelectionListApprover = { text: string; diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsCreatePage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsCreatePage.tsx index dc0f067f60df..90f10ce0cd63 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsCreatePage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsCreatePage.tsx @@ -11,7 +11,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading'; @@ -23,7 +23,7 @@ import type SCREENS from '@src/SCREENS'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import ApprovalWorkflowEditor from './ApprovalWorkflowEditor'; -type WorkspaceWorkflowsApprovalsCreatePageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +type WorkspaceWorkflowsApprovalsCreatePageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; function WorkspaceWorkflowsApprovalsCreatePage({policy, isLoadingReportData = true, route}: WorkspaceWorkflowsApprovalsCreatePageProps) { const styles = useThemeStyles(); diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx index c2da4e39739a..0c7b7fd8465a 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx @@ -13,7 +13,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import {convertPolicyEmployeesToApprovalWorkflows} from '@libs/WorkflowUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; @@ -27,7 +27,7 @@ import type ApprovalWorkflow from '@src/types/onyx/ApprovalWorkflow'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import ApprovalWorkflowEditor from './ApprovalWorkflowEditor'; -type WorkspaceWorkflowsApprovalsEditPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +type WorkspaceWorkflowsApprovalsEditPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; function WorkspaceWorkflowsApprovalsEditPage({policy, isLoadingReportData = true, route}: WorkspaceWorkflowsApprovalsEditPageProps) { const styles = useThemeStyles(); diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx index 917ef5b8d2ff..273a7cf64b9f 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx @@ -19,7 +19,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; @@ -48,7 +48,7 @@ type SelectionListMember = { type MembersSection = SectionListData>; type WorkspaceWorkflowsApprovalsExpensesFromPageProps = WithPolicyAndFullscreenLoadingProps & - StackScreenProps; + StackScreenProps; function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportData = true, route}: WorkspaceWorkflowsApprovalsExpensesFromPageProps) { const styles = useThemeStyles(); From adf60af1bd91ca422ca30f561b8ef1e05a87630f Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 7 Aug 2024 09:09:02 +0200 Subject: [PATCH 008/257] Refactor old naming, replace FullScreenNavigator with WorkspaceNavigator --- .../AppNavigator/getPartialStateDiff.ts | 23 ++++++++------- .../Navigation/getTopmostFullScreenRoute.ts | 28 ------------------- .../Navigation/getTopmostWorkspaceRoute.ts | 28 +++++++++++++++++++ .../linkingConfig/getAdaptedStateFromPath.ts | 12 ++++---- 4 files changed, 47 insertions(+), 44 deletions(-) delete mode 100644 src/libs/Navigation/getTopmostFullScreenRoute.ts create mode 100644 src/libs/Navigation/getTopmostWorkspaceRoute.ts diff --git a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts index cac65b833bde..974f98dccccb 100644 --- a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts +++ b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts @@ -1,6 +1,6 @@ import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; -import getTopmostFullScreenRoute from '@libs/Navigation/getTopmostFullScreenRoute'; +import getTopmostWorkspaceRoute from '@libs/Navigation/getTopmostWorkspaceRoute'; import type {Metainfo} from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; import shallowCompare from '@libs/ObjectUtils'; @@ -63,19 +63,22 @@ function getPartialStateDiff(state: State, templateState: St // This one is heuristic and may need to be improved if we will be able to navigate from modal screen with full screen in background to another modal screen with full screen in background. // For now this simple check is enough. if (metainfo.isWorkspaceNavigatorMandatory) { - const stateTopmostFullScreen = getTopmostFullScreenRoute(state); - const templateStateTopmostFullScreen = getTopmostFullScreenRoute(templateState); - const fullScreenDiff = templateState.routes.filter((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR).at(-1) as NavigationPartialRoute; + const stateTopmostWorkspaceRoute = getTopmostWorkspaceRoute(state); + const templateStateTopmostWorkspaceRoute = getTopmostWorkspaceRoute(templateState); + const workspaceNavDiff = templateState.routes.filter((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR).at(-1) as NavigationPartialRoute; if ( // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - (!stateTopmostFullScreen && templateStateTopmostFullScreen) || - (stateTopmostFullScreen && - templateStateTopmostFullScreen && - (stateTopmostFullScreen.name !== templateStateTopmostFullScreen.name || - !shallowCompare(stateTopmostFullScreen.params as Record | undefined, templateStateTopmostFullScreen.params as Record | undefined))) + (!stateTopmostWorkspaceRoute && templateStateTopmostWorkspaceRoute) || + (stateTopmostWorkspaceRoute && + templateStateTopmostWorkspaceRoute && + (stateTopmostWorkspaceRoute.name !== templateStateTopmostWorkspaceRoute.name || + !shallowCompare( + stateTopmostWorkspaceRoute.params as Record | undefined, + templateStateTopmostWorkspaceRoute.params as Record | undefined, + ))) ) { - diff[NAVIGATORS.WORKSPACE_NAVIGATOR] = fullScreenDiff; + diff[NAVIGATORS.WORKSPACE_NAVIGATOR] = workspaceNavDiff; } } diff --git a/src/libs/Navigation/getTopmostFullScreenRoute.ts b/src/libs/Navigation/getTopmostFullScreenRoute.ts deleted file mode 100644 index ae17b0094f42..000000000000 --- a/src/libs/Navigation/getTopmostFullScreenRoute.ts +++ /dev/null @@ -1,28 +0,0 @@ -import NAVIGATORS from '@src/NAVIGATORS'; -import type {NavigationPartialRoute, RootStackParamList, State, WorkspaceScreenName} from './types'; - -// Get the name of topmost fullscreen route in the navigation stack. -function getTopmostFullScreenRoute(state: State): NavigationPartialRoute | undefined { - if (!state) { - return; - } - - const topmostFullScreenRoute = state.routes.filter((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR).at(-1); - - if (!topmostFullScreenRoute) { - return; - } - - if (topmostFullScreenRoute.state) { - // There will be at least one route in the fullscreen navigator. - const {name, params} = topmostFullScreenRoute.state.routes.at(-1) as NavigationPartialRoute; - - return {name, params}; - } - - if (!!topmostFullScreenRoute.params && 'screen' in topmostFullScreenRoute.params) { - return {name: topmostFullScreenRoute.params.screen as WorkspaceScreenName, params: topmostFullScreenRoute.params.params}; - } -} - -export default getTopmostFullScreenRoute; diff --git a/src/libs/Navigation/getTopmostWorkspaceRoute.ts b/src/libs/Navigation/getTopmostWorkspaceRoute.ts new file mode 100644 index 000000000000..4e9c5c607c5e --- /dev/null +++ b/src/libs/Navigation/getTopmostWorkspaceRoute.ts @@ -0,0 +1,28 @@ +import NAVIGATORS from '@src/NAVIGATORS'; +import type {NavigationPartialRoute, RootStackParamList, State, WorkspaceScreenName} from './types'; + +// Get the name of topmost workspace navigator route in the navigation stack. +function getTopmostWorkspaceRoute(state: State): NavigationPartialRoute | undefined { + if (!state) { + return; + } + + const topmostWorkspaceRoute = state.routes.filter((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR).at(-1); + + if (!topmostWorkspaceRoute) { + return; + } + + if (topmostWorkspaceRoute.state) { + // There will be at least one route in the workspace navigator. + const {name, params} = topmostWorkspaceRoute.state.routes.at(-1) as NavigationPartialRoute; + + return {name, params}; + } + + if (!!topmostWorkspaceRoute.params && 'screen' in topmostWorkspaceRoute.params) { + return {name: topmostWorkspaceRoute.params.screen as WorkspaceScreenName, params: topmostWorkspaceRoute.params.params}; + } +} + +export default getTopmostWorkspaceRoute; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 50c3bdf50761..293827b1bd2e 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -108,7 +108,7 @@ function getParamsFromRoute(screenName: string): string[] { return route.match(/(?<=[:?&])(\w+)(?=[/=?&]|$)/g) ?? []; } -// This function will return CentralPaneNavigator route or FullScreenNavigator route. +// This function will return CentralPaneNavigator route or WorkspaceNavigator route. function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): NavigationPartialRoute | undefined { // Check for backTo param. One screen with different backTo value may need diferent screens visible under the overlay. if (route.params && 'backTo' in route.params && typeof route.params.backTo === 'string') { @@ -147,7 +147,7 @@ function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): Navigat } } - // Check for FullScreenNavigator + // Check for WorkspaceNavigator for (const [workspaceScreenName, RHPNames] of Object.entries(WORKSPACE_SCREEN_TO_RHP_MAPPING)) { if (RHPNames.includes(route.name)) { const paramsFromRoute = getParamsFromRoute(workspaceScreenName); @@ -206,8 +206,8 @@ function getAdaptedState(state: PartialState // If the root route is type of WorkspaceNavigator, the default bottom tab will be added. const matchingBottomTabRoute = getMatchingBottomTabRouteForState({routes: matchingRootRoute ? [matchingRootRoute] : []}); routes.push(createBottomTabNavigator(matchingBottomTabRoute, policyID)); - // When we open a screen in RHP from FullScreenNavigator, we need to add the appropriate screen in CentralPane. - // Then, when we close FullScreenNavigator, we will be redirected to the correct page in CentralPane. + // When we open a screen in RHP from WorkspaceNavigator, we need to add the appropriate screen in CentralPane. + // Then, when we close WorkspaceNavigator, we will be redirected to the correct page in CentralPane. if (matchingRootRoute?.name === NAVIGATORS.WORKSPACE_NAVIGATOR) { routes.push({name: SCREENS.SETTINGS.WORKSPACES}); } @@ -229,7 +229,7 @@ function getAdaptedState(state: PartialState // - default central pane on desktop layout // - found lhp / onboardingModalNavigator - // There is no screen in these navigators that would have mandatory central pane, bottom tab or fullscreen navigator. + // There is no screen in these navigators that would have mandatory central pane, bottom tab or workspace navigator. metainfo.isCentralPaneAndBottomTabMandatory = false; metainfo.isWorkspaceNavigatorMandatory = false; const routes = []; @@ -273,7 +273,7 @@ function getAdaptedState(state: PartialState // Routes // - default bottom tab // - default central pane on desktop layout - // - found fullscreen + // - found workspace navigator const routes = []; routes.push( From 4ddc955742b354103470ec297ed2f67f5907380b Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 25 Jul 2024 12:02:04 +0200 Subject: [PATCH 009/257] Add BottomTabBar to WorkspaceInitialPage and SettingsWorkspaces --- .../Navigation/AppNavigator/AuthScreens.tsx | 10 ++++-- .../Navigators/WorkspaceNavigator.tsx | 31 ++++++++++--------- src/pages/home/sidebar/BottomTabAvatar.tsx | 12 ++++++- src/pages/workspace/WorkspaceInitialPage.tsx | 4 ++- src/pages/workspace/WorkspacesListPage.tsx | 7 +++-- 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 5029536782ea..e8b64cac3eaf 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -95,6 +95,7 @@ function shouldOpenOnAdminRoom() { return url ? new URL(url).searchParams.get('openOnAdminRoom') === 'true' : false; } +// @TODO: Add these params to SearchPage and ReportScreen function getCentralPaneScreenInitialParams(screenName: CentralPaneName, initialReportID?: string): Partial> { if (screenName === SCREENS.SEARCH.CENTRAL_PANE) { // Generate default query string with buildSearchQueryString without argument. @@ -579,14 +580,19 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie /> {Object.entries(CENTRAL_PANE_SCREENS).map(([screenName, componentGetter]) => { const centralPaneName = screenName as CentralPaneName; + const options = {...CentralPaneScreenOptions}; + + if (centralPaneName === SCREENS.SETTINGS.WORKSPACES) { + options.animationEnabled = false; + } + return ( ); })} diff --git a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceNavigator.tsx index d6d6cbb1ddae..674d6a019482 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceNavigator.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; @@ -29,22 +30,24 @@ const CENTRAL_PANE_WORKSPACE_SCREENS = { function WorkspaceNavigator() { return ( - - - {Object.entries(CENTRAL_PANE_WORKSPACE_SCREENS).map(([screenName, componentGetter]) => ( + + - ))} - + {Object.entries(CENTRAL_PANE_WORKSPACE_SCREENS).map(([screenName, componentGetter]) => ( + + ))} + + ); } diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index fc11e462d7f2..944b73d6fb31 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -1,3 +1,4 @@ +import {useRoute} from '@react-navigation/native'; import React, {useCallback} from 'react'; import {useOnyx} from 'react-native-onyx'; import {PressableWithFeedback} from '@components/Pressable'; @@ -5,12 +6,14 @@ import Text from '@components/Text'; import Tooltip from '@components/Tooltip'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; import AvatarWithDelegateAvatar from './AvatarWithDelegateAvatar'; import AvatarWithOptionalStatus from './AvatarWithOptionalStatus'; import ProfileAvatarWithIndicator from './ProfileAvatarWithIndicator'; @@ -28,8 +31,10 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT const {translate} = useLocalize(); const [account] = useOnyx(ONYXKEYS.ACCOUNT); const delegateEmail = account?.delegatedAccess?.delegate ?? ''; + const route = useRoute(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const emojiStatus = currentUserPersonalDetails?.status?.emojiCode ?? ''; + const {shouldUseNarrowLayout} = useResponsiveLayout(); const showSettingsPage = useCallback(() => { if (isCreateMenuOpen) { @@ -37,8 +42,13 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT return; } + if (([SCREENS.SETTINGS.WORKSPACES, SCREENS.WORKSPACE.INITIAL] as string[]).includes(route.name) && shouldUseNarrowLayout) { + Navigation.goBack(ROUTES.SETTINGS); + return; + } + interceptAnonymousUser(() => Navigation.navigate(ROUTES.SETTINGS)); - }, [isCreateMenuOpen]); + }, [isCreateMenuOpen, shouldUseNarrowLayout, route.name]); let children; diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 6b595f96b42e..f7d45d277cd7 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -22,6 +22,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import {isConnectionInProgress} from '@libs/actions/connections'; import * as CurrencyUtils from '@libs/CurrencyUtils'; +import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import getTopmostRouteName from '@libs/Navigation/getTopmostRouteName'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; @@ -362,7 +363,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac return ( + ); diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index ea17d945aed5..49187b1c9a88 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -4,15 +4,15 @@ import {useOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import Button from '@components/Button'; import ConfirmModal from '@components/ConfirmModal'; -import FeatureList from '@components/FeatureList'; import type {FeatureListItem} from '@components/FeatureList'; +import FeatureList from '@components/FeatureList'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; import LottieAnimations from '@components/LottieAnimations'; import type {MenuItemProps} from '@components/MenuItem'; -import OfflineWithFeedback from '@components/OfflineWithFeedback'; import type {OfflineWithFeedbackProps} from '@components/OfflineWithFeedback'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; import type {PopoverMenuItem} from '@components/PopoverMenu'; import {PressableWithoutFeedback} from '@components/Pressable'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -27,6 +27,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {isConnectionInProgress} from '@libs/actions/connections'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import localeCompare from '@libs/LocaleCompare'; +import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -37,6 +38,7 @@ import * as Session from '@userActions/Session'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; import type {Policy as PolicyType} from '@src/types/onyx'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; import type {PolicyDetailsForNonMembers} from '@src/types/onyx/Policy'; @@ -436,6 +438,7 @@ function WorkspacesListPage() { cancelText={translate('common.cancel')} danger /> + {isSmallScreenWidth && } ); } From 49d73c83a11e5b17bcbfa1422a1d31e3490e2f30 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 25 Jul 2024 14:50:48 +0200 Subject: [PATCH 010/257] Fix pressing settings tab when navigating deeper into workspaces --- src/pages/home/sidebar/BottomTabAvatar.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index 944b73d6fb31..bac2d9eee7e2 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -42,7 +42,13 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT return; } - if (([SCREENS.SETTINGS.WORKSPACES, SCREENS.WORKSPACE.INITIAL] as string[]).includes(route.name) && shouldUseNarrowLayout) { + if (route.name === SCREENS.SETTINGS.WORKSPACES && shouldUseNarrowLayout) { + Navigation.goBack(ROUTES.SETTINGS); + return; + } + + if (route.name === SCREENS.WORKSPACE.INITIAL) { + Navigation.dismissModal(); Navigation.goBack(ROUTES.SETTINGS); return; } From 79e4a6fec7e555baea6cfe603aef601d3d0dad0c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 25 Jul 2024 15:01:32 +0200 Subject: [PATCH 011/257] Turn off animation for FullScreenNavigator --- .../Navigation/AppNavigator/getRootNavigatorScreenOptions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts index e09f85936385..a59a339c0c6a 100644 --- a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts +++ b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts @@ -107,7 +107,7 @@ const getRootNavigatorScreenOptions: GetRootNavigatorScreenOptions = (isSmallScr }, // We need to turn off animation for the full screen to avoid delay when closing screens. - animationEnabled: isSmallScreenWidth, + animationEnabled: false, }, centralPaneNavigator: { From 96d0d6f47cb5530df584d07c7aca8c0f10cc3faa Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 6 Aug 2024 18:17:55 +0200 Subject: [PATCH 012/257] use shouldUseNarrowLayout instead of isSmallScreenWidth --- src/pages/workspace/WorkspacesListPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 49187b1c9a88..fe79ce141d49 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -438,7 +438,7 @@ function WorkspacesListPage() { cancelText={translate('common.cancel')} danger /> - {isSmallScreenWidth && } + {shouldUseNarrowLayout && } ); } From c31bd2bfc14e6ae98832666b2178b3a4646fdc31 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 6 Aug 2024 18:18:37 +0200 Subject: [PATCH 013/257] fix pressing on settings tab while in workspace navigator --- src/pages/home/sidebar/BottomTabAvatar.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index bac2d9eee7e2..0be364d4922f 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -49,7 +49,6 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT if (route.name === SCREENS.WORKSPACE.INITIAL) { Navigation.dismissModal(); - Navigation.goBack(ROUTES.SETTINGS); return; } From f3870a686146a9baa0e54e2672ef366fc58e18d0 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 3 Sep 2024 12:33:23 +0200 Subject: [PATCH 014/257] Add todo comments for new navigation logic, adjust split navigators, adjust getAdaptedState --- ...on+stack+6.3.29+002+dontDetachScreen.patch | 2 +- src/NAVIGATORS.ts | 4 +- .../Navigation/AppNavigator/AuthScreens.tsx | 32 ++- .../AppNavigator/CENTRAL_PANE_SCREENS.tsx | 22 -- .../Navigators/ReportsSplitNavigator.tsx | 67 +++++ .../Navigators/SettingsSplitNavigator.tsx | 53 ++++ ...igator.tsx => WorkspaceSplitNavigator.tsx} | 16 +- .../CustomRouter.ts | 239 ++++++++++-------- .../createCustomStackNavigator/index.tsx | 93 +------ .../SplitStackRouter.ts | 21 +- src/libs/Navigation/Navigation.ts | 3 +- .../CENTRAL_PANE_TO_RHP_MAPPING.ts | 6 +- .../TAB_TO_CENTRAL_PANE_MAPPING.ts | 27 +- src/libs/Navigation/linkingConfig/config.ts | 131 +++++++--- .../linkingConfig/getAdaptedStateFromPath.ts | 208 ++++++++------- src/libs/Navigation/linkingConfig/index.ts | 2 +- .../getActionForBottomTabNavigator.ts | 50 ++++ .../Navigation/newLinkTo/getMinimalAction.ts | 42 +++ src/libs/Navigation/newLinkTo/index.ts | 239 ++++++++++++++++++ src/libs/Navigation/newLinkTo/types.ts | 11 + src/libs/Navigation/types.ts | 63 ++++- src/libs/ObjectUtils.ts | 13 +- src/libs/actions/Session/index.ts | 1 + src/pages/Search/SearchPage.tsx | 71 +++++- src/pages/WorkspaceSwitcherPage/index.tsx | 7 +- .../SidebarScreen/BaseSidebarScreen.tsx | 3 + .../home/sidebar/SidebarScreen/index.tsx | 9 +- src/pages/settings/InitialSettingsPage.tsx | 5 +- src/styles/index.ts | 13 + 29 files changed, 1027 insertions(+), 426 deletions(-) delete mode 100644 src/libs/Navigation/AppNavigator/CENTRAL_PANE_SCREENS.tsx create mode 100644 src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx create mode 100644 src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx rename src/libs/Navigation/AppNavigator/Navigators/{WorkspaceNavigator.tsx => WorkspaceSplitNavigator.tsx} (94%) create mode 100644 src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts create mode 100644 src/libs/Navigation/newLinkTo/getMinimalAction.ts create mode 100644 src/libs/Navigation/newLinkTo/index.ts create mode 100644 src/libs/Navigation/newLinkTo/types.ts diff --git a/patches/@react-navigation+stack+6.3.29+002+dontDetachScreen.patch b/patches/@react-navigation+stack+6.3.29+002+dontDetachScreen.patch index c65ebbb98007..529e9aab0221 100644 --- a/patches/@react-navigation+stack+6.3.29+002+dontDetachScreen.patch +++ b/patches/@react-navigation+stack+6.3.29+002+dontDetachScreen.patch @@ -43,7 +43,7 @@ index 7558eb3..b7bb75e 100644 }) : STATE_TRANSITIONING_OR_BELOW_TOP; } + -+ const isHomeScreenAndNotOnTop = (route.name === 'BottomTabNavigator' || route.name === 'Workspace_Initial') && isScreenActive !== STATE_ON_TOP; ++ const isHomeScreenAndNotOnTop = (route.name === 'BottomTabNavigator' || route.name === 'Workspace_Initial' || route.name === 'Home' || route.name === 'Search_Bottom_Tab' || route.name === 'Settings_Root') && isScreenActive !== STATE_ON_TOP; + const { headerShown = true, diff --git a/src/NAVIGATORS.ts b/src/NAVIGATORS.ts index cb829856da7f..c6f014f24e72 100644 --- a/src/NAVIGATORS.ts +++ b/src/NAVIGATORS.ts @@ -12,5 +12,7 @@ export default { WELCOME_VIDEO_MODAL_NAVIGATOR: 'WelcomeVideoModalNavigator', EXPLANATION_MODAL_NAVIGATOR: 'ExplanationModalNavigator', FULL_SCREEN_NAVIGATOR: 'FullScreenNavigator', - WORKSPACE_NAVIGATOR: 'WorkspaceNavigator', + REPORTS_SPLIT_NAVIGATOR: 'ReportsSplitNavigator', + SETTINGS_SPLIT_NAVIGATOR: 'SettingsSplitNavigator', + WORKSPACE_SPLIT_NAVIGATOR: 'WorkspaceSplitNavigator', } as const; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index e8b64cac3eaf..b2d4b10e98e8 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -32,6 +32,7 @@ import {buildSearchQueryString} from '@libs/SearchUtils'; import * as SessionUtils from '@libs/SessionUtils'; import ConnectionCompletePage from '@pages/ConnectionCompletePage'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; +import SearchPage from '@pages/Search/SearchPage'; import DesktopSignInRedirectPage from '@pages/signin/DesktopSignInRedirectPage'; import * as App from '@userActions/App'; import * as Download from '@userActions/Download'; @@ -54,18 +55,18 @@ import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; import beforeRemoveReportOpenedFromSearchRHP from './beforeRemoveReportOpenedFromSearchRHP'; -import CENTRAL_PANE_SCREENS from './CENTRAL_PANE_SCREENS'; import createCustomStackNavigator from './createCustomStackNavigator'; import defaultScreenOptions from './defaultScreenOptions'; import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions'; -import BottomTabNavigator from './Navigators/BottomTabNavigator'; import ExplanationModalNavigator from './Navigators/ExplanationModalNavigator'; import FeatureTrainingModalNavigator from './Navigators/FeatureTrainingModalNavigator'; import LeftModalNavigator from './Navigators/LeftModalNavigator'; import OnboardingModalNavigator from './Navigators/OnboardingModalNavigator'; +import ReportsSplitNavigator from './Navigators/ReportsSplitNavigator'; import RightModalNavigator from './Navigators/RightModalNavigator'; +import SettingsSplitNavigator from './Navigators/SettingsSplitNavigator'; import WelcomeVideoModalNavigator from './Navigators/WelcomeVideoModalNavigator'; -import WorkspaceNavigator from './Navigators/WorkspaceNavigator'; +import WorkspaceSplitNavigator from './Navigators/WorkspaceSplitNavigator'; type AuthScreensProps = { /** Session of currently logged in user */ @@ -429,10 +430,21 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie screenOptions={screenOptions.centralPaneNavigator} isSmallScreenWidth={isSmallScreenWidth} > + {/* This have to be the first navigator in auth screens. */} + + - {Object.entries(CENTRAL_PANE_SCREENS).map(([screenName, componentGetter]) => { + {/* {Object.entries(CENTRAL_PANE_SCREENS).map(([screenName, componentGetter]) => { const centralPaneName = screenName as CentralPaneName; const options = {...CentralPaneScreenOptions}; @@ -595,7 +607,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie options={options} /> ); - })} + })} */} diff --git a/src/libs/Navigation/AppNavigator/CENTRAL_PANE_SCREENS.tsx b/src/libs/Navigation/AppNavigator/CENTRAL_PANE_SCREENS.tsx deleted file mode 100644 index 5bbe2046040a..000000000000 --- a/src/libs/Navigation/AppNavigator/CENTRAL_PANE_SCREENS.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import type {CentralPaneName} from '@libs/Navigation/types'; -import withPrepareCentralPaneScreen from '@src/components/withPrepareCentralPaneScreen'; -import SCREENS from '@src/SCREENS'; -import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; - -type Screens = Partial React.ComponentType>>; - -const CENTRAL_PANE_SCREENS = { - [SCREENS.SETTINGS.WORKSPACES]: withPrepareCentralPaneScreen(() => require('../../../pages/workspace/WorkspacesListPage').default), - [SCREENS.SETTINGS.PREFERENCES.ROOT]: withPrepareCentralPaneScreen(() => require('../../../pages/settings/Preferences/PreferencesPage').default), - [SCREENS.SETTINGS.SECURITY]: withPrepareCentralPaneScreen(() => require('../../../pages/settings/Security/SecuritySettingsPage').default), - [SCREENS.SETTINGS.PROFILE.ROOT]: withPrepareCentralPaneScreen(() => require('../../../pages/settings/Profile/ProfilePage').default), - [SCREENS.SETTINGS.WALLET.ROOT]: withPrepareCentralPaneScreen(() => require('../../../pages/settings/Wallet/WalletPage').default), - [SCREENS.SETTINGS.ABOUT]: withPrepareCentralPaneScreen(() => require('../../../pages/settings/AboutPage/AboutPage').default), - [SCREENS.SETTINGS.TROUBLESHOOT]: withPrepareCentralPaneScreen(() => require('../../../pages/settings/Troubleshoot/TroubleshootPage').default), - [SCREENS.SETTINGS.SAVE_THE_WORLD]: withPrepareCentralPaneScreen(() => require('../../../pages/TeachersUnite/SaveTheWorldPage').default), - [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: withPrepareCentralPaneScreen(() => require('../../../pages/settings/Subscription/SubscriptionSettingsPage').default), - [SCREENS.SEARCH.CENTRAL_PANE]: withPrepareCentralPaneScreen(() => require('../../../pages/Search/SearchPage').default), - [SCREENS.REPORT]: withPrepareCentralPaneScreen(() => require('../../../pages/home/ReportScreen').default), -} satisfies Screens; - -export default CENTRAL_PANE_SCREENS; diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx new file mode 100644 index 000000000000..2ad1d7a480c9 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -0,0 +1,67 @@ +import React, {useRef} from 'react'; +import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; +import withPrepareCentralPaneScreen from '@components/withPrepareCentralPaneScreen'; +import useActiveWorkspace from '@hooks/useActiveWorkspace'; +import usePermissions from '@hooks/usePermissions'; +import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; +import getCurrentUrl from '@libs/Navigation/currentUrl'; +import type {ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; +import * as ReportUtils from '@libs/ReportUtils'; +import SidebarScreen from '@pages/home/sidebar/SidebarScreen'; +import CONST from '@src/CONST'; +import SCREENS from '@src/SCREENS'; +import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; + +const loadReportScreen = withPrepareCentralPaneScreen(() => require('../../../../pages/home/ReportScreen').default); + +const Stack = createSplitStackNavigator(); + +function shouldOpenOnAdminRoom() { + const url = getCurrentUrl(); + return url ? new URL(url).searchParams.get('openOnAdminRoom') === 'true' : false; +} + +function ReportsSplitNavigator() { + const {canUseDefaultRooms} = usePermissions(); + const {activeWorkspaceID} = useActiveWorkspace(); + + let initialReportID: string | undefined; + const isInitialRender = useRef(true); + + if (isInitialRender.current) { + const currentURL = getCurrentUrl(); + if (currentURL) { + initialReportID = new URL(currentURL).pathname.match(CONST.REGEX.REPORT_ID_FROM_PATH)?.at(1); + } + + if (!initialReportID) { + const initialReport = ReportUtils.findLastAccessedReport(!canUseDefaultRooms, shouldOpenOnAdminRoom(), activeWorkspaceID); + initialReportID = initialReport?.reportID ?? ''; + } + + isInitialRender.current = false; + } + + return ( + + + + + + + ); +} + +ReportsSplitNavigator.displayName = 'ReportsSplitNavigator'; + +export default ReportsSplitNavigator; diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx new file mode 100644 index 000000000000..62a1af45f10b --- /dev/null +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; +import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; +import type {SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; +import withPrepareCentralPaneScreen from '@src/components/withPrepareCentralPaneScreen'; +import SCREENS from '@src/SCREENS'; +import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; + +const loadInitialSettingsPage = () => require('../../../../pages/settings/InitialSettingsPage').default; + +type Screens = Partial React.ComponentType>>; + +const CENTRAL_PANE_SETTINGS_SCREENS = { + [SCREENS.SETTINGS.WORKSPACES]: withPrepareCentralPaneScreen(() => require('../../../../pages/workspace/WorkspacesListPage').default), + [SCREENS.SETTINGS.PREFERENCES.ROOT]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/Preferences/PreferencesPage').default), + [SCREENS.SETTINGS.SECURITY]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/Security/SecuritySettingsPage').default), + [SCREENS.SETTINGS.PROFILE.ROOT]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/Profile/ProfilePage').default), + [SCREENS.SETTINGS.WALLET.ROOT]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/Wallet/WalletPage').default), + [SCREENS.SETTINGS.ABOUT]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/AboutPage/AboutPage').default), + [SCREENS.SETTINGS.TROUBLESHOOT]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/Troubleshoot/TroubleshootPage').default), + [SCREENS.SETTINGS.SAVE_THE_WORLD]: withPrepareCentralPaneScreen(() => require('../../../../pages/TeachersUnite/SaveTheWorldPage').default), + [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/Subscription/SubscriptionSettingsPage').default), +} satisfies Screens; + +const Stack = createSplitStackNavigator(); + +function SettingsSplitNavigator() { + return ( + + + + {Object.entries(CENTRAL_PANE_SETTINGS_SCREENS).map(([screenName, componentGetter]) => ( + + ))} + + + ); +} + +SettingsSplitNavigator.displayName = 'SettingsSplitNavigator'; + +export {CENTRAL_PANE_SETTINGS_SCREENS}; +export default SettingsSplitNavigator; diff --git a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx similarity index 94% rename from src/libs/Navigation/AppNavigator/Navigators/WorkspaceNavigator.tsx rename to src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx index 674d6a019482..19f37707e857 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx @@ -5,12 +5,10 @@ import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; -const loadWorkspaceInitialPage = () => require('../../../../pages/workspace/WorkspaceInitialPage').default; - -const RootStack = createSplitStackNavigator(); - type Screens = Partial React.ComponentType>>; +const loadWorkspaceInitialPage = () => require('../../../../pages/workspace/WorkspaceInitialPage').default; + const CENTRAL_PANE_WORKSPACE_SCREENS = { [SCREENS.WORKSPACE.PROFILE]: () => require('../../../../pages/workspace/WorkspaceProfilePage').default, [SCREENS.WORKSPACE.WORKFLOWS]: () => require('../../../../pages/workspace/workflows/WorkspaceWorkflowsPage').default, @@ -28,25 +26,27 @@ const CENTRAL_PANE_WORKSPACE_SCREENS = { [SCREENS.WORKSPACE.RULES]: () => require('../../../../pages/workspace/rules/PolicyRulesPage').default, } satisfies Screens; +const Stack = createSplitStackNavigator(); + function WorkspaceNavigator() { return ( - - {Object.entries(CENTRAL_PANE_WORKSPACE_SCREENS).map(([screenName, componentGetter]) => ( - ))} - + ); } diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 3e163bd35b70..1f52c6e1e4a3 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -1,109 +1,18 @@ import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; import {findFocusedRoute, getPathFromState, StackRouter} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/routers'; -import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import * as Localize from '@libs/Localize'; -import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; -import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; +import isSideModalNavigator from '@libs/Navigation/isSideModalNavigator'; import linkingConfig from '@libs/Navigation/linkingConfig'; -import getAdaptedStateFromPath from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; -import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; -import {isCentralPaneName, isOnboardingFlowName} from '@libs/NavigationUtils'; +import {RootStackParamList} from '@libs/Navigation/types'; +import {isOnboardingFlowName} from '@libs/NavigationUtils'; +import * as SearchUtils from '@libs/SearchUtils'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import type {ResponsiveStackNavigatorRouterOptions} from './types'; -function insertRootRoute(state: State, routeToInsert: NavigationPartialRoute) { - const nonModalRoutes = state.routes.filter( - (route) => route.name !== NAVIGATORS.RIGHT_MODAL_NAVIGATOR && route.name !== NAVIGATORS.LEFT_MODAL_NAVIGATOR && route.name !== NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR, - ); - const modalRoutes = state.routes.filter( - (route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || route.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR || route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR, - ); - - // It's safe to modify this state before returning in getRehydratedState. - - // @ts-expect-error Updating read only property - // noinspection JSConstantReassignment - state.routes = [...nonModalRoutes, routeToInsert, ...modalRoutes]; // eslint-disable-line - - // @ts-expect-error Updating read only property - // noinspection JSConstantReassignment - state.index = state.routes.length - 1; // eslint-disable-line - - // @ts-expect-error Updating read only property - // noinspection JSConstantReassignment - state.stale = true; // eslint-disable-line -} - -function compareAndAdaptState(state: StackNavigationState) { - // If the state of the last path is not defined the getPathFromState won't work correctly. - if (!state?.routes.at(-1)?.state) { - return; - } - - // We need to be sure that the bottom tab state is defined. - const topmostBottomTabRoute = getTopmostBottomTabRoute(state); - const isNarrowLayout = getIsNarrowLayout(); - - // This solutions is heuristics and will work for our cases. We may need to improve it in the future if we will have more cases to handle. - if (topmostBottomTabRoute && !isNarrowLayout) { - const fullScreenRoute = state.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR); - - // If there is fullScreenRoute we don't need to add anything. - if (fullScreenRoute) { - return; - } - - // We will generate a template state and compare the current state with it. - // If there is a difference in the screens that should be visible under the overlay, we will add the screen from templateState to the current state. - const pathFromCurrentState = getPathFromState(state, linkingConfig.config); - const {adaptedState: templateState} = getAdaptedStateFromPath(pathFromCurrentState, linkingConfig.config); - - if (!templateState) { - return; - } - - const templateFullScreenRoute = templateState.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR); - - // If templateFullScreenRoute is defined, and full screen route is not in the state, we need to add it. - if (templateFullScreenRoute) { - insertRootRoute(state, templateFullScreenRoute); - return; - } - - const topmostCentralPaneRoute = state.routes.filter((route) => isCentralPaneName(route.name)).at(-1); - const templateCentralPaneRoute = templateState.routes.find((route) => isCentralPaneName(route.name)); - - const topmostCentralPaneRouteExtracted = getTopmostCentralPaneRoute(state); - const templateCentralPaneRouteExtracted = getTopmostCentralPaneRoute(templateState as State); - - // If there is no templateCentralPaneRoute, we don't have anything to add. - if (!templateCentralPaneRoute) { - return; - } - - // If there is no topmostCentralPaneRoute in the state and template state has one, we need to add it. - if (!topmostCentralPaneRoute) { - insertRootRoute(state, templateCentralPaneRoute); - return; - } - - // If there is central pane route in state and template state has one, we need to check if they are the same. - if (topmostCentralPaneRouteExtracted && templateCentralPaneRouteExtracted && topmostCentralPaneRouteExtracted.name !== templateCentralPaneRouteExtracted.name) { - // Not every RHP screen has matching central pane defined. In that case we use the REPORT screen as default for initial screen. - // But we don't want to override the central pane for those screens as they may be opened with different central panes under the overlay. - // e.g. i-know-a-teacher may be opened with different central panes under the overlay - if (templateCentralPaneRouteExtracted.name === SCREENS.REPORT) { - return; - } - insertRootRoute(state, templateCentralPaneRoute); - } - } -} - function shouldPreventReset(state: StackNavigationState, action: CommonActions.Action | StackActionType) { if (action.type !== CONST.NAVIGATION_ACTIONS.RESET || !action?.payload) { return false; @@ -121,23 +30,151 @@ function shouldPreventReset(state: StackNavigationState, action: } } +function shouldDismissSideModalNavigator(state: StackNavigationState, action: CommonActions.Action | StackActionType) { + if (action.type !== CONST.NAVIGATION.ACTION_TYPE.PUSH) { + return false; + } + + const lastRoute = state.routes.at(-1); + + // If the last route is a side modal navigator and the generated minimal action want's to push a new side modal navigator that means they are different ones. + // We want to dismiss the one that is currently on the top. + if (isSideModalNavigator(lastRoute?.name) && isSideModalNavigator(action.payload.name)) { + return true; + } + + return false; +} + +const SCREENS_WITH_WORKSPACE_SWITCHER: string[] = [SCREENS.SEARCH.CENTRAL_PANE, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]; + +// function isPushingScreenWithWorkspaceSwitcher(action: CommonActions.Action | StackActionType): action is StackActionType | {type: 'PUSH'; payload: any} { +// if (action.type !== CONST.NAVIGATION.ACTION_TYPE.PUSH) { +// return false; +// } + +// // Only these screens have the workspace switcher. +// if (SCREENS_WITH_WORKSPACE_SWITCHER.includes(action.payload.name)) { +// return true; +// } + +// return false; +// } + +// eslint-disable-next-line rulesdir/no-inline-named-export +type CustomRootStackActionType = { + type: 'SWITCH_POLICY_ID'; + payload: {policyID: string}; +}; + +// function extractPolicyIDFromState(state: StackNavigationState) { +// for (let i = state.routes.length - 1; i >= 0; i--) { +// const route = state.routes[i]; +// if (route.name === SCREENS.SEARCH.CENTRAL_PANE) { +// return extractPolicyIDFromQuery(route as NavigationPartialRoute); +// } +// if (route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { +// const params = route.params ? (route.params as RootStackParamList[typeof NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]) : undefined; +// return params?.policyID; +// } +// } +// } + function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { const stackRouter = StackRouter(options); + // @TODO: Make sure that everything works fine without compareAndAdaptState function return { ...stackRouter, - getRehydratedState(partialState: StackNavigationState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): StackNavigationState { - compareAndAdaptState(partialState); - const state = stackRouter.getRehydratedState(partialState, {routeNames, routeParamList, routeGetIdList}); - return state; - }, - getStateForAction(state: StackNavigationState, action: CommonActions.Action | StackActionType, configOptions: RouterConfigOptions) { + getStateForAction(state: StackNavigationState, action: CommonActions.Action | StackActionType | CustomRootStackActionType, configOptions: RouterConfigOptions) { + // TODO: Put this into const; + if (action.type === 'SWITCH_POLICY_ID') { + const lastRoute = state.routes.at(-1); + if (lastRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { + const currentParams = lastRoute.params as RootStackParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; + const queryJSON = SearchUtils.buildSearchQueryJSON(currentParams.q); + let newParams = null; + + if (!queryJSON) { + return; + } + + if (action.payload.policyID) { + queryJSON.policyID = action.payload.policyID; + newParams = {...currentParams, q: SearchUtils.buildSearchQueryString(queryJSON)}; + } else { + delete queryJSON.policyID; + newParams = {...currentParams, q: SearchUtils.buildSearchQueryString(queryJSON)}; + } + + const newRoutes = [...state.routes, {...lastRoute, params: newParams}]; + return {...state, routes: newRoutes, index: newRoutes.length - 1}; + } + if (lastRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { + // TODO: handle change policy id of reports navigator. + return; + } + // In other cases, do nothing. + return null; + } + + // Don't let the user navigate back to a non-onboarding screen if they are currently on an onboarding screen and it's not finished. if (shouldPreventReset(state, action)) { return state; } + + // TODO: I don't remember if the code below makes sense Wojtek :D but it's possible. + // One part seems redundant to the lines 102-108 above + // + // Copy existing policyID to the new screen. + // TODO: Can't figure out the types for + // if (action.type === 'PUSH' && isPushingScreenWithWorkspaceSwitcher(action)) { + // const policyID = extractPolicyIDFromState(state); + + // // If there is no policyID, continue with the default behavior. + // if (!policyID) { + // return stackRouter.getStateForAction(state, action, configOptions); + // } + + // // If there is, we need to add it to the new screen. + // // + // const modifiedAction = {...action}; + + // if (action.payload.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { + // modifiedAction.payload.params = {...action.payload.params, policyID}; + // } + + // if (action.payload.name === SCREENS.SEARCH.CENTRAL_PANE) { + // if (policyID) { + // const queryJSON = SearchUtils.buildSearchQueryJSON(params.q); + // if (queryJSON) { + // queryJSON.policyID = policyID; + // params.q = SearchUtils.buildSearchQueryString(queryJSON); + // } + // } else { + // const queryJSON = SearchUtils.buildSearchQueryJSON(params.q); + // if (queryJSON) { + // delete queryJSON.policyID; + // params.q = SearchUtils.buildSearchQueryString(queryJSON); + // } + // } + // action.payload.params = {...action.payload.params, policyID: extractPolicyIDFromState(state)}; + // } + + // // This shouldn't happen, but if it does, we don't want to break the app. + // console.error('Unhandled screen with workspace switcher:', action.payload.name); + // return; + // } + + if (shouldDismissSideModalNavigator(state, action)) { + const modifiedState = {...state, routes: state.routes.slice(0, -1), index: state.index !== 0 ? state.index - 1 : 0}; + return stackRouter.getStateForAction(modifiedState, action, configOptions); + } + return stackRouter.getStateForAction(state, action, configOptions); }, }; } export default CustomRouter; +export type {CustomRootStackActionType}; diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx index 6c153b1b159e..af4407af6dc2 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx @@ -1,44 +1,13 @@ -import type {ParamListBase, RouteProp, StackActionHelpers, StackNavigationState} from '@react-navigation/native'; +import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native'; import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; import {StackView} from '@react-navigation/stack'; -import React, {useEffect, useMemo} from 'react'; -import {View} from 'react-native'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import useThemeStyles from '@hooks/useThemeStyles'; -import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; -import navigationRef from '@libs/Navigation/navigationRef'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; -import {isCentralPaneName} from '@libs/NavigationUtils'; -import SCREENS from '@src/SCREENS'; +import React, {useMemo} from 'react'; import CustomRouter from './CustomRouter'; import type {ResponsiveStackNavigatorProps, ResponsiveStackNavigatorRouterOptions} from './types'; -type Routes = StackNavigationState['routes']; -function reduceCentralPaneRoutes(routes: Routes): Routes { - const result: Routes = []; - let count = 0; - const reverseRoutes = [...routes].reverse(); - - reverseRoutes.forEach((route) => { - if (isCentralPaneName(route.name)) { - // Remove all central pane routes except the last 3. This will improve performance. - if (count < 3) { - result.push(route); - count++; - } - } else { - result.push(route); - } - }); - - return result.reverse(); -} - function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { - const {shouldUseNarrowLayout} = useResponsiveLayout(); - const styles = useThemeStyles(); - + // TODO: This part needs some TS magic to work. const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< StackNavigationState, ResponsiveStackNavigatorRouterOptions, @@ -51,57 +20,14 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { initialRouteName: props.initialRouteName, }); - useEffect(() => { - if (!navigationRef.isReady()) { - return; - } - navigationRef.resetRoot(navigationRef.getRootState()); - }, [shouldUseNarrowLayout]); - - const {stateToRender, searchRoute} = useMemo(() => { - const routes = reduceCentralPaneRoutes(state.routes); - - if (shouldUseNarrowLayout) { - const isSearchCentralPane = (route: RouteProp) => getTopmostCentralPaneRoute({routes: [route]} as State)?.name === SCREENS.SEARCH.CENTRAL_PANE; - - const lastRoute = routes.at(-1); - const lastSearchCentralPane = lastRoute && isSearchCentralPane(lastRoute) ? lastRoute : undefined; - const filteredRoutes = routes.filter((route) => !isSearchCentralPane(route)); - - // On narrow layout, if we are on /search route we want to hide all central pane routes and show only the bottom tab navigator. - if (lastSearchCentralPane) { - const filteredRoute = filteredRoutes.at(0); - if (filteredRoute) { - return { - stateToRender: { - ...state, - index: 0, - routes: [filteredRoute], - }, - searchRoute: lastSearchCentralPane, - }; - } - } - - return { - stateToRender: { - ...state, - index: filteredRoutes.length - 1, - routes: filteredRoutes, - }, - searchRoute: undefined, - }; - } - + const stateToRender = useMemo(() => { + const routes = state.routes.slice(-3); return { - stateToRender: { - ...state, - index: routes.length - 1, - routes: [...routes], - }, - searchRoute: undefined, + ...state, + routes, + index: routes.length - 1, }; - }, [state, shouldUseNarrowLayout]); + }, [state]); return ( @@ -112,7 +38,6 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { descriptors={descriptors} navigation={navigation} /> - {searchRoute && {descriptors[searchRoute.key].render()}} ); } diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts index 37db6f1ae5d3..ef0af961540f 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts @@ -1,4 +1,4 @@ -import type {ParamListBase, PartialState, RouterConfigOptions, StackNavigationState} from '@react-navigation/native'; +import type {CommonActions, ParamListBase, PartialState, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; import {StackRouter} from '@react-navigation/native'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import type {SplitStackNavigatorRouterOptions} from './types'; @@ -47,10 +47,29 @@ function adaptStateIfNecessary(state: StackState, sidebarScreen: string, default } } +function isPushingSidebarOnCentralPane(state: StackState, action: CommonActions.Action | StackActionType, options: SplitStackNavigatorRouterOptions) { + if (action.type === 'PUSH' && action.payload.name === options.sidebarScreen && state.routes.length > 1) { + return true; + } + return false; +} + function SplitStackRouter(options: SplitStackNavigatorRouterOptions) { const stackRouter = StackRouter(options); return { ...stackRouter, + getStateForAction(state: StackNavigationState, action: CommonActions.Action | StackActionType, configOptions: RouterConfigOptions) { + if (isPushingSidebarOnCentralPane(state, action, options)) { + if (getIsNarrowLayout()) { + // TODO: It's possible that it's better to push whole new SplitNavigator in such case. Not sure yet. + // Pop to top on narrow layout. + return {...state, routes: [state.routes.at(0)], index: 0}; + } + // On wide screen do nothing as we want to keep the central pane screen and the sidebar is visible. + return state; + } + return stackRouter.getStateForAction(state, action, configOptions); + }, getInitialState({routeNames, routeParamList, routeGetIdList}: RouterConfigOptions) { const initialState = stackRouter.getInitialState({routeNames, routeParamList, routeGetIdList}); adaptStateIfNecessary(initialState, options.sidebarScreen, options.defaultCentralScreen); diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 22a9bf6fc042..4b485beb3618 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -23,8 +23,8 @@ import originalGetTopmostReportId from './getTopmostReportId'; import isReportOpenInRHP from './isReportOpenInRHP'; import linkingConfig from './linkingConfig'; import getMatchingBottomTabRouteForState from './linkingConfig/getMatchingBottomTabRouteForState'; -import linkTo from './linkTo'; import navigationRef from './navigationRef'; +import linkTo from './newLinkTo'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; import switchPolicyID from './switchPolicyID'; import type {NavigationStateRoute, RootStackParamList, State, StateOrRoute, SwitchPolicyIDParams} from './types'; @@ -194,6 +194,7 @@ function navigate(route: Route = ROUTES.HOME, type?: string) { pendingRoute = route; return; } + // linkTo(navigationRef.current, route, type, isActiveRoute(route)); linkTo(navigationRef.current, route, type, isActiveRoute(route)); } diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts index 5d2a6b75c224..674f4ca81314 100755 --- a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts @@ -1,7 +1,8 @@ -import type {CentralPaneName} from '@libs/Navigation/types'; +import type {SplitNavigatorScreenName} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; +import WORKSPACE_SCREEN_TO_RHP_MAPPING from './WORKSPACE_SCREEN_TO_RHP_MAPPING'; -const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = { +const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = { [SCREENS.SETTINGS.PROFILE.ROOT]: [ SCREENS.SETTINGS.PROFILE.DISPLAY_NAME, SCREENS.SETTINGS.PROFILE.CONTACT_METHODS, @@ -80,6 +81,7 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = SCREENS.SETTINGS.SUBSCRIPTION.CHANGE_BILLING_CURRENCY, SCREENS.SETTINGS.SUBSCRIPTION.CHANGE_PAYMENT_CURRENCY, ], + ...WORKSPACE_SCREEN_TO_RHP_MAPPING, }; export default CENTRAL_PANE_TO_RHP_MAPPING; diff --git a/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts b/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts index a68959ae7d0f..653c26e06e1c 100755 --- a/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts @@ -1,9 +1,8 @@ -import type {BottomTabName, CentralPaneName} from '@navigation/types'; +import type {BottomTabName, CentralPaneName, SplitNavigatorScreenName} from '@navigation/types'; import SCREENS from '@src/SCREENS'; -const TAB_TO_CENTRAL_PANE_MAPPING: Record = { +const TAB_TO_CENTRAL_PANE_MAPPING: Record = { [SCREENS.HOME]: [SCREENS.REPORT], - [SCREENS.SEARCH.BOTTOM_TAB]: [SCREENS.SEARCH.CENTRAL_PANE], [SCREENS.SETTINGS.ROOT]: [ SCREENS.SETTINGS.PROFILE.ROOT, SCREENS.SETTINGS.PREFERENCES.ROOT, @@ -15,19 +14,33 @@ const TAB_TO_CENTRAL_PANE_MAPPING: Record = { SCREENS.SETTINGS.TROUBLESHOOT, SCREENS.SETTINGS.SUBSCRIPTION.ROOT, ], + [SCREENS.WORKSPACE.INITIAL]: [ + SCREENS.WORKSPACE.PROFILE, + SCREENS.WORKSPACE.REIMBURSE, + SCREENS.WORKSPACE.MEMBERS, + SCREENS.WORKSPACE.WORKFLOWS, + SCREENS.WORKSPACE.ACCOUNTING.ROOT, + SCREENS.WORKSPACE.TAXES, + SCREENS.WORKSPACE.TAGS, + SCREENS.WORKSPACE.CATEGORIES, + SCREENS.WORKSPACE.DISTANCE_RATES, + SCREENS.WORKSPACE.REPORT_FIELDS, + SCREENS.WORKSPACE.INVOICES, + SCREENS.WORKSPACE.EXPENSIFY_CARD, + ], }; -const generateCentralPaneToTabMapping = (): Record => { - const mapping: Record = {} as Record; +const generateCentralPaneToTabMapping = (): Record => { + const mapping: Record = {} as Record; for (const [tabName, CentralPaneNames] of Object.entries(TAB_TO_CENTRAL_PANE_MAPPING)) { for (const CentralPaneName of CentralPaneNames) { - mapping[CentralPaneName] = tabName as BottomTabName; + mapping[CentralPaneName] = tabName as SplitNavigatorScreenName; } } return mapping; }; -const CENTRAL_PANE_TO_TAB_MAPPING: Record = generateCentralPaneToTabMapping(); +const CENTRAL_PANE_TO_TAB_MAPPING: Record = generateCentralPaneToTabMapping(); export {CENTRAL_PANE_TO_TAB_MAPPING}; export default TAB_TO_CENTRAL_PANE_MAPPING; diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 7c893aeca74d..210db4ef6fad 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -9,7 +9,8 @@ import createNormalizedConfigs from './createNormalizedConfigs'; // Moved to a separate file to avoid cyclic dependencies. const config: LinkingOptions['config'] = { - initialRouteName: NAVIGATORS.BOTTOM_TAB_NAVIGATOR, + // initialRouteName: NAVIGATORS.BOTTOM_TAB_NAVIGATOR, + initialRouteName: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, screens: { // Main Routes [SCREENS.VALIDATE_LOGIN]: ROUTES.VALIDATE_LOGIN, @@ -29,49 +30,49 @@ const config: LinkingOptions['config'] = { [SCREENS.REPORT_AVATAR]: ROUTES.REPORT_AVATAR.route, [SCREENS.TRANSACTION_RECEIPT]: ROUTES.TRANSACTION_RECEIPT.route, [SCREENS.WORKSPACE_JOIN_USER]: ROUTES.WORKSPACE_JOIN_USER.route, - [SCREENS.REPORT]: ROUTES.REPORT_WITH_ID.route, - [SCREENS.SETTINGS.PROFILE.ROOT]: { - path: ROUTES.SETTINGS_PROFILE, - exact: true, - }, - [SCREENS.SETTINGS.PREFERENCES.ROOT]: { - path: ROUTES.SETTINGS_PREFERENCES, - exact: true, - }, - [SCREENS.SETTINGS.SECURITY]: { - path: ROUTES.SETTINGS_SECURITY, - exact: true, - }, - [SCREENS.SETTINGS.WALLET.ROOT]: { - path: ROUTES.SETTINGS_WALLET, - exact: true, - }, - [SCREENS.SETTINGS.ABOUT]: { - path: ROUTES.SETTINGS_ABOUT, - exact: true, - }, - [SCREENS.SETTINGS.TROUBLESHOOT]: { - path: ROUTES.SETTINGS_TROUBLESHOOT, - exact: true, - }, - [SCREENS.SETTINGS.WORKSPACES]: ROUTES.SETTINGS_WORKSPACES, + // [SCREENS.REPORT]: ROUTES.REPORT_WITH_ID.route, + // [SCREENS.SETTINGS.PROFILE.ROOT]: { + // path: ROUTES.SETTINGS_PROFILE, + // exact: true, + // }, + // [SCREENS.SETTINGS.PREFERENCES.ROOT]: { + // path: ROUTES.SETTINGS_PREFERENCES, + // // exact: true, + // }, + // [SCREENS.SETTINGS.SECURITY]: { + // path: ROUTES.SETTINGS_SECURITY, + // exact: true, + // }, + // [SCREENS.SETTINGS.WALLET.ROOT]: { + // path: ROUTES.SETTINGS_WALLET, + // exact: true, + // }, + // [SCREENS.SETTINGS.ABOUT]: { + // path: ROUTES.SETTINGS_ABOUT, + // exact: true, + // }, + // [SCREENS.SETTINGS.TROUBLESHOOT]: { + // path: ROUTES.SETTINGS_TROUBLESHOOT, + // exact: true, + // }, + // [SCREENS.SETTINGS.WORKSPACES]: ROUTES.SETTINGS_WORKSPACES, [SCREENS.SEARCH.CENTRAL_PANE]: { path: ROUTES.SEARCH_CENTRAL_PANE.route, }, - [SCREENS.SETTINGS.SAVE_THE_WORLD]: ROUTES.SETTINGS_SAVE_THE_WORLD, - [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: ROUTES.SETTINGS_SUBSCRIPTION, + // [SCREENS.SETTINGS.SAVE_THE_WORLD]: ROUTES.SETTINGS_SAVE_THE_WORLD, + // [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: ROUTES.SETTINGS_SUBSCRIPTION, // Sidebar - [NAVIGATORS.BOTTOM_TAB_NAVIGATOR]: { - path: ROUTES.ROOT, - initialRouteName: SCREENS.HOME, - screens: { - [SCREENS.HOME]: ROUTES.HOME, - [SCREENS.SETTINGS.ROOT]: { - path: ROUTES.SETTINGS, - }, - }, - }, + // [NAVIGATORS.BOTTOM_TAB_NAVIGATOR]: { + // path: ROUTES.ROOT, + // initialRouteName: SCREENS.HOME, + // screens: { + // [SCREENS.HOME]: ROUTES.HOME, + // // [SCREENS.SETTINGS.ROOT]: { + // // path: ROUTES.SETTINGS, + // // }, + // }, + // }, [SCREENS.NOT_FOUND]: '*', [NAVIGATORS.LEFT_MODAL_NAVIGATOR]: { @@ -1241,7 +1242,57 @@ const config: LinkingOptions['config'] = { }, }, - [NAVIGATORS.WORKSPACE_NAVIGATOR]: { + [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: { + path: ROUTES.ROOT, + screens: { + [SCREENS.HOME]: { + path: ROUTES.HOME, + exact: true, + }, + [SCREENS.REPORT]: { + path: ROUTES.REPORT_WITH_ID.route, + exact: true, + }, + }, + }, + + [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: { + screens: { + [SCREENS.SETTINGS.ROOT]: ROUTES.SETTINGS, + [SCREENS.SETTINGS.WORKSPACES]: { + path: ROUTES.SETTINGS_WORKSPACES, + exact: true, + }, + [SCREENS.SETTINGS.PROFILE.ROOT]: { + path: ROUTES.SETTINGS_PROFILE, + exact: true, + }, + [SCREENS.SETTINGS.SECURITY]: { + path: ROUTES.SETTINGS_SECURITY, + exact: true, + }, + [SCREENS.SETTINGS.WALLET.ROOT]: { + path: ROUTES.SETTINGS_WALLET, + exact: true, + }, + [SCREENS.SETTINGS.ABOUT]: { + path: ROUTES.SETTINGS_ABOUT, + exact: true, + }, + [SCREENS.SETTINGS.TROUBLESHOOT]: { + path: ROUTES.SETTINGS_TROUBLESHOOT, + exact: true, + }, + [SCREENS.SETTINGS.SAVE_THE_WORLD]: ROUTES.SETTINGS_SAVE_THE_WORLD, + [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: ROUTES.SETTINGS_SUBSCRIPTION, + [SCREENS.SETTINGS.PREFERENCES.ROOT]: { + path: ROUTES.SETTINGS_PREFERENCES, + // exact: true, + }, + }, + }, + + [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: { screens: { [SCREENS.WORKSPACE.INITIAL]: { path: ROUTES.WORKSPACE_INITIAL.route, diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 293827b1bd2e..435bc138b829 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -4,7 +4,7 @@ import pick from 'lodash/pick'; import type {TupleToUnion} from 'type-fest'; import {isAnonymousUser} from '@libs/actions/Session'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import type {BottomTabName, CentralPaneName, NavigationPartialRoute, RootStackParamList, WorkspaceScreenName} from '@libs/Navigation/types'; +import type {BottomTabName, CentralPaneName, NavigationPartialRoute, RootStackParamList, SplitNavigatorScreenName} from '@libs/Navigation/types'; import {isCentralPaneName} from '@libs/NavigationUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; @@ -17,9 +17,8 @@ import SCREENS from '@src/SCREENS'; import CENTRAL_PANE_TO_RHP_MAPPING from './CENTRAL_PANE_TO_RHP_MAPPING'; import config, {normalizedConfigs} from './config'; import getMatchingBottomTabRouteForState from './getMatchingBottomTabRouteForState'; -import getMatchingCentralPaneRouteForState from './getMatchingCentralPaneRouteForState'; import replacePathInNestedState from './replacePathInNestedState'; -import WORKSPACE_SCREEN_TO_RHP_MAPPING from './WORKSPACE_SCREEN_TO_RHP_MAPPING'; +import {CENTRAL_PANE_TO_TAB_MAPPING} from './TAB_TO_CENTRAL_PANE_MAPPING'; const RHP_SCREENS_OPENED_FROM_LHN = [ SCREENS.SETTINGS.SHARE_CODE, @@ -31,6 +30,12 @@ const RHP_SCREENS_OPENED_FROM_LHN = [ SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM, ] satisfies Screen[]; +const mapLhnToSplitNavigatorName = { + [SCREENS.SETTINGS.ROOT]: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, + [SCREENS.HOME]: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, + [SCREENS.WORKSPACE.INITIAL]: NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, +}; + type RHPScreenOpenedFromLHN = TupleToUnion; type Metainfo = { @@ -44,11 +49,14 @@ type Metainfo = { type GetAdaptedStateReturnType = { adaptedState: ReturnType; - metainfo: Metainfo; + // metainfo: Metainfo; }; type GetAdaptedStateFromPath = (...args: [...Parameters, shouldReplacePathInNestedState?: boolean]) => GetAdaptedStateReturnType; +type SplitNavigatorLHNScreen = keyof typeof mapLhnToSplitNavigatorName; +type SplitNavigator = (typeof mapLhnToSplitNavigatorName)[SplitNavigatorLHNScreen]; + // The function getPathFromState that we are using in some places isn't working correctly without defined index. const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState => ({routes, index: routes.length - 1}); @@ -78,14 +86,44 @@ function createBottomTabNavigator(route: NavigationPartialRoute, }; } -function createWorkspaceNavigator(route?: NavigationPartialRoute): NavigationPartialRoute { +// function createWorkspaceNavigator(route?: NavigationPartialRoute): NavigationPartialRoute { +// const routes = []; + +// const policyID = route?.params && 'policyID' in route.params ? route.params.policyID : undefined; + +// // Both routes in WorkspaceNavigator should store a policyID in params, so here this param is also passed to the screen displayed in LHN in WorkspaceNavigator +// routes.push({ +// name: SCREENS.WORKSPACE.INITIAL, +// params: { +// policyID, +// }, +// }); + +// if (route) { +// routes.push(route); +// } +// return { +// name: NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, +// state: getRoutesWithIndex(routes), +// }; +// } + +function getParamsFromRoute(screenName: string): string[] { + const routeConfig = normalizedConfigs[screenName as Screen]; + + const route = routeConfig.pattern; + + return route.match(/(?<=[:?&])(\w+)(?=[/=?&]|$)/g) ?? []; +} + +function createSplitNavigator(splitNavigatorLHNScreen: SplitNavigatorLHNScreen, route?: NavigationPartialRoute): NavigationPartialRoute { const routes = []; const policyID = route?.params && 'policyID' in route.params ? route.params.policyID : undefined; // Both routes in WorkspaceNavigator should store a policyID in params, so here this param is also passed to the screen displayed in LHN in WorkspaceNavigator routes.push({ - name: SCREENS.WORKSPACE.INITIAL, + name: splitNavigatorLHNScreen, params: { policyID, }, @@ -95,21 +133,13 @@ function createWorkspaceNavigator(route?: NavigationPartialRoute | undefined { +function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): NavigationPartialRoute | undefined { // Check for backTo param. One screen with different backTo value may need diferent screens visible under the overlay. if (route.params && 'backTo' in route.params && typeof route.params.backTo === 'string') { const stateForBackTo = getStateFromPath(route.params.backTo, config); @@ -142,19 +172,21 @@ function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): Navigat for (const [centralPaneName, RHPNames] of Object.entries(CENTRAL_PANE_TO_RHP_MAPPING)) { if (RHPNames.includes(route.name)) { const paramsFromRoute = getParamsFromRoute(centralPaneName); - - return {name: centralPaneName as CentralPaneName, params: pick(route.params, paramsFromRoute)}; + return createSplitNavigator(CENTRAL_PANE_TO_TAB_MAPPING[centralPaneName] as SplitNavigatorLHNScreen, { + name: centralPaneName as SplitNavigatorScreenName, + params: pick(route.params, paramsFromRoute), + }); } } // Check for WorkspaceNavigator - for (const [workspaceScreenName, RHPNames] of Object.entries(WORKSPACE_SCREEN_TO_RHP_MAPPING)) { - if (RHPNames.includes(route.name)) { - const paramsFromRoute = getParamsFromRoute(workspaceScreenName); + // for (const [workspaceScreenName, RHPNames] of Object.entries(WORKSPACE_SCREEN_TO_RHP_MAPPING)) { + // if (RHPNames.includes(route.name)) { + // const paramsFromRoute = getParamsFromRoute(workspaceScreenName); - return createWorkspaceNavigator({name: workspaceScreenName as WorkspaceScreenName, params: pick(route.params, paramsFromRoute)}); - } - } + // return createWorkspaceNavigator({name: workspaceScreenName as WorkspaceScreenName, params: pick(route.params, paramsFromRoute)}); + // } + // } // check for valid reportID in the route params // if the reportID is valid, we should navigate back to screen report in CPN @@ -166,15 +198,13 @@ function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): Navigat function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { const isNarrowLayout = getIsNarrowLayout(); - const metainfo = { - isCentralPaneAndBottomTabMandatory: true, - isWorkspaceNavigatorMandatory: true, - }; + // const metainfo = { + // isCentralPaneAndBottomTabMandatory: true, + // isWorkspaceNavigatorMandatory: true, + // }; // We need to check what is defined to know what we need to add. - const bottomTabNavigator = state.routes.find((route) => route.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR); - const centralPaneNavigator = state.routes.find((route) => isCentralPaneName(route.name)); - const WorkspaceNavigator = state.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR); + const WorkspaceNavigator = state.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR); const rhpNavigator = state.routes.find((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR); const lhpNavigator = state.routes.find((route) => route.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR); const onboardingModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR); @@ -197,19 +227,16 @@ function getAdaptedState(state: PartialState const isRHPScreenOpenedFromLHN = focusedRHPRoute?.name && RHP_SCREENS_OPENED_FROM_LHN.includes(focusedRHPRoute?.name as RHPScreenOpenedFromLHN); // This may happen if this RHP doesn't have a route that should be under the overlay defined. if (!matchingRootRoute || isRHPScreenOpenedFromLHN) { - metainfo.isCentralPaneAndBottomTabMandatory = false; - metainfo.isWorkspaceNavigatorMandatory = false; + // metainfo.isCentralPaneAndBottomTabMandatory = false; + // metainfo.isWorkspaceNavigatorMandatory = false; // If matchingRootRoute is undefined and it's a narrow layout, don't add a report screen under the RHP. matchingRootRoute = matchingRootRoute ?? (!isNarrowLayout ? {name: SCREENS.REPORT} : undefined); } - // If the root route is type of WorkspaceNavigator, the default bottom tab will be added. - const matchingBottomTabRoute = getMatchingBottomTabRouteForState({routes: matchingRootRoute ? [matchingRootRoute] : []}); - routes.push(createBottomTabNavigator(matchingBottomTabRoute, policyID)); // When we open a screen in RHP from WorkspaceNavigator, we need to add the appropriate screen in CentralPane. // Then, when we close WorkspaceNavigator, we will be redirected to the correct page in CentralPane. - if (matchingRootRoute?.name === NAVIGATORS.WORKSPACE_NAVIGATOR) { - routes.push({name: SCREENS.SETTINGS.WORKSPACES}); + if (matchingRootRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { + routes.push(createSplitNavigator(SCREENS.SETTINGS.ROOT, {name: SCREENS.SETTINGS.WORKSPACES})); } if (matchingRootRoute && (!isNarrowLayout || !isRHPScreenOpenedFromLHN)) { @@ -220,7 +247,7 @@ function getAdaptedState(state: PartialState routes.push(rhpNavigator); return { adaptedState: getRoutesWithIndex(routes), - metainfo, + // metainfo, }; } if (lhpNavigator ?? onboardingModalNavigator ?? welcomeVideoModalNavigator ?? featureTrainingModalNavigator) { @@ -230,22 +257,17 @@ function getAdaptedState(state: PartialState // - found lhp / onboardingModalNavigator // There is no screen in these navigators that would have mandatory central pane, bottom tab or workspace navigator. - metainfo.isCentralPaneAndBottomTabMandatory = false; - metainfo.isWorkspaceNavigatorMandatory = false; + // metainfo.isCentralPaneAndBottomTabMandatory = false; + // metainfo.isWorkspaceNavigatorMandatory = false; const routes = []; - routes.push( - createBottomTabNavigator( - { - name: SCREENS.HOME, - }, - policyID, - ), - ); - if (!isNarrowLayout) { - routes.push({ - name: SCREENS.REPORT, - }); - } + + const splitNavigatorMainScreen = !isNarrowLayout + ? { + name: SCREENS.REPORT, + } + : undefined; + + routes.push(createSplitNavigator(SCREENS.HOME, splitNavigatorMainScreen)); // Separate ifs are necessary for typescript to see that we are not pushing undefined to the array. if (lhpNavigator) { @@ -266,7 +288,7 @@ function getAdaptedState(state: PartialState return { adaptedState: getRoutesWithIndex(routes), - metainfo, + // metainfo, }; } if (WorkspaceNavigator) { @@ -277,39 +299,35 @@ function getAdaptedState(state: PartialState const routes = []; routes.push( - createBottomTabNavigator( - { - name: SCREENS.SETTINGS.ROOT, + createSplitNavigator(SCREENS.SETTINGS.ROOT, { + name: SCREENS.SETTINGS.WORKSPACES, + params: { + policyID, }, - policyID, - ), + }), ); - routes.push({ - name: SCREENS.SETTINGS.WORKSPACES, - }); - routes.push(WorkspaceNavigator); return { adaptedState: getRoutesWithIndex(routes), - metainfo, - }; - } - if (centralPaneNavigator) { - // Routes - // - matching bottom tab - // - found central pane - const routes = []; - const matchingBottomTabRoute = getMatchingBottomTabRouteForState(state); - routes.push(createBottomTabNavigator(matchingBottomTabRoute, policyID)); - routes.push(centralPaneNavigator); - - return { - adaptedState: getRoutesWithIndex(routes), - metainfo, + // metainfo, }; } + // if (centralPaneNavigator) { + // // Routes + // // - matching bottom tab + // // - found central pane + // const routes = []; + // const matchingBottomTabRoute = getMatchingBottomTabRouteForState(state); + // routes.push(createBottomTabNavigator(matchingBottomTabRoute, policyID)); + // routes.push(centralPaneNavigator); + + // return { + // adaptedState: getRoutesWithIndex(routes), + // // metainfo, + // }; + // } if (attachmentsScreen) { // Routes // - matching bottom tab @@ -328,44 +346,16 @@ function getAdaptedState(state: PartialState return { adaptedState: getRoutesWithIndex(routes), - metainfo, + // metainfo, }; } } // We need to make sure that this if only handles states where we deeplink to the bottom tab directly - if (bottomTabNavigator && bottomTabNavigator.state) { - // Routes - // - found bottom tab - // - matching central pane on desktop layout - - // We want to make sure that the bottom tab search page is always pushed with matching central pane page. Even on the narrow layout. - if (isNarrowLayout && bottomTabNavigator.state?.routes.at(0)?.name !== SCREENS.SEARCH.BOTTOM_TAB) { - return { - adaptedState: state, - metainfo, - }; - } - - const routes = [...state.routes]; - const matchingCentralPaneRoute = getMatchingCentralPaneRouteForState(state); - if (matchingCentralPaneRoute) { - routes.push(matchingCentralPaneRoute); - } else { - // If there is no matching central pane, we want to add the default one. - metainfo.isCentralPaneAndBottomTabMandatory = false; - routes.push({name: SCREENS.REPORT}); - } - - return { - adaptedState: getRoutesWithIndex(routes), - metainfo, - }; - } return { adaptedState: state, - metainfo, + // metainfo, }; } diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index 1f556aa67809..7bb5e8ae5b5a 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -15,7 +15,7 @@ const linkingConfig: LinkingOptions = { return adaptedState; }, subscribe, - getPathFromState: customGetPathFromState, + // getPathFromState: customGetPathFromState, prefixes, config, }; diff --git a/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts b/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts new file mode 100644 index 000000000000..85580d068ad7 --- /dev/null +++ b/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts @@ -0,0 +1,50 @@ +import type {NavigationAction, NavigationState} from '@react-navigation/native'; +import type {Writable} from 'type-fest'; +import type {RootStackParamList, StackNavigationAction} from '@libs/Navigation/types'; +import getTopmostBottomTabRoute from '@navigation/getTopmostBottomTabRoute'; +import CONST from '@src/CONST'; +import type {ActionPayloadParams} from './types'; + +// Because we need to change the type to push, we also need to set target for this action to the bottom tab navigator. +function getActionForBottomTabNavigator( + action: StackNavigationAction, + state: NavigationState, + policyID?: string, + shouldNavigate?: boolean, +): Writable | undefined { + const bottomTabNavigatorRoute = state.routes.at(0); + if (!bottomTabNavigatorRoute || bottomTabNavigatorRoute.state === undefined || !action || action.type !== CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { + return; + } + + const params = action.payload.params as ActionPayloadParams; + let payloadParams = params.params as Record; + const screen = params.screen; + + if (policyID && !payloadParams?.policyID) { + payloadParams = {...payloadParams, policyID}; + } else if (!policyID) { + delete payloadParams?.policyID; + } + + // Check if the current bottom tab is the same as the one we want to navigate to. If it is, we don't need to do anything. + const bottomTabCurrentTab = getTopmostBottomTabRoute(state); + const bottomTabParams = bottomTabCurrentTab?.params as Record; + + // Verify if the policyID is different than the one we are currently on. If it is, we need to navigate to the new policyID. + const isNewPolicy = bottomTabParams?.policyID !== payloadParams?.policyID; + if (bottomTabCurrentTab?.name === screen && !shouldNavigate && !isNewPolicy) { + return; + } + + return { + type: CONST.NAVIGATION.ACTION_TYPE.PUSH, + payload: { + name: screen, + params: payloadParams, + }, + target: bottomTabNavigatorRoute.state.key, + }; +} + +export default getActionForBottomTabNavigator; diff --git a/src/libs/Navigation/newLinkTo/getMinimalAction.ts b/src/libs/Navigation/newLinkTo/getMinimalAction.ts new file mode 100644 index 000000000000..ff01b3b8333b --- /dev/null +++ b/src/libs/Navigation/newLinkTo/getMinimalAction.ts @@ -0,0 +1,42 @@ +import type {NavigationAction, NavigationState} from '@react-navigation/native'; +import type {Writable} from 'type-fest'; +import type {State} from '@navigation/types'; +import type {ActionPayload} from './types'; + +/** + * Motivation for this function is described in NAVIGATION.md + * + * @param action action generated by getActionFromState + * @param state The root state + * @returns minimalAction minimal action is the action that we should dispatch + */ +function getMinimalAction(action: NavigationAction, state: NavigationState): Writable { + let currentAction: NavigationAction = action; + let currentState: State | undefined = state; + let currentTargetKey: string | undefined; + + while (currentAction.payload && 'name' in currentAction.payload && currentState?.routes[currentState.index ?? -1].name === currentAction.payload.name) { + if (!currentState?.routes[currentState.index ?? -1].state) { + break; + } + + currentState = currentState?.routes[currentState.index ?? -1].state; + currentTargetKey = currentState?.key; + + const payload = currentAction.payload as ActionPayload; + + // Creating new smaller action + currentAction = { + type: currentAction.type, + payload: { + name: payload?.params?.screen, + params: payload?.params?.params, + path: payload?.params?.path, + }, + target: currentTargetKey, + }; + } + return currentAction; +} + +export default getMinimalAction; diff --git a/src/libs/Navigation/newLinkTo/index.ts b/src/libs/Navigation/newLinkTo/index.ts new file mode 100644 index 000000000000..0f278a9dfc24 --- /dev/null +++ b/src/libs/Navigation/newLinkTo/index.ts @@ -0,0 +1,239 @@ +import {getActionFromState} from '@react-navigation/core'; +import type {NavigationContainerRef, NavigationState, PartialState} from '@react-navigation/native'; +import {findFocusedRoute} from '@react-navigation/native'; +import {shallowCompare} from '@libs/ObjectUtils'; +import {getPathWithoutPolicyID} from '@libs/PolicyUtils'; +import getStateFromPath from '@navigation/getStateFromPath'; +import linkingConfig from '@navigation/linkingConfig'; +import type {RootStackParamList, StackNavigationAction} from '@navigation/types'; +import CONST from '@src/CONST'; +import type {Route} from '@src/ROUTES'; +import getMinimalAction from './getMinimalAction'; + +function shouldDispatchAction(currentState: NavigationState, stateFromPath: PartialState>) { + const currentFocusedRoute = findFocusedRoute(currentState); + const targetFocusedRoute = findFocusedRoute(stateFromPath); + + const areNamesEqual = currentFocusedRoute?.name === targetFocusedRoute?.name; + const areParamsEqual = shallowCompare(currentFocusedRoute?.params as Record | undefined, targetFocusedRoute?.params as Record | undefined); + + if (areNamesEqual && areParamsEqual) { + return false; + } + + return true; +} + +export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string, isActiveRoute?: boolean) { + if (!navigation) { + throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); + } + + const pathWithoutPolicyID = getPathWithoutPolicyID(`/${path}`) as Route; + + // This is the state generated with the default getStateFromPath function. + // It won't include the whole state that will be generated for this path but the focused route will be correct. + // It is necessary because getActionFromState will generate RESET action for whole state generated with our custom getStateFromPath function. + const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; + const currentState = navigation.getRootState() as NavigationState; + const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); + + // We don't want to dispatch action to push/replace with exactly the same route that is already focused. + if (!shouldDispatchAction(currentState, stateFromPath)) { + return; + } + + // If there is no action, just reset the whole state. + if (!action) { + navigation.resetRoot(stateFromPath); + return; + } + + if (action.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { + // We want to PUSH by default to add entries to the browser history. + action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; + } + + if (!shouldDispatchAction(currentState, stateFromPath)) { + return; + } + + const minimalAction = getMinimalAction(action, navigation.getRootState()); + navigation.dispatch(minimalAction); + + // const pathWithoutPolicyID = getPathWithoutPolicyID(`/${path}`) as Route; + // const rootState = navigation.getRootState() as NavigationState; + // const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; + // // Creating path with /w/ included if necessary. + // const topmostCentralPaneRoute = getTopmostCentralPaneRoute(rootState); + // const policyIDs = !!topmostCentralPaneRoute?.params && 'policyIDs' in topmostCentralPaneRoute.params ? (topmostCentralPaneRoute?.params?.policyIDs as string) : ''; + // const extractedPolicyID = extractPolicyIDFromPath(`/${path}`); + // const policyIDFromState = getPolicyIDFromState(rootState); + // const policyID = extractedPolicyID ?? policyIDFromState ?? policyIDs; + // const lastRoute = rootState?.routes?.at(-1); + + // const isNarrowLayout = getIsNarrowLayout(); + + // const isWorkspaceScreenOnTop = lastRoute?.name === NAVIGATORS.WORKSPACE_NAVIGATOR; + + // // policyIDs is present only on SCREENS.SEARCH.CENTRAL_PANE and it's displayed in the url as a query param, on the other pages this parameter is called policyID and it's shown in the url in the format: /w/:policyID + // if (policyID && !isWorkspaceScreenOnTop && !policyIDs) { + // // The stateFromPath doesn't include proper path if there is a policy passed with /w/id. + // // We need to replace the path in the state with the proper one. + // // To avoid this hacky solution we may want to create custom getActionFromState function in the future. + // replacePathInNestedState(stateFromPath, `/w/${policyID}${pathWithoutPolicyID}`); + // } + + // const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); + + // const isReportInRhpOpened = isReportOpenInRHP(rootState); + + // // If action type is different than NAVIGATE we can't change it to the PUSH safely + // if (action?.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { + // const actionPayloadParams = action.payload.params as ActionPayloadParams; + + // const topRouteName = lastRoute?.name; + + // // CentralPane screens aren't nested in any navigator, if actionPayloadParams?.screen is undefined, it means the screen name and parameters have to be read directly from action.payload + // const targetName = actionPayloadParams?.screen ?? action.payload.name; + // const targetParams = actionPayloadParams?.params ?? actionPayloadParams; + // const isTargetNavigatorOnTop = topRouteName === action.payload.name; + + // const isTargetScreenDifferentThanCurrent = !!(!topmostCentralPaneRoute || topmostCentralPaneRoute.name !== targetName); + // const areParamsDifferent = + // targetName === SCREENS.REPORT + // ? getTopmostReportId(rootState) !== getTopmostReportId(stateFromPath) + // : !shallowCompare( + // omitBy(topmostCentralPaneRoute?.params as Record | undefined, (value) => value === undefined), + // omitBy(targetParams as Record | undefined, (value) => value === undefined), + // ); + + // // If this action is navigating to the report screen and the top most navigator is different from the one we want to navigate - PUSH the new screen to the top of the stack by default + // if (isCentralPaneName(action.payload.name) && (isTargetScreenDifferentThanCurrent || areParamsDifferent)) { + // // We need to push a tab if the tab doesn't match the central pane route that we are going to push. + // const topmostBottomTabRoute = getTopmostBottomTabRoute(rootState); + // const policyIDsFromState = extractPolicyIDsFromState(stateFromPath); + // const matchingBottomTabRoute = getMatchingBottomTabRouteForState(stateFromPath, policyID || policyIDsFromState); + // const isOpeningSearch = matchingBottomTabRoute.name === SCREENS.SEARCH.BOTTOM_TAB; + // const isNewPolicyID = + // ((topmostBottomTabRoute?.params as Record)?.policyID ?? '') !== + // ((matchingBottomTabRoute?.params as Record)?.policyID ?? ''); + + // if (topmostBottomTabRoute && (topmostBottomTabRoute.name !== matchingBottomTabRoute.name || isNewPolicyID || isOpeningSearch)) { + // root.dispatch({ + // type: CONST.NAVIGATION.ACTION_TYPE.PUSH, + // payload: matchingBottomTabRoute, + // }); + // } + + // if (type === CONST.NAVIGATION.TYPE.UP) { + // action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; + // } else { + // action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; + // } + + // // If we navigate to SCREENS.SEARCH.CENTRAL_PANE, it's necessary to pass the current policyID, but we have to remember that this param is called policyIDs on this page + // if (targetName === SCREENS.SEARCH.CENTRAL_PANE && targetParams && policyID) { + // (targetParams as Record).policyIDs = policyID; + // } + + // // If the type is UP, we deeplinked into one of the RHP flows and we want to replace the current screen with the previous one in the flow + // // and at the same time we want the back button to go to the page we were before the deeplink + // } else if (type === CONST.NAVIGATION.TYPE.UP) { + // action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; + + // // If this action is navigating to ModalNavigator or WorkspaceNavigator and the last route on the root navigator is not already opened Navigator then push + // } else if ((action.payload.name === NAVIGATORS.WORKSPACE_NAVIGATOR || isSideModalNavigator(action.payload.name)) && !isTargetNavigatorOnTop) { + // if (isSideModalNavigator(topRouteName)) { + // dismissModal(navigation); + // } + + // // If this RHP has mandatory central pane and bottom tab screens defined we need to push them. + // const {adaptedState, metainfo} = getAdaptedStateFromPath(path, linkingConfig.config); + // if (adaptedState && (metainfo.isCentralPaneAndBottomTabMandatory || metainfo.isWorkspaceNavigatorMandatory)) { + // const diff = getPartialStateDiff(rootState, adaptedState as State, metainfo); + // const diffActions = getActionsFromPartialDiff(diff); + // for (const diffAction of diffActions) { + // root.dispatch(diffAction); + // } + // } + // // All actions related to FullScreenNavigator on wide screen are pushed when comparing differences between rootState and adaptedState. + // if (action.payload.name === NAVIGATORS.WORKSPACE_NAVIGATOR) { + // return; + // } + // action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; + + // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + // } else if (action.payload.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR) { + // // If path contains a policyID, we should invoke the navigate function + // const shouldNavigate = !!extractedPolicyID; + // const actionForBottomTabNavigator = getActionForBottomTabNavigator(action, rootState, policyID, shouldNavigate); + + // if (!actionForBottomTabNavigator) { + // return; + // } + + // root.dispatch(actionForBottomTabNavigator); + + // // If the layout is wide we need to push matching central pane route to the stack. + // if (!isNarrowLayout) { + // // stateFromPath should always include bottom tab navigator state, so getMatchingCentralPaneRouteForState will be always defined. + // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + // const matchingCentralPaneRoute = getMatchingCentralPaneRouteForState(stateFromPath, rootState)!; + // if (matchingCentralPaneRoute && 'name' in matchingCentralPaneRoute) { + // root.dispatch({ + // type: CONST.NAVIGATION.ACTION_TYPE.PUSH, + // payload: { + // name: matchingCentralPaneRoute.name, + // params: matchingCentralPaneRoute.params, + // }, + // }); + // } + // } else { + // // If the layout is small we need to pop everything from the central pane so the bottom tab navigator is visible. + // root.dispatch({ + // type: 'POP_TO_TOP', + // target: rootState.key, + // }); + // } + // return; + // } + // } + + // if (action && 'payload' in action && action.payload && 'name' in action.payload && isSideModalNavigator(action.payload.name)) { + // // Information about the state may be in the params. + // const currentFocusedRoute = findFocusedRoute(extrapolateStateFromParams(rootState)); + // const targetFocusedRoute = findFocusedRoute(stateFromPath); + + // // If the current focused route is the same as the target focused route, we don't want to navigate. + // if ( + // currentFocusedRoute?.name === targetFocusedRoute?.name && + // shallowCompare(currentFocusedRoute?.params as Record, targetFocusedRoute?.params as Record) + // ) { + // return; + // } + + // const minimalAction = getMinimalAction(action, navigation.getRootState()); + // if (minimalAction) { + // // There are situations where a route already exists on the current navigation stack + // // But we want to push the same route instead of going back in the stack + // // Which would break the user navigation history + // if (!isActiveRoute && type === CONST.NAVIGATION.ACTION_TYPE.PUSH) { + // minimalAction.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; + // } + // root.dispatch(minimalAction); + // return; + // } + // } + + // // When we navigate from the ReportScreen opened in RHP, this page shouldn't be removed from the navigation state to allow users to go back to it. + // if (isReportInRhpOpened && action) { + // action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; + // } + + // if (action !== undefined) { + // root.dispatch(action); + // } else { + // root.reset(stateFromPath); + // } +} diff --git a/src/libs/Navigation/newLinkTo/types.ts b/src/libs/Navigation/newLinkTo/types.ts new file mode 100644 index 000000000000..254a4cdef2a5 --- /dev/null +++ b/src/libs/Navigation/newLinkTo/types.ts @@ -0,0 +1,11 @@ +type ActionPayloadParams = { + screen?: string; + params?: unknown; + path?: string; +}; + +type ActionPayload = { + params?: ActionPayloadParams; +}; + +export type {ActionPayload, ActionPayloadParams}; diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index ce1a062beaff..571f57896d79 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -58,19 +58,19 @@ type CentralPaneScreensParamList = { openOnAdminRoom?: boolean; referrer?: string; }; - [SCREENS.SETTINGS.PROFILE.ROOT]: undefined; + // [SCREENS.SETTINGS.WORKSPACES]: undefined; [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; + // [SCREENS.SETTINGS.PROFILE.ROOT]: undefined; [SCREENS.SETTINGS.SECURITY]: undefined; - [SCREENS.SETTINGS.WALLET.ROOT]: undefined; + // [SCREENS.SETTINGS.WALLET.ROOT]: undefined; [SCREENS.SETTINGS.ABOUT]: undefined; [SCREENS.SETTINGS.TROUBLESHOOT]: undefined; - [SCREENS.SETTINGS.WORKSPACES]: undefined; [SCREENS.SEARCH.CENTRAL_PANE]: { q: SearchQueryString; name?: string; }; - [SCREENS.SETTINGS.SAVE_THE_WORLD]: undefined; + // [SCREENS.SETTINGS.SAVE_THE_WORLD]: undefined; [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: undefined; }; @@ -109,17 +109,16 @@ type SettingsNavigatorParamList = { [SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD]: { backTo: Routes; }; - [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; + // [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: undefined; [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE]: undefined; [SCREENS.SETTINGS.PREFERENCES.LANGUAGE]: undefined; [SCREENS.SETTINGS.PREFERENCES.THEME]: undefined; [SCREENS.SETTINGS.CLOSE]: undefined; - [SCREENS.SETTINGS.SECURITY]: undefined; - [SCREENS.SETTINGS.ABOUT]: undefined; - [SCREENS.SETTINGS.TROUBLESHOOT]: undefined; + // [SCREENS.SETTINGS.SECURITY]: undefined; + // [SCREENS.SETTINGS.ABOUT]: undefined; [SCREENS.SETTINGS.APP_DOWNLOAD_LINKS]: undefined; - [SCREENS.SETTINGS.TROUBLESHOOT]: undefined; + // [SCREENS.SETTINGS.TROUBLESHOOT]: undefined; [SCREENS.SETTINGS.CONSOLE]: { backTo: Routes; }; @@ -1283,7 +1282,30 @@ type TravelNavigatorParamList = { [SCREENS.TRAVEL.MY_TRIPS]: undefined; }; -type WorkspaceNavigatorParamList = { +type ReportsSplitNavigatorParamList = { + [SCREENS.HOME]: {policyID?: string}; + [SCREENS.REPORT]: { + reportActionID: string; + reportID: string; + openOnAdminRoom?: boolean; + referrer?: string; + }; +}; + +type SettingsSplitNavigatorParamList = { + [SCREENS.SETTINGS.ROOT]: {policyID?: string}; + [SCREENS.SETTINGS.WORKSPACES]: undefined; + [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; + [SCREENS.SETTINGS.SECURITY]: undefined; + [SCREENS.SETTINGS.PROFILE.ROOT]: undefined; + [SCREENS.SETTINGS.WALLET.ROOT]: undefined; + [SCREENS.SETTINGS.ABOUT]: undefined; + [SCREENS.SETTINGS.TROUBLESHOOT]: undefined; + [SCREENS.SETTINGS.SAVE_THE_WORLD]: undefined; + [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: undefined; +}; + +type WorkspaceSplitNavigatorParamList = { [SCREENS.WORKSPACE.INITIAL]: { policyID: string; backTo?: string; @@ -1461,9 +1483,11 @@ type AuthScreensParamList = CentralPaneScreensParamList & policyID?: string; }; [SCREENS.NOT_FOUND]: undefined; + [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: NavigatorScreenParams & {policyID?: string}; + [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: NavigatorScreenParams; + [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: NavigatorScreenParams; [NAVIGATORS.LEFT_MODAL_NAVIGATOR]: NavigatorScreenParams; [NAVIGATORS.RIGHT_MODAL_NAVIGATOR]: NavigatorScreenParams; - [NAVIGATORS.WORKSPACE_NAVIGATOR]: NavigatorScreenParams; [NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR]: NavigatorScreenParams; [NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR]: NavigatorScreenParams; [NAVIGATORS.WELCOME_VIDEO_MODAL_NAVIGATOR]: NavigatorScreenParams; @@ -1529,18 +1553,28 @@ type RootStackParamList = PublicScreensParamList & AuthScreensParamList & LeftMo type BottomTabName = keyof BottomTabNavigatorParamList; -type WorkspaceScreenName = keyof WorkspaceNavigatorParamList; +type WorkspaceScreenName = keyof WorkspaceSplitNavigatorParamList; type CentralPaneName = keyof CentralPaneScreensParamList; type OnboardingFlowName = keyof OnboardingModalNavigatorParamList; +type SplitNavigatorScreenName = keyof WorkspaceSplitNavigatorParamList & keyof SettingsSplitNavigatorParamList & keyof ReportsSplitNavigatorParamList; + type SwitchPolicyIDParams = { policyID?: string; route?: Routes; isPolicyAdmin?: boolean; }; +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace ReactNavigation { + // eslint-disable-next-line @typescript-eslint/consistent-type-definitions, @typescript-eslint/no-empty-interface + interface RootParamList extends RootStackParamList {} + } +} + export type { AddPersonalBankAccountNavigatorParamList, AuthScreensParamList, @@ -1556,7 +1590,7 @@ export type { ExplanationModalNavigatorParamList, FlagCommentNavigatorParamList, WorkspaceScreenName, - WorkspaceNavigatorParamList, + WorkspaceSplitNavigatorParamList, LeftModalNavigatorParamList, MoneyRequestNavigatorParamList, NavigationPartialRoute, @@ -1576,10 +1610,12 @@ export type { ReportDescriptionNavigatorParamList, ReportDetailsNavigatorParamList, ReportSettingsNavigatorParamList, + ReportsSplitNavigatorParamList, RightModalNavigatorParamList, RoomMembersNavigatorParamList, RootStackParamList, SettingsNavigatorParamList, + SettingsSplitNavigatorParamList, SignInNavigatorParamList, FeatureTrainingNavigatorParamList, SplitDetailsNavigatorParamList, @@ -1599,4 +1635,5 @@ export type { RestrictedActionParamList, MissingPersonalDetailsParamList, DebugParamList, + SplitNavigatorScreenName, }; diff --git a/src/libs/ObjectUtils.ts b/src/libs/ObjectUtils.ts index 644fe1c7596e..9e5a4fc5d8d7 100644 --- a/src/libs/ObjectUtils.ts +++ b/src/libs/ObjectUtils.ts @@ -1,13 +1,20 @@ +const getDefinedKeys = (obj: Record): string[] => { + return Object.entries(obj) + .filter(([, value]) => value !== undefined) + .map(([key]) => key); +}; + const shallowCompare = (obj1?: Record, obj2?: Record): boolean => { if (!obj1 && !obj2) { return true; } if (obj1 && obj2) { - const keys1 = Object.keys(obj1); - const keys2 = Object.keys(obj2); + const keys1 = getDefinedKeys(obj1); + const keys2 = getDefinedKeys(obj2); return keys1.length === keys2.length && keys1.every((key) => obj1[key] === obj2[key]); } return false; }; -export default shallowCompare; +// eslint-disable-next-line import/prefer-default-export +export {shallowCompare}; diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index 4d6ba6cfa774..585f08d13f78 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -757,6 +757,7 @@ function cleanupSession() { PersistedRequests.clear(); NetworkConnection.clearReconnectionCallbacks(); SessionUtils.resetDidUserLogInDuringSession(); + // TODO: Check if this breaks something resetHomeRouteParams(); clearCache().then(() => { Log.info('Cleared all cache data', true, {}, true); diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 7f82aaabfc6f..18bcb74e5c99 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -1,27 +1,45 @@ +// eslint-disable-next-line import/extensions, prettier/prettier import type {StackScreenProps} from '@react-navigation/stack'; import React, {useMemo} from 'react'; +import {View} from 'react-native'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import Search from '@components/Search'; +import {useSearchContext} from '@components/Search/SearchContext'; import SearchPageHeader from '@components/Search/SearchPageHeader'; import SearchStatusBar from '@components/Search/SearchStatusBar'; +import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; +import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; +import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; +import TopBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar'; import Navigation from '@libs/Navigation/Navigation'; import type {AuthScreensParamList} from '@libs/Navigation/types'; import * as SearchUtils from '@libs/SearchUtils'; import ROUTES from '@src/ROUTES'; -import type SCREENS from '@src/SCREENS'; +import SCREENS from '@src/SCREENS'; +import SearchTypeMenu from './SearchTypeMenu'; type SearchPageProps = StackScreenProps; function SearchPage({route}: SearchPageProps) { + const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const styles = useThemeStyles(); + const {q} = route.params; - const queryJSON = useMemo(() => SearchUtils.buildSearchQueryJSON(q), [q]); + const {queryJSON, policyID} = useMemo(() => { + const parsedQuery = SearchUtils.buildSearchQueryJSON(q); + const extractedPolicyID = parsedQuery && SearchUtils.getPolicyIDFromSearchQuery(parsedQuery); + + return {queryJSON: parsedQuery, policyID: extractedPolicyID}; + }, [q]); + const handleOnBackButtonPress = () => Navigation.goBack(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query: SearchUtils.buildCannedSearchQuery()})); + const {clearSelectedTransactions} = useSearchContext(); // On small screens this page is not displayed, the configuration is in the file: src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx // To avoid calling hooks in the Search component when this page isn't visible, we return null here. @@ -42,18 +60,42 @@ function SearchPage({route}: SearchPageProps) { shouldShowLink={false} > {queryJSON && ( - <> - - - - + + + {/* {!selectionMode?.isEnabled && queryJSON ? ( */} + {queryJSON ? ( + + + + + ) : ( + { + clearSelectedTransactions(); + turnOffMobileSelectionMode(); + }} + /> + )} + + + <> + + + + + )} @@ -61,5 +103,6 @@ function SearchPage({route}: SearchPageProps) { } SearchPage.displayName = 'SearchPage'; +SearchPage.whyDidYouRender = true; export default SearchPage; diff --git a/src/pages/WorkspaceSwitcherPage/index.tsx b/src/pages/WorkspaceSwitcherPage/index.tsx index 221889b80b49..ea9e00ba607a 100644 --- a/src/pages/WorkspaceSwitcherPage/index.tsx +++ b/src/pages/WorkspaceSwitcherPage/index.tsx @@ -14,7 +14,7 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation from '@libs/Navigation/Navigation'; +import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import {sortWorkspacesBySelected} from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -90,10 +90,11 @@ function WorkspaceSwitcherPage() { const {policyID} = option; - setActiveWorkspaceID(policyID); + // setActiveWorkspaceID(policyID); Navigation.goBack(); if (policyID !== activeWorkspaceID) { - Navigation.navigateWithSwitchPolicyID({policyID}); + // Navigation.navigateWithSwitchPolicyID({policyID}); + navigationRef.dispatch({type: 'SWITCH_POLICY_ID', payload: {policyID}}); } }, [activeWorkspaceID, setActiveWorkspaceID], diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx index edc8dfb3cb3a..b82865dd13c7 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx @@ -7,6 +7,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {updateLastAccessedWorkspace} from '@libs/actions/Policy/Policy'; import * as Browser from '@libs/Browser'; +import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import TopBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar'; import Navigation from '@libs/Navigation/Navigation'; import Performance from '@libs/Performance'; @@ -14,6 +15,7 @@ import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import Timing from '@userActions/Timing'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import SCREENS from '@src/SCREENS'; /** * Function called when a pinned chat is selected. @@ -63,6 +65,7 @@ function BaseSidebarScreen() { insets={insets} /> + )} diff --git a/src/pages/home/sidebar/SidebarScreen/index.tsx b/src/pages/home/sidebar/SidebarScreen/index.tsx index 625491674cd8..3190c7b7aa71 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.tsx +++ b/src/pages/home/sidebar/SidebarScreen/index.tsx @@ -1,12 +1,13 @@ import React from 'react'; -import FreezeWrapper from '@libs/Navigation/FreezeWrapper'; +// import FreezeWrapper from '@libs/Navigation/FreezeWrapper'; import BaseSidebarScreen from './BaseSidebarScreen'; +// TODO-SPLITS: Figure out how to handle the FreezeWrapper component. function SidebarScreen() { return ( - - - + // + + // ); } diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 48873a342a6f..d26ea2b73f97 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -1,10 +1,10 @@ import {useRoute} from '@react-navigation/native'; import React, {useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react'; -// eslint-disable-next-line no-restricted-imports import type {GestureResponderEvent, ScrollView as RNScrollView, ScrollViewProps, StyleProp, ViewStyle} from 'react-native'; import {NativeModules, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; +// eslint-disable-next-line no-restricted-imports import AccountSwitcher from '@components/AccountSwitcher'; import AccountSwitcherSkeletonView from '@components/AccountSwitcherSkeletonView'; import ConfirmModal from '@components/ConfirmModal'; @@ -29,6 +29,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import * as CurrencyUtils from '@libs/CurrencyUtils'; +import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import Navigation from '@libs/Navigation/Navigation'; import * as SubscriptionUtils from '@libs/SubscriptionUtils'; import * as UserUtils from '@libs/UserUtils'; @@ -44,6 +45,7 @@ import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; import type {Icon as TIcon} from '@src/types/onyx/OnyxCommon'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; @@ -428,6 +430,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr onCancel={() => toggleSignoutConfirmModal(false)} /> + ); } diff --git a/src/styles/index.ts b/src/styles/index.ts index 8220389867d9..f1c93a3d6d73 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1552,6 +1552,19 @@ const styles = (theme: ThemeColors) => ...wordBreak.breakWord, }, + searchSplitContainer: { + flex: 1, + flexDirection: 'row', + }, + + searchSidebar: { + width: variables.sideBarWidth, + height: '100%', + justifyContent: 'space-between', + borderRightWidth: 1, + borderColor: theme.border, + }, + // Sidebar Styles sidebar: { backgroundColor: theme.sidebar, From 6a296fe6fc5013764983b93fe9fb3b06f945afc5 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 3 Sep 2024 14:20:38 +0200 Subject: [PATCH 015/257] Remove ActiveCentralPaneRouteContext --- src/hooks/useActiveCentralPaneRoute.ts | 9 ----- .../ActiveCentralPaneRouteContext.ts | 6 ---- .../Navigators/BottomTabNavigator.tsx | 36 ++++++++----------- src/pages/Search/SearchPage.tsx | 11 ++++-- src/pages/Search/SearchPageBottomTab.tsx | 22 +++++------- src/pages/settings/InitialSettingsPage.tsx | 16 ++++----- 6 files changed, 40 insertions(+), 60 deletions(-) delete mode 100644 src/hooks/useActiveCentralPaneRoute.ts delete mode 100644 src/libs/Navigation/AppNavigator/Navigators/ActiveCentralPaneRouteContext.ts diff --git a/src/hooks/useActiveCentralPaneRoute.ts b/src/hooks/useActiveCentralPaneRoute.ts deleted file mode 100644 index 05354e810c3d..000000000000 --- a/src/hooks/useActiveCentralPaneRoute.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {useContext} from 'react'; -import ActiveCentralPaneRouteContext from '@libs/Navigation/AppNavigator/Navigators/ActiveCentralPaneRouteContext'; -import type {AuthScreensParamList, NavigationPartialRoute} from '@libs/Navigation/types'; - -function useActiveCentralPaneRoute(): NavigationPartialRoute | undefined { - return useContext(ActiveCentralPaneRouteContext); -} - -export default useActiveCentralPaneRoute; diff --git a/src/libs/Navigation/AppNavigator/Navigators/ActiveCentralPaneRouteContext.ts b/src/libs/Navigation/AppNavigator/Navigators/ActiveCentralPaneRouteContext.ts deleted file mode 100644 index 6f37126584a2..000000000000 --- a/src/libs/Navigation/AppNavigator/Navigators/ActiveCentralPaneRouteContext.ts +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import type {AuthScreensParamList, NavigationPartialRoute} from '@libs/Navigation/types'; - -const ActiveCentralPaneRouteContext = React.createContext | undefined>(undefined); - -export default ActiveCentralPaneRouteContext; diff --git a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx index 30e8d4c668c6..c045e01ee2dd 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx @@ -1,14 +1,11 @@ -import {useNavigationState} from '@react-navigation/native'; import type {StackNavigationOptions} from '@react-navigation/stack'; import React from 'react'; import createCustomBottomTabNavigator from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator'; -import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; -import type {BottomTabNavigatorParamList, CentralPaneName, NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; +import type {BottomTabNavigatorParamList} from '@libs/Navigation/types'; import SidebarScreen from '@pages/home/sidebar/SidebarScreen'; import SearchPageBottomTab from '@pages/Search/SearchPageBottomTab'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; -import ActiveCentralPaneRouteContext from './ActiveCentralPaneRouteContext'; const loadInitialSettingsPage = () => require('../../../../pages/settings/InitialSettingsPage').default; const Tab = createCustomBottomTabNavigator(); @@ -19,24 +16,21 @@ const screenOptions: StackNavigationOptions = { }; function BottomTabNavigator() { - const activeRoute = useNavigationState | undefined>(getTopmostCentralPaneRoute); return ( - - - - - - - + + + + + ); } diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 18bcb74e5c99..3091d422e3e1 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -20,6 +20,7 @@ import type {AuthScreensParamList} from '@libs/Navigation/types'; import * as SearchUtils from '@libs/SearchUtils'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; +import SearchPageBottomTab from './SearchPageBottomTab'; import SearchTypeMenu from './SearchTypeMenu'; type SearchPageProps = StackScreenProps; @@ -29,7 +30,7 @@ function SearchPage({route}: SearchPageProps) { const {shouldUseNarrowLayout} = useResponsiveLayout(); const styles = useThemeStyles(); - const {q} = route.params; + const {q, name} = route.params; const {queryJSON, policyID} = useMemo(() => { const parsedQuery = SearchUtils.buildSearchQueryJSON(q); @@ -44,7 +45,13 @@ function SearchPage({route}: SearchPageProps) { // On small screens this page is not displayed, the configuration is in the file: src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx // To avoid calling hooks in the Search component when this page isn't visible, we return null here. if (shouldUseNarrowLayout) { - return null; + return ( + + ); } return ( diff --git a/src/pages/Search/SearchPageBottomTab.tsx b/src/pages/Search/SearchPageBottomTab.tsx index c72462d1f66e..b96088faa4db 100644 --- a/src/pages/Search/SearchPageBottomTab.tsx +++ b/src/pages/Search/SearchPageBottomTab.tsx @@ -6,19 +6,17 @@ import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView import ScreenWrapper from '@components/ScreenWrapper'; import Search from '@components/Search'; import SearchStatusBar from '@components/Search/SearchStatusBar'; -import useActiveCentralPaneRoute from '@hooks/useActiveCentralPaneRoute'; +import type {SearchQueryJSON} from '@components/Search/types'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import Navigation from '@libs/Navigation/Navigation'; -import type {AuthScreensParamList} from '@libs/Navigation/types'; import * as SearchUtils from '@libs/SearchUtils'; import TopBar from '@navigation/AppNavigator/createCustomBottomTabNavigator/TopBar'; import variables from '@styles/variables'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; import SearchSelectionModeHeader from './SearchSelectionModeHeader'; import SearchTypeMenu from './SearchTypeMenu'; @@ -26,11 +24,17 @@ const TOO_CLOSE_TO_TOP_DISTANCE = 10; const TOO_CLOSE_TO_BOTTOM_DISTANCE = 10; const ANIMATION_DURATION_IN_MS = 300; -function SearchPageBottomTab() { +type SearchPageBottomTabProps = { + queryJSON?: SearchQueryJSON; + policyID?: string; + searchName?: string; +}; + +function SearchPageBottomTab({queryJSON, policyID, searchName}: SearchPageBottomTabProps) { const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const {windowHeight} = useWindowDimensions(); - const activeCentralPaneRoute = useActiveCentralPaneRoute(); + const styles = useThemeStyles(); const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE); @@ -59,14 +63,6 @@ function SearchPageBottomTab() { }, }); - const searchParams = activeCentralPaneRoute?.params as AuthScreensParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; - const parsedQuery = SearchUtils.buildSearchQueryJSON(searchParams?.q); - const searchName = searchParams?.name; - const policyIDFromSearchQuery = parsedQuery && SearchUtils.getPolicyIDFromSearchQuery(parsedQuery); - const isActiveCentralPaneRoute = activeCentralPaneRoute?.name === SCREENS.SEARCH.CENTRAL_PANE; - const queryJSON = isActiveCentralPaneRoute ? parsedQuery : undefined; - const policyID = isActiveCentralPaneRoute ? policyIDFromSearchQuery : undefined; - const handleOnBackButtonPress = () => Navigation.goBack(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query: SearchUtils.buildCannedSearchQuery()})); if (!queryJSON) { diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index d26ea2b73f97..9992230127b9 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -1,4 +1,4 @@ -import {useRoute} from '@react-navigation/native'; +import {useNavigationState, useRoute} from '@react-navigation/native'; import React, {useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react'; import type {GestureResponderEvent, ScrollView as RNScrollView, ScrollViewProps, StyleProp, ViewStyle} from 'react-native'; import {NativeModules, View} from 'react-native'; @@ -7,6 +7,7 @@ import type {ValueOf} from 'type-fest'; // eslint-disable-next-line no-restricted-imports import AccountSwitcher from '@components/AccountSwitcher'; import AccountSwitcherSkeletonView from '@components/AccountSwitcherSkeletonView'; +// eslint-disable-next-line no-restricted-imports import ConfirmModal from '@components/ConfirmModal'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -20,7 +21,6 @@ import Text from '@components/Text'; import Tooltip from '@components/Tooltip'; import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; -import useActiveCentralPaneRoute from '@hooks/useActiveCentralPaneRoute'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useSingleExecution from '@hooks/useSingleExecution'; @@ -30,6 +30,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; +import getTopmostRouteName from '@libs/Navigation/getTopmostRouteName'; import Navigation from '@libs/Navigation/Navigation'; import * as SubscriptionUtils from '@libs/SubscriptionUtils'; import * as UserUtils from '@libs/UserUtils'; @@ -89,7 +90,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr const waitForNavigate = useWaitForNavigation(); const popoverAnchor = useRef(null); const {translate} = useLocalize(); - const activeCentralPaneRoute = useActiveCentralPaneRoute(); + const activeRoute = useNavigationState(getTopmostRouteName); const emojiCode = currentUserPersonalDetails?.status?.emojiCode ?? ''; const [allConnectionSyncProgresses] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}`); const {setInitialURL} = useContext(InitialURLContext); @@ -324,11 +325,8 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr ref={popoverAnchor} shouldBlockSelection={!!item.link} onSecondaryInteraction={item.link ? (event) => openPopover(item.link, event) : undefined} - focused={ - !!activeCentralPaneRoute && - !!item.routeName && - !!(activeCentralPaneRoute.name.toLowerCase().replaceAll('_', '') === item.routeName.toLowerCase().replaceAll('/', '')) - } + focused={!!activeRoute && !!item.routeName && !!(activeRoute.toLowerCase().replaceAll('_', '') === item.routeName.toLowerCase().replaceAll('/', ''))} + isPaneMenu iconRight={item.iconRight} shouldShowRightIcon={item.shouldShowRightIcon} /> @@ -337,7 +335,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr ); }, - [styles.pb4, styles.mh3, styles.sectionTitle, styles.sectionMenuItem, translate, userWallet?.currentBalance, isExecuting, singleExecution, activeCentralPaneRoute, waitForNavigate], + [styles.pb4, styles.mh3, styles.sectionTitle, styles.sectionMenuItem, translate, userWallet?.currentBalance, isExecuting, singleExecution, activeRoute, waitForNavigate], ); const accountMenuItems = useMemo(() => getMenuItemsSection(accountMenuItemsData), [accountMenuItemsData, getMenuItemsSection]); From 4be604a1b7c797331262bcc61272e9ec16f78f3b Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Sat, 7 Sep 2024 11:29:20 +0200 Subject: [PATCH 016/257] Refactor useActiveWorkspace --- src/App.tsx | 4 -- .../ActiveWorkspaceContext.tsx | 8 +--- .../ActiveWorkspaceProvider/index.tsx | 25 ++++++----- .../ActiveWorkspaceProvider/index.website.tsx | 29 ------------ src/components/Search/SearchPageHeader.tsx | 2 +- src/hooks/useActiveWorkspace.ts | 3 +- .../useActiveWorkspaceFromNavigationState.ts | 31 ------------- src/hooks/useReportIDs.tsx | 2 +- .../Navigation/AppNavigator/AuthScreens.tsx | 14 ++---- .../Navigators/ReportsSplitNavigator.tsx | 2 +- .../BottomTabBar.tsx | 4 +- .../CustomRouter.ts | 29 +++++++++--- src/libs/Navigation/NavigationRoot.tsx | 6 --- src/libs/Navigation/getPolicyIDFromState.ts | 20 ++++----- .../linkingConfig/createSplitNavigator.ts | 44 +++++++++++++++++++ .../linkingConfig/customGetPathFromState.ts | 17 ++++--- .../linkingConfig/getAdaptedStateFromPath.ts | 3 +- src/libs/Navigation/linkingConfig/index.ts | 2 +- src/libs/Navigation/types.ts | 2 +- src/pages/Search/SearchPage.tsx | 5 ++- src/pages/Search/SearchPageBottomTab.tsx | 3 ++ src/pages/WorkspaceSwitcherPage/index.tsx | 5 +-- src/pages/home/ReportScreen.tsx | 3 +- src/pages/home/sidebar/SidebarLinksData.tsx | 6 +-- .../SidebarScreen/BaseSidebarScreen.tsx | 4 +- src/pages/workspace/WorkspaceNewRoomPage.tsx | 2 +- src/pages/workspace/WorkspaceProfilePage.tsx | 5 +-- src/pages/workspace/WorkspacesListPage.tsx | 3 +- 28 files changed, 132 insertions(+), 151 deletions(-) delete mode 100644 src/components/ActiveWorkspaceProvider/index.website.tsx delete mode 100644 src/hooks/useActiveWorkspaceFromNavigationState.ts create mode 100644 src/libs/Navigation/linkingConfig/createSplitNavigator.ts diff --git a/src/App.tsx b/src/App.tsx index 177cc00c7dee..0b42805160d0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,7 +7,6 @@ import {PickerStateProvider} from 'react-native-picker-select'; import {SafeAreaProvider} from 'react-native-safe-area-context'; import '../wdyr'; import ActiveElementRoleProvider from './components/ActiveElementRoleProvider'; -import ActiveWorkspaceContextProvider from './components/ActiveWorkspaceProvider'; import ColorSchemeWrapper from './components/ColorSchemeWrapper'; import ComposeProviders from './components/ComposeProviders'; import CustomStatusBarAndBackground from './components/CustomStatusBarAndBackground'; @@ -34,7 +33,6 @@ import {KeyboardStateProvider} from './components/withKeyboardState'; import CONFIG from './CONFIG'; import Expensify from './Expensify'; import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop'; -import {ReportIDsContextProvider} from './hooks/useReportIDs'; import OnyxUpdateManager from './libs/actions/OnyxUpdateManager'; import {ReportAttachmentsProvider} from './pages/home/report/ReportAttachmentsContext'; import type {Route} from './ROUTES'; @@ -85,8 +83,6 @@ function App({url}: AppProps) { EnvironmentProvider, CustomStatusBarAndBackgroundContextProvider, ActiveElementRoleProvider, - ActiveWorkspaceContextProvider, - ReportIDsContextProvider, PlaybackContextProvider, FullScreenContextProvider, VolumeContextProvider, diff --git a/src/components/ActiveWorkspace/ActiveWorkspaceContext.tsx b/src/components/ActiveWorkspace/ActiveWorkspaceContext.tsx index 466f0f492c8e..7908020d16d2 100644 --- a/src/components/ActiveWorkspace/ActiveWorkspaceContext.tsx +++ b/src/components/ActiveWorkspace/ActiveWorkspaceContext.tsx @@ -1,11 +1,5 @@ import {createContext} from 'react'; -type ActiveWorkspaceContextType = { - activeWorkspaceID?: string; - setActiveWorkspaceID: (activeWorkspaceID?: string) => void; -}; - -const ActiveWorkspaceContext = createContext({activeWorkspaceID: undefined, setActiveWorkspaceID: () => undefined}); +const ActiveWorkspaceContext = createContext(undefined); export default ActiveWorkspaceContext; -export {type ActiveWorkspaceContextType}; diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index bc7260cdf10b..19cadaca6318 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -1,19 +1,24 @@ -import React, {useMemo, useState} from 'react'; +import {useNavigationState} from '@react-navigation/native'; +import React from 'react'; import ActiveWorkspaceContext from '@components/ActiveWorkspace/ActiveWorkspaceContext'; +import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; function ActiveWorkspaceContextProvider({children}: ChildrenProps) { - const [activeWorkspaceID, setActiveWorkspaceID] = useState(undefined); + const activeWorkspaceID = useNavigationState(getPolicyIDFromState); - const value = useMemo( - () => ({ - activeWorkspaceID, - setActiveWorkspaceID, - }), - [activeWorkspaceID, setActiveWorkspaceID], - ); + // @TODO Remember to handle saving activeWorkspaceID in the session storage - return {children}; + // const setActiveWorkspaceID = useCallback((workspaceID: string | undefined) => { + // updateActiveWorkspaceID(workspaceID); + // if (workspaceID && sessionStorage) { + // sessionStorage?.setItem(CONST.SESSION_STORAGE_KEYS.ACTIVE_WORKSPACE_ID, workspaceID); + // } else { + // sessionStorage?.removeItem(CONST.SESSION_STORAGE_KEYS.ACTIVE_WORKSPACE_ID); + // } + // }, []); + + return {children}; } export default ActiveWorkspaceContextProvider; diff --git a/src/components/ActiveWorkspaceProvider/index.website.tsx b/src/components/ActiveWorkspaceProvider/index.website.tsx deleted file mode 100644 index 82e46d70f896..000000000000 --- a/src/components/ActiveWorkspaceProvider/index.website.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React, {useCallback, useMemo, useState} from 'react'; -import ActiveWorkspaceContext from '@components/ActiveWorkspace/ActiveWorkspaceContext'; -import CONST from '@src/CONST'; -import type ChildrenProps from '@src/types/utils/ChildrenProps'; - -function ActiveWorkspaceContextProvider({children}: ChildrenProps) { - const [activeWorkspaceID, updateActiveWorkspaceID] = useState(undefined); - - const setActiveWorkspaceID = useCallback((workspaceID: string | undefined) => { - updateActiveWorkspaceID(workspaceID); - if (workspaceID && sessionStorage) { - sessionStorage?.setItem(CONST.SESSION_STORAGE_KEYS.ACTIVE_WORKSPACE_ID, workspaceID); - } else { - sessionStorage?.removeItem(CONST.SESSION_STORAGE_KEYS.ACTIVE_WORKSPACE_ID); - } - }, []); - - const value = useMemo( - () => ({ - activeWorkspaceID, - setActiveWorkspaceID, - }), - [activeWorkspaceID, setActiveWorkspaceID], - ); - - return {children}; -} - -export default ActiveWorkspaceContextProvider; diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index f50540346e6d..d2595f052db3 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -116,7 +116,7 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { const theme = useTheme(); const styles = useThemeStyles(); const {isOffline} = useNetwork(); - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout(); const {selectedTransactions, clearSelectedTransactions, selectedReports} = useSearchContext(); const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE); diff --git a/src/hooks/useActiveWorkspace.ts b/src/hooks/useActiveWorkspace.ts index cce3c2a4b31f..11a986cdb053 100644 --- a/src/hooks/useActiveWorkspace.ts +++ b/src/hooks/useActiveWorkspace.ts @@ -1,8 +1,7 @@ import {useContext} from 'react'; import ActiveWorkspaceContext from '@components/ActiveWorkspace/ActiveWorkspaceContext'; -import type {ActiveWorkspaceContextType} from '@components/ActiveWorkspace/ActiveWorkspaceContext'; -function useActiveWorkspace(): ActiveWorkspaceContextType { +function useActiveWorkspace(): string { return useContext(ActiveWorkspaceContext); } diff --git a/src/hooks/useActiveWorkspaceFromNavigationState.ts b/src/hooks/useActiveWorkspaceFromNavigationState.ts deleted file mode 100644 index d2851e83ab6c..000000000000 --- a/src/hooks/useActiveWorkspaceFromNavigationState.ts +++ /dev/null @@ -1,31 +0,0 @@ -import {useNavigationState} from '@react-navigation/native'; -import Log from '@libs/Log'; -import type {BottomTabNavigatorParamList} from '@libs/Navigation/types'; -import SCREENS from '@src/SCREENS'; - -/** - * Get the currently selected policy ID stored in the navigation state. This hook should only be called only from screens in BottomTab. - * Differences between this hook and useActiveWorkspace: - * - useActiveWorkspaceFromNavigationState reads the active workspace id directly from the navigation state, it's a bit slower than useActiveWorkspace and it can be called only from BottomTabScreens. - * It allows to read a value of policyID immediately after the update. - * - useActiveWorkspace allows to read the current policyID anywhere, it's faster because it doesn't require searching in the navigation state. - */ -function useActiveWorkspaceFromNavigationState() { - // The last policyID value is always stored in the last route in BottomTabNavigator. - const activeWorkspaceID = useNavigationState((state) => { - // SCREENS.HOME is a screen located in the BottomTabNavigator, if it's not in state.routeNames it means that this hook was called from a screen in another navigator. - if (!state.routeNames.includes(SCREENS.HOME)) { - Log.warn('useActiveWorkspaceFromNavigationState should be called only from BottomTab screens'); - } - - const params = state.routes.at(-1)?.params ?? {}; - - if ('policyID' in params) { - return params?.policyID; - } - }); - - return activeWorkspaceID; -} - -export default useActiveWorkspaceFromNavigationState; diff --git a/src/hooks/useReportIDs.tsx b/src/hooks/useReportIDs.tsx index b7d84cb25196..d51d9e53c48c 100644 --- a/src/hooks/useReportIDs.tsx +++ b/src/hooks/useReportIDs.tsx @@ -91,7 +91,7 @@ function ReportIDsContextProvider({ const {accountID} = useCurrentUserPersonalDetails(); const currentReportIDValue = useCurrentReportID(); const derivedCurrentReportID = currentReportIDForTests ?? currentReportIDValue?.currentReportID; - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); const policyMemberAccountIDs = useMemo(() => getPolicyEmployeeListByIdWithoutCurrentUser(policies, activeWorkspaceID, accountID), [policies, activeWorkspaceID, accountID]); diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index b2d4b10e98e8..f0bb089be026 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -4,6 +4,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import Onyx, {withOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import ActiveGuidesEventListener from '@components/ActiveGuidesEventListener'; +import ActiveWorkspaceContextProvider from '@components/ActiveWorkspaceProvider'; import ComposeProviders from '@components/ComposeProviders'; import OptionsListContextProvider from '@components/OptionListContextProvider'; import {SearchContextProvider} from '@components/Search/SearchContext'; @@ -11,6 +12,7 @@ import SearchRouterModal from '@components/Search/SearchRouter/SearchRouterModal import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useOnboardingFlowRouter from '@hooks/useOnboardingFlow'; import usePermissions from '@hooks/usePermissions'; +import {ReportIDsContextProvider} from '@hooks/useReportIDs'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -234,7 +236,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie const {shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout(); const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); const {canUseDefaultRooms} = usePermissions(); - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(onboardingIsMediumOrLargerScreenWidth), [screenOptions, onboardingIsMediumOrLargerScreenWidth]); const onboardingScreenOptions = useMemo( () => getOnboardingModalScreenOptions(shouldUseNarrowLayout, styles, StyleUtils, onboardingIsMediumOrLargerScreenWidth), @@ -415,16 +417,8 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); - const CentralPaneScreenOptions = { - headerShown: false, - title: 'New Expensify', - - // Prevent unnecessary scrolling - cardStyle: styles.cardStyleNavigator, - }; - return ( - + (getChatTabBrickRoad(activeWorkspaceID)); @@ -147,7 +147,7 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 1f52c6e1e4a3..a9566869d9b8 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -2,9 +2,11 @@ import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigatio import {findFocusedRoute, getPathFromState, StackRouter} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/routers'; import * as Localize from '@libs/Localize'; +import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; import isSideModalNavigator from '@libs/Navigation/isSideModalNavigator'; import linkingConfig from '@libs/Navigation/linkingConfig'; -import {RootStackParamList} from '@libs/Navigation/types'; +import createSplitNavigator from '@libs/Navigation/linkingConfig/createSplitNavigator'; +import type {RootStackParamList} from '@libs/Navigation/types'; import {isOnboardingFlowName} from '@libs/NavigationUtils'; import * as SearchUtils from '@libs/SearchUtils'; import * as Welcome from '@userActions/Welcome'; @@ -101,18 +103,19 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { if (action.payload.policyID) { queryJSON.policyID = action.payload.policyID; - newParams = {...currentParams, q: SearchUtils.buildSearchQueryString(queryJSON)}; } else { delete queryJSON.policyID; - newParams = {...currentParams, q: SearchUtils.buildSearchQueryString(queryJSON)}; } - const newRoutes = [...state.routes, {...lastRoute, params: newParams}]; + newParams = {...currentParams, q: SearchUtils.buildSearchQueryString(queryJSON)}; + const newRoutes = [...state.routes, {...lastRoute, key: lastRoute.key + 'key', params: newParams}]; return {...state, routes: newRoutes, index: newRoutes.length - 1}; } if (lastRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { // TODO: handle change policy id of reports navigator. - return; + const newRoute = createSplitNavigator('Home', {name: SCREENS.REPORT, params: {reportID: ''}}, action.payload.policyID, lastRoute.key + 'key'); + const newRoutes = [...state.routes, newRoute]; + return {...state, routes: newRoutes, index: newRoutes.length - 1}; } // In other cases, do nothing. return null; @@ -123,6 +126,22 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { return state; } + if (action.type === 'PUSH' && action.payload.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { + const policyID = getPolicyIDFromState(state); + const currentParams = {...action.payload.params}; + action.payload.params = {...currentParams, policyID}; + } + + if (action.type === 'PUSH' && action.payload.name === SCREENS.SEARCH.CENTRAL_PANE) { + const policyID = getPolicyIDFromState(state); + const params = policyID ? {policyID} : {}; + action.payload.params = {q: SearchUtils.buildSearchQueryString(params), isCustomQuery: false}; + } + + if (action.type === 'RESET') { + const policyID = getPolicyIDFromState(action.payload); + } + // TODO: I don't remember if the code below makes sense Wojtek :D but it's possible. // One part seems redundant to the lines 102-108 above // diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index bb005fc6b763..124e0ed541d6 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -4,7 +4,6 @@ import React, {useContext, useEffect, useMemo, useRef} from 'react'; import {NativeModules} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import {ScrollOffsetContext} from '@components/ScrollOffsetContextProvider'; -import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useCurrentReportID from '@hooks/useCurrentReportID'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; @@ -21,13 +20,11 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import AppNavigator from './AppNavigator'; -import getPolicyIDFromState from './getPolicyIDFromState'; import linkingConfig from './linkingConfig'; import customGetPathFromState from './linkingConfig/customGetPathFromState'; import getAdaptedStateFromPath from './linkingConfig/getAdaptedStateFromPath'; import Navigation, {navigationRef} from './Navigation'; import setupCustomAndroidBackHandler from './setupCustomAndroidBackHandler'; -import type {RootStackParamList} from './types'; type NavigationRootProps = { /** Whether the current user is logged in with an authToken */ @@ -88,7 +85,6 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh const currentReportIDValue = useCurrentReportID(); const {shouldUseNarrowLayout} = useResponsiveLayout(); - const {setActiveWorkspaceID} = useActiveWorkspace(); const [user] = useOnyx(ONYXKEYS.USER); const [isOnboardingCompleted = true] = useOnyx(ONYXKEYS.NVP_ONBOARDING, { @@ -161,11 +157,9 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh const currentRoute = navigationRef.getCurrentRoute(); Firebase.log(`[NAVIGATION] screen: ${currentRoute?.name}, params: ${JSON.stringify(currentRoute?.params ?? {})}`); - const activeWorkspaceID = getPolicyIDFromState(state as NavigationState); // Performance optimization to avoid context consumers to delay first render setTimeout(() => { currentReportIDValue?.updateCurrentReportID(state); - setActiveWorkspaceID(activeWorkspaceID); }, 0); parseAndLogRoute(state); diff --git a/src/libs/Navigation/getPolicyIDFromState.ts b/src/libs/Navigation/getPolicyIDFromState.ts index 702fb654780d..8077c5eea998 100644 --- a/src/libs/Navigation/getPolicyIDFromState.ts +++ b/src/libs/Navigation/getPolicyIDFromState.ts @@ -1,8 +1,7 @@ +import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import extractPolicyIDFromQuery from './extractPolicyIDFromQuery'; -import getTopmostBottomTabRoute from './getTopmostBottomTabRoute'; -import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute'; -import type {RootStackParamList, State} from './types'; +import type {NavigationPartialRoute, RootStackParamList, State} from './types'; /** * returns policyID value if one exists in navigation state @@ -12,19 +11,16 @@ import type {RootStackParamList, State} from './types'; * - on Search related screens as policyID filter inside `q` (SearchQuery) param (only for SEARCH_CENTRAL_PANE) */ const getPolicyIDFromState = (state: State): string | undefined => { - const topmostBottomTabRoute = getTopmostBottomTabRoute(state); - - if (!topmostBottomTabRoute) { - return; + const lastPolicyRoute = state.routes.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.CENTRAL_PANE); + if (lastPolicyRoute?.params && 'policyID' in lastPolicyRoute.params) { + return lastPolicyRoute?.params?.policyID; } - if (topmostBottomTabRoute.name === SCREENS.SEARCH.BOTTOM_TAB) { - const topmostCentralPaneRoute = getTopmostCentralPaneRoute(state); - return extractPolicyIDFromQuery(topmostCentralPaneRoute); + if (lastPolicyRoute) { + return extractPolicyIDFromQuery(lastPolicyRoute as NavigationPartialRoute); } - const policyID = topmostBottomTabRoute && topmostBottomTabRoute.params && 'policyID' in topmostBottomTabRoute.params && topmostBottomTabRoute.params?.policyID; - return policyID ? (topmostBottomTabRoute.params?.policyID as string) : undefined; + return undefined; }; export default getPolicyIDFromState; diff --git a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts b/src/libs/Navigation/linkingConfig/createSplitNavigator.ts new file mode 100644 index 000000000000..7ee473560955 --- /dev/null +++ b/src/libs/Navigation/linkingConfig/createSplitNavigator.ts @@ -0,0 +1,44 @@ +import type {NavigationState, PartialState} from '@react-navigation/native'; +import type {NavigationPartialRoute, SplitNavigatorScreenName} from '@libs/Navigation/types'; +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; + +const mapLhnToSplitNavigatorName = { + [SCREENS.SETTINGS.ROOT]: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, + [SCREENS.HOME]: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, + [SCREENS.WORKSPACE.INITIAL]: NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, +}; + +type SplitNavigatorLHNScreen = keyof typeof mapLhnToSplitNavigatorName; +type SplitNavigator = (typeof mapLhnToSplitNavigatorName)[SplitNavigatorLHNScreen]; + +// The function getPathFromState that we are using in some places isn't working correctly without defined index. +const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState => ({routes, index: routes.length - 1}); + +function createSplitNavigator( + splitNavigatorLHNScreen: SplitNavigatorLHNScreen, + route?: NavigationPartialRoute, + policyID?: string, + key?: string, +): NavigationPartialRoute { + const routes = []; + + const params = policyID ? {policyID} : {}; + + // Both routes in WorkspaceNavigator should store a policyID in params, so here this param is also passed to the screen displayed in LHN in WorkspaceNavigator + routes.push({ + name: splitNavigatorLHNScreen, + }); + + if (route) { + routes.push(route); + } + return { + key, + name: mapLhnToSplitNavigatorName[splitNavigatorLHNScreen], + state: getRoutesWithIndex(routes), + params, + }; +} + +export default createSplitNavigator; diff --git a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts index a9c9b6f23b19..199e6656dabd 100644 --- a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts +++ b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts @@ -1,20 +1,19 @@ import {getPathFromState} from '@react-navigation/native'; -import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; -import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; -import type {BottomTabName, RootStackParamList, State} from '@libs/Navigation/types'; +import type {RootStackParamList, State} from '@libs/Navigation/types'; import {removePolicyIDParamFromState} from '@libs/NavigationUtils'; -import SCREENS from '@src/SCREENS'; +import NAVIGATORS from '@src/NAVIGATORS'; -// The policy ID parameter should be included in the URL when any of these pages is opened in the bottom tab. -const SCREENS_WITH_POLICY_ID_IN_URL: BottomTabName[] = [SCREENS.HOME] as const; +function getTopmostSplitNavigator(state: State | undefined) { + return state?.routes.findLast((route) => route.name.endsWith('SplitNavigator')); +} const customGetPathFromState: typeof getPathFromState = (state, options) => { // For the Home and Settings pages we should remove policyID from the params, because on small screens it's displayed twice in the URL const stateWithoutPolicyID = removePolicyIDParamFromState(state as State); const path = getPathFromState(stateWithoutPolicyID, options); - const policyIDFromState = getPolicyIDFromState(state as State); - const topmostBottomTabRouteName = getTopmostBottomTabRoute(state as State)?.name; - const shouldAddPolicyID = !!topmostBottomTabRouteName && SCREENS_WITH_POLICY_ID_IN_URL.includes(topmostBottomTabRouteName); + const topmostSplitNavigator = getTopmostSplitNavigator(state as State); + const policyIDFromState = topmostSplitNavigator?.params?.policyID; + const shouldAddPolicyID = !!topmostSplitNavigator && topmostSplitNavigator?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; return `${policyIDFromState && shouldAddPolicyID ? `/w/${policyIDFromState}` : ''}${path}`; }; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 435bc138b829..0bd68671e21e 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -139,7 +139,7 @@ function createSplitNavigator(splitNavigatorLHNScreen: SplitNavigatorLHNScreen, } // This function will return CentralPaneNavigator route or WorkspaceNavigator route. -function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): NavigationPartialRoute | undefined { +function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): NavigationPartialRoute | undefined { // Check for backTo param. One screen with different backTo value may need diferent screens visible under the overlay. if (route.params && 'backTo' in route.params && typeof route.params.backTo === 'string') { const stateForBackTo = getStateFromPath(route.params.backTo, config); @@ -371,6 +371,7 @@ const getAdaptedStateFromPath: GetAdaptedStateFromPath = (path, options, shouldR if (shouldReplacePathInNestedState) { replacePathInNestedState(state, path); } + if (state === undefined) { throw new Error('Unable to parse path'); } diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index 7bb5e8ae5b5a..1f556aa67809 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -15,7 +15,7 @@ const linkingConfig: LinkingOptions = { return adaptedState; }, subscribe, - // getPathFromState: customGetPathFromState, + getPathFromState: customGetPathFromState, prefixes, config, }; diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 571f57896d79..06b37ed61539 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1484,7 +1484,7 @@ type AuthScreensParamList = CentralPaneScreensParamList & }; [SCREENS.NOT_FOUND]: undefined; [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: NavigatorScreenParams & {policyID?: string}; - [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: NavigatorScreenParams; + [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: NavigatorScreenParams & {policyID?: string}; [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: NavigatorScreenParams; [NAVIGATORS.LEFT_MODAL_NAVIGATOR]: NavigatorScreenParams; [NAVIGATORS.RIGHT_MODAL_NAVIGATOR]: NavigatorScreenParams; diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 3091d422e3e1..57fbbcd80d57 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -77,7 +77,10 @@ function SearchPage({route}: SearchPageProps) { breadcrumbLabel={translate('common.search')} shouldDisplaySearch={false} /> - + ) : ( )} + ); } diff --git a/src/pages/WorkspaceSwitcherPage/index.tsx b/src/pages/WorkspaceSwitcherPage/index.tsx index ea9e00ba607a..83bb71ef15e2 100644 --- a/src/pages/WorkspaceSwitcherPage/index.tsx +++ b/src/pages/WorkspaceSwitcherPage/index.tsx @@ -41,7 +41,7 @@ function WorkspaceSwitcherPage() { const {isOffline} = useNetwork(); const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); const {translate} = useLocalize(); - const {activeWorkspaceID, setActiveWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS); @@ -90,14 +90,13 @@ function WorkspaceSwitcherPage() { const {policyID} = option; - // setActiveWorkspaceID(policyID); Navigation.goBack(); if (policyID !== activeWorkspaceID) { // Navigation.navigateWithSwitchPolicyID({policyID}); navigationRef.dispatch({type: 'SWITCH_POLICY_ID', payload: {policyID}}); } }, - [activeWorkspaceID, setActiveWorkspaceID], + [activeWorkspaceID], ); const usersWorkspaces = useMemo(() => { diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index dd38a0716377..00a672083214 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -109,8 +109,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro const reactionListRef = useRef(null); const {isOffline} = useNetwork(); const {shouldUseNarrowLayout, isInNarrowPaneModal} = useResponsiveLayout(); - const {activeWorkspaceID} = useActiveWorkspace(); - + const activeWorkspaceID = useActiveWorkspace(); const [modal] = useOnyx(ONYXKEYS.MODAL); const [isComposerFullSize] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_IS_COMPOSER_FULL_SIZE}${reportIDFromRoute}`, {initialValue: false}); const [accountManagerReportID] = useOnyx(ONYXKEYS.ACCOUNT_MANAGER_REPORT_ID, {initialValue: ''}); diff --git a/src/pages/home/sidebar/SidebarLinksData.tsx b/src/pages/home/sidebar/SidebarLinksData.tsx index e5a74db796d8..d83b4758ce52 100644 --- a/src/pages/home/sidebar/SidebarLinksData.tsx +++ b/src/pages/home/sidebar/SidebarLinksData.tsx @@ -6,7 +6,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import type {EdgeInsets} from 'react-native-safe-area-context'; import type {ValueOf} from 'type-fest'; -import useActiveWorkspaceFromNavigationState from '@hooks/useActiveWorkspaceFromNavigationState'; +import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; import {useReportIDs} from '@hooks/useReportIDs'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -34,7 +34,7 @@ type SidebarLinksDataProps = SidebarLinksDataOnyxProps & { function SidebarLinksData({insets, isLoadingApp = true, onLinkClick, priorityMode = CONST.PRIORITY_MODE.DEFAULT}: SidebarLinksDataProps) { const isFocused = useIsFocused(); const styles = useThemeStyles(); - const activeWorkspaceID = useActiveWorkspaceFromNavigationState(); + const activeWorkspaceID = useActiveWorkspace(); const {translate} = useLocalize(); const {orderedReportIDs, currentReportID, policyMemberAccountIDs} = useReportIDs(); @@ -52,7 +52,6 @@ function SidebarLinksData({insets, isLoadingApp = true, onLinkClick, priorityMod const currentReportIDRef = useRef(currentReportID); currentReportIDRef.current = currentReportID; const isActiveReport = useCallback((reportID: string): boolean => currentReportIDRef.current === reportID, []); - return ( diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx index b82865dd13c7..71a8587fb889 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx @@ -2,7 +2,7 @@ import React, {useEffect} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import ScreenWrapper from '@components/ScreenWrapper'; -import useActiveWorkspaceFromNavigationState from '@hooks/useActiveWorkspaceFromNavigationState'; +import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {updateLastAccessedWorkspace} from '@libs/actions/Policy/Policy'; @@ -27,7 +27,7 @@ const startTimer = () => { function BaseSidebarScreen() { const styles = useThemeStyles(); - const activeWorkspaceID = useActiveWorkspaceFromNavigationState(); + const activeWorkspaceID = useActiveWorkspace(); const {translate} = useLocalize(); const [activeWorkspace] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activeWorkspaceID ?? -1}`); diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 481fc6c41402..28a1e9ad4a7a 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -55,7 +55,7 @@ function WorkspaceNewRoomPage() { const wasLoading = usePrevious(!!formState?.isLoading); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); const {isLoading = false, errorFields = {}} = formState ?? {}; - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); const activeWorkspaceOrDefaultID = activeWorkspaceID ?? activePolicyID; diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index e99afe7ba408..9fce5cd9dff7 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -52,7 +52,7 @@ function WorkspaceProfilePage({policyDraft, policy: policyProp, currencyList = { const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const illustrations = useThemeIllustrations(); - const {activeWorkspaceID, setActiveWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = route.params.policyID; const {canUseSpotnanaTravel} = usePermissions(); const [currentUserAccountID = -1] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.accountID}); @@ -136,10 +136,9 @@ function WorkspaceProfilePage({policyDraft, policy: policyProp, currencyList = { // If the workspace being deleted is the active workspace, switch to the "All Workspaces" view if (activeWorkspaceID === policy?.id) { - setActiveWorkspaceID(undefined); Navigation.navigateWithSwitchPolicyID({policyID: undefined}); } - }, [policy?.id, policyName, activeWorkspaceID, setActiveWorkspaceID]); + }, [policy?.id, policyName, activeWorkspaceID]); return ( (); @@ -132,7 +132,6 @@ function WorkspacesListPage() { // If the workspace being deleted is the active workspace, switch to the "All Workspaces" view if (activeWorkspaceID === policyIDToDelete) { - setActiveWorkspaceID(undefined); Navigation.navigateWithSwitchPolicyID({policyID: undefined}); } }; From 6d36f7b8b34c1b6b61ca1e59f42b6123803aa801 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 11 Sep 2024 11:53:37 +0200 Subject: [PATCH 017/257] Add createSplitNavigator --- .../ActiveWorkspaceProvider/index.tsx | 31 +++- .../Navigation/AppNavigator/AuthScreens.tsx | 2 + .../CustomRouter.ts | 40 +++-- .../AppNavigator/getActionsFromPartialDiff.ts | 2 +- .../AppNavigator/getPartialStateDiff.ts | 6 +- src/libs/Navigation/Navigation.ts | 28 +++- src/libs/Navigation/dismissModal.ts | 2 +- src/libs/Navigation/dismissModalWithReport.ts | 2 +- src/libs/Navigation/getPolicyIDFromState.ts | 2 +- .../Navigation/getTopmostWorkspaceRoute.ts | 2 +- src/libs/Navigation/linkTo/index.ts | 6 +- .../CENTRAL_PANE_TO_RHP_MAPPING.ts | 21 --- .../LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts | 10 ++ .../linkingConfig/SEARCH_RHP_SCREENS.ts | 25 +++ .../TAB_TO_CENTRAL_PANE_MAPPING.ts | 4 +- .../linkingConfig/createSplitNavigator.ts | 38 ++--- .../linkingConfig/getAdaptedStateFromPath.ts | 157 +++++------------- .../getMatchingBottomTabRouteForState.ts | 2 +- src/libs/Navigation/newLinkTo/index.ts | 6 +- src/libs/Navigation/types.ts | 16 +- 20 files changed, 200 insertions(+), 202 deletions(-) create mode 100644 src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts create mode 100644 src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index 19cadaca6318..011b58720d35 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -1,14 +1,37 @@ import {useNavigationState} from '@react-navigation/native'; -import React from 'react'; +import React, {useMemo} from 'react'; import ActiveWorkspaceContext from '@components/ActiveWorkspace/ActiveWorkspaceContext'; -import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; +import * as SearchUtils from '@libs/SearchUtils'; +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; function ActiveWorkspaceContextProvider({children}: ChildrenProps) { - const activeWorkspaceID = useNavigationState(getPolicyIDFromState); + const lastPolicyRoute = useNavigationState((state) => + state?.routes?.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.CENTRAL_PANE), + ); - // @TODO Remember to handle saving activeWorkspaceID in the session storage + const policyIDFromRouteParam = lastPolicyRoute?.params && 'policyID' in lastPolicyRoute.params ? (lastPolicyRoute?.params?.policyID as string) : ''; + const queryFromRouteParam = lastPolicyRoute?.params && 'q' in lastPolicyRoute.params ? (lastPolicyRoute.params.q as string) : ''; + + const activeWorkspaceID = useMemo(() => { + if (policyIDFromRouteParam) { + return policyIDFromRouteParam; + } + + if (queryFromRouteParam) { + const queryJSON = SearchUtils.buildSearchQueryJSON(queryFromRouteParam); + if (!queryJSON) { + return undefined; + } + return SearchUtils.getPolicyIDFromSearchQuery(queryJSON); + } + + return undefined; + }, [policyIDFromRouteParam, queryFromRouteParam]); + + // @TODO Remember to handle saving activeWorkspaceID in the session storage // const setActiveWorkspaceID = useCallback((workspaceID: string | undefined) => { // updateActiveWorkspaceID(workspaceID); // if (workspaceID && sessionStorage) { diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index f0bb089be026..bf008e8c131e 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -99,6 +99,7 @@ function shouldOpenOnAdminRoom() { } // @TODO: Add these params to SearchPage and ReportScreen +// eslint-disable-next-line @typescript-eslint/no-unused-vars function getCentralPaneScreenInitialParams(screenName: CentralPaneName, initialReportID?: string): Partial> { if (screenName === SCREENS.SEARCH.CENTRAL_PANE) { // Generate default query string with buildSearchQueryString without argument. @@ -439,6 +440,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie name={SCREENS.SEARCH.CENTRAL_PANE} options={screenOptions.fullScreen} component={SearchPage} + initialParams={{q: buildSearchQueryString()}} /> ); const currentParams = {...action.payload.params}; action.payload.params = {...currentParams, policyID}; } if (action.type === 'PUSH' && action.payload.name === SCREENS.SEARCH.CENTRAL_PANE) { - const policyID = getPolicyIDFromState(state); - const params = policyID ? {policyID} : {}; - action.payload.params = {q: SearchUtils.buildSearchQueryString(params), isCustomQuery: false}; - } + const policyID = getPolicyIDFromState(state as State); + const currentParams = action.payload.params as RootStackParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; + const queryJSON = SearchUtils.buildSearchQueryJSON(currentParams.q); + if (!queryJSON) { + return; + } + if (policyID) { + queryJSON.policyID = policyID; + } else { + delete queryJSON.policyID; + } - if (action.type === 'RESET') { - const policyID = getPolicyIDFromState(action.payload); + action.payload.params = {q: SearchUtils.buildSearchQueryString(queryJSON), isCustomQuery: false}; } // TODO: I don't remember if the code below makes sense Wojtek :D but it's possible. diff --git a/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts b/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts index d66eb313cbb1..1cbb5ec3d718 100644 --- a/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts +++ b/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts @@ -13,7 +13,7 @@ function getActionsFromPartialDiff(diff: GetPartialStateDiffReturnType): Navigat const bottomTabDiff = diff[NAVIGATORS.BOTTOM_TAB_NAVIGATOR]; const centralPaneDiff = diff[NAVIGATORS.CENTRAL_PANE_NAVIGATOR]; - const fullScreenDiff = diff[NAVIGATORS.WORKSPACE_NAVIGATOR]; + const fullScreenDiff = diff[NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]; // There is only one bottom tab navigator so we can just push this route. if (bottomTabDiff) { diff --git a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts index 974f98dccccb..79def4ee9218 100644 --- a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts +++ b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts @@ -9,7 +9,7 @@ import NAVIGATORS from '@src/NAVIGATORS'; type GetPartialStateDiffReturnType = { [NAVIGATORS.BOTTOM_TAB_NAVIGATOR]?: NavigationPartialRoute; [NAVIGATORS.CENTRAL_PANE_NAVIGATOR]?: NavigationPartialRoute; - [NAVIGATORS.WORKSPACE_NAVIGATOR]?: NavigationPartialRoute; + [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]?: NavigationPartialRoute; }; /** @@ -65,7 +65,7 @@ function getPartialStateDiff(state: State, templateState: St if (metainfo.isWorkspaceNavigatorMandatory) { const stateTopmostWorkspaceRoute = getTopmostWorkspaceRoute(state); const templateStateTopmostWorkspaceRoute = getTopmostWorkspaceRoute(templateState); - const workspaceNavDiff = templateState.routes.filter((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR).at(-1) as NavigationPartialRoute; + const workspaceNavDiff = templateState.routes.filter((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR).at(-1) as NavigationPartialRoute; if ( // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing @@ -78,7 +78,7 @@ function getPartialStateDiff(state: State, templateState: St templateStateTopmostWorkspaceRoute.params as Record | undefined, ))) ) { - diff[NAVIGATORS.WORKSPACE_NAVIGATOR] = workspaceNavDiff; + diff[NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR] = workspaceNavDiff; } } diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 4b485beb3618..8d5deb0d8bfa 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -90,7 +90,7 @@ function getActiveRouteIndex(stateOrRoute: StateOrRoute, index?: number): number if ( 'name' in stateOrRoute && - (stateOrRoute.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.WORKSPACE_NAVIGATOR) + (stateOrRoute.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) ) { return 0; } @@ -198,6 +198,28 @@ function navigate(route: Route = ROUTES.HOME, type?: string) { linkTo(navigationRef.current, route, type, isActiveRoute(route)); } +function newGoBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopToTop = false) { + if (!canNavigate('goBack')) { + return; + } + + if (!navigationRef.current?.canGoBack()) { + Log.hmmm('[Navigation] Unable to go back'); + return; + } + navigationRef.current.goBack(); + + if (fallbackRoute) { + /** + * Cases to handle: + * 1. RHP + * 2. fallbackRoute is in the current navigator + * 3. fallbackRoute is in the different navigator + * 4. fallbackRoute isn't present in the current state + */ + } +} + /** * @param fallbackRoute - Fallback route if pop/goBack action should, but is not possible within RHP * @param shouldEnforceFallback - Enforces navigation to fallback route @@ -233,7 +255,7 @@ function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopT } if (shouldEnforceFallback || (isFirstRouteInNavigator && fallbackRoute)) { - navigate(fallbackRoute, CONST.NAVIGATION.TYPE.UP); + navigate(fallbackRoute, 'REPLACE'); return; } @@ -243,7 +265,7 @@ function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopT if (isCentralPaneFocused && fallbackRoute) { // Allow CentralPane to use UP with fallback route if the path is not found in root navigator. if (distanceFromPathInRootNavigator === -1) { - navigate(fallbackRoute, CONST.NAVIGATION.TYPE.UP); + navigate(fallbackRoute, 'REPLACE'); return; } diff --git a/src/libs/Navigation/dismissModal.ts b/src/libs/Navigation/dismissModal.ts index ea00a8646c85..ff24f8f944b1 100644 --- a/src/libs/Navigation/dismissModal.ts +++ b/src/libs/Navigation/dismissModal.ts @@ -18,7 +18,7 @@ function dismissModal(navigationRef: NavigationContainerRef) const state = navigationRef.getState(); const lastRoute = state.routes.at(-1); switch (lastRoute?.name) { - case NAVIGATORS.WORKSPACE_NAVIGATOR: + case NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR: case NAVIGATORS.LEFT_MODAL_NAVIGATOR: case NAVIGATORS.RIGHT_MODAL_NAVIGATOR: case NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR: diff --git a/src/libs/Navigation/dismissModalWithReport.ts b/src/libs/Navigation/dismissModalWithReport.ts index 2c24d13c3ac4..0ddd2ab5bfc6 100644 --- a/src/libs/Navigation/dismissModalWithReport.ts +++ b/src/libs/Navigation/dismissModalWithReport.ts @@ -34,7 +34,7 @@ function dismissModalWithReport(targetReport: OnyxEntry, navigationRef: const state = navigationRef.getState(); const lastRoute = state.routes.at(-1); switch (lastRoute?.name) { - case NAVIGATORS.WORKSPACE_NAVIGATOR: + case NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR: case NAVIGATORS.LEFT_MODAL_NAVIGATOR: case NAVIGATORS.RIGHT_MODAL_NAVIGATOR: case SCREENS.NOT_FOUND: diff --git a/src/libs/Navigation/getPolicyIDFromState.ts b/src/libs/Navigation/getPolicyIDFromState.ts index 8077c5eea998..f5604c8a3733 100644 --- a/src/libs/Navigation/getPolicyIDFromState.ts +++ b/src/libs/Navigation/getPolicyIDFromState.ts @@ -11,7 +11,7 @@ import type {NavigationPartialRoute, RootStackParamList, State} from './types'; * - on Search related screens as policyID filter inside `q` (SearchQuery) param (only for SEARCH_CENTRAL_PANE) */ const getPolicyIDFromState = (state: State): string | undefined => { - const lastPolicyRoute = state.routes.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.CENTRAL_PANE); + const lastPolicyRoute = state?.routes?.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.CENTRAL_PANE); if (lastPolicyRoute?.params && 'policyID' in lastPolicyRoute.params) { return lastPolicyRoute?.params?.policyID; } diff --git a/src/libs/Navigation/getTopmostWorkspaceRoute.ts b/src/libs/Navigation/getTopmostWorkspaceRoute.ts index 4e9c5c607c5e..04e1237643dd 100644 --- a/src/libs/Navigation/getTopmostWorkspaceRoute.ts +++ b/src/libs/Navigation/getTopmostWorkspaceRoute.ts @@ -7,7 +7,7 @@ function getTopmostWorkspaceRoute(state: State): NavigationP return; } - const topmostWorkspaceRoute = state.routes.filter((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR).at(-1); + const topmostWorkspaceRoute = state.routes.filter((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR).at(-1); if (!topmostWorkspaceRoute) { return; diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 9f474c1e7055..872a64d3cc8d 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -57,7 +57,7 @@ export default function linkTo(navigation: NavigationContainerRef = { +const TAB_TO_CENTRAL_PANE_MAPPING: Record = { [SCREENS.HOME]: [SCREENS.REPORT], [SCREENS.SETTINGS.ROOT]: [ SCREENS.SETTINGS.PROFILE.ROOT, diff --git a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts b/src/libs/Navigation/linkingConfig/createSplitNavigator.ts index 7ee473560955..b016e535052e 100644 --- a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts +++ b/src/libs/Navigation/linkingConfig/createSplitNavigator.ts @@ -1,44 +1,28 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; -import type {NavigationPartialRoute, SplitNavigatorScreenName} from '@libs/Navigation/types'; -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; +import type {NavigationPartialRoute, SplitNavigatorByLHN, SplitNavigatorLHNScreen, SplitNavigatorParamListType} from '@libs/Navigation/types'; +import LHN_TO_SPLIT_NAVIGATOR_NAME from './LHN_TO_SPLIT_NAVIGATOR_MAPPING'; -const mapLhnToSplitNavigatorName = { - [SCREENS.SETTINGS.ROOT]: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, - [SCREENS.HOME]: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, - [SCREENS.WORKSPACE.INITIAL]: NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, -}; - -type SplitNavigatorLHNScreen = keyof typeof mapLhnToSplitNavigatorName; -type SplitNavigator = (typeof mapLhnToSplitNavigatorName)[SplitNavigatorLHNScreen]; +type ExtractRouteType = Extract; // The function getPathFromState that we are using in some places isn't working correctly without defined index. const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState => ({routes, index: routes.length - 1}); -function createSplitNavigator( - splitNavigatorLHNScreen: SplitNavigatorLHNScreen, - route?: NavigationPartialRoute, - policyID?: string, - key?: string, -): NavigationPartialRoute { +function createSplitNavigator( + splitNavigatorLHN: NavigationPartialRoute, + route?: NavigationPartialRoute>, + splitNavigatorParams?: SplitNavigatorParamListType[SplitNavigatorByLHN], +): NavigationPartialRoute> { const routes = []; - const params = policyID ? {policyID} : {}; - - // Both routes in WorkspaceNavigator should store a policyID in params, so here this param is also passed to the screen displayed in LHN in WorkspaceNavigator - routes.push({ - name: splitNavigatorLHNScreen, - }); + routes.push(splitNavigatorLHN); if (route) { routes.push(route); } return { - key, - name: mapLhnToSplitNavigatorName[splitNavigatorLHNScreen], + name: LHN_TO_SPLIT_NAVIGATOR_NAME[splitNavigatorLHN.name], state: getRoutesWithIndex(routes), - params, + params: splitNavigatorParams, }; } - export default createSplitNavigator; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 0bd68671e21e..15ecf12a3dea 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -4,8 +4,7 @@ import pick from 'lodash/pick'; import type {TupleToUnion} from 'type-fest'; import {isAnonymousUser} from '@libs/actions/Session'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import type {BottomTabName, CentralPaneName, NavigationPartialRoute, RootStackParamList, SplitNavigatorScreenName} from '@libs/Navigation/types'; -import {isCentralPaneName} from '@libs/NavigationUtils'; +import type {NavigationPartialRoute, RootStackParamList, SplitNavigatorScreenName} from '@libs/Navigation/types'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; @@ -16,8 +15,9 @@ import type {Screen} from '@src/SCREENS'; import SCREENS from '@src/SCREENS'; import CENTRAL_PANE_TO_RHP_MAPPING from './CENTRAL_PANE_TO_RHP_MAPPING'; import config, {normalizedConfigs} from './config'; -import getMatchingBottomTabRouteForState from './getMatchingBottomTabRouteForState'; +import createSplitNavigator from './createSplitNavigator'; import replacePathInNestedState from './replacePathInNestedState'; +import SEARCH_RHP_SCREENS from './SEARCH_RHP_SCREENS'; import {CENTRAL_PANE_TO_TAB_MAPPING} from './TAB_TO_CENTRAL_PANE_MAPPING'; const RHP_SCREENS_OPENED_FROM_LHN = [ @@ -60,54 +60,6 @@ type SplitNavigator = (typeof mapLhnToSplitNavigatorName)[SplitNavigatorLHNScree // The function getPathFromState that we are using in some places isn't working correctly without defined index. const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState => ({routes, index: routes.length - 1}); -const addPolicyIDToRoute = (route: NavigationPartialRoute, policyID?: string) => { - const routeWithPolicyID = {...route}; - if (!routeWithPolicyID.params) { - routeWithPolicyID.params = {policyID}; - return routeWithPolicyID; - } - - if ('policyID' in routeWithPolicyID.params && !!routeWithPolicyID.params.policyID) { - return routeWithPolicyID; - } - - routeWithPolicyID.params = {...routeWithPolicyID.params, policyID}; - - return routeWithPolicyID; -}; - -function createBottomTabNavigator(route: NavigationPartialRoute, policyID?: string): NavigationPartialRoute { - const routesForBottomTabNavigator: Array> = []; - routesForBottomTabNavigator.push(addPolicyIDToRoute(route, policyID) as NavigationPartialRoute); - - return { - name: NAVIGATORS.BOTTOM_TAB_NAVIGATOR, - state: getRoutesWithIndex(routesForBottomTabNavigator), - }; -} - -// function createWorkspaceNavigator(route?: NavigationPartialRoute): NavigationPartialRoute { -// const routes = []; - -// const policyID = route?.params && 'policyID' in route.params ? route.params.policyID : undefined; - -// // Both routes in WorkspaceNavigator should store a policyID in params, so here this param is also passed to the screen displayed in LHN in WorkspaceNavigator -// routes.push({ -// name: SCREENS.WORKSPACE.INITIAL, -// params: { -// policyID, -// }, -// }); - -// if (route) { -// routes.push(route); -// } -// return { -// name: NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, -// state: getRoutesWithIndex(routes), -// }; -// } - function getParamsFromRoute(screenName: string): string[] { const routeConfig = normalizedConfigs[screenName as Screen]; @@ -116,30 +68,8 @@ function getParamsFromRoute(screenName: string): string[] { return route.match(/(?<=[:?&])(\w+)(?=[/=?&]|$)/g) ?? []; } -function createSplitNavigator(splitNavigatorLHNScreen: SplitNavigatorLHNScreen, route?: NavigationPartialRoute): NavigationPartialRoute { - const routes = []; - - const policyID = route?.params && 'policyID' in route.params ? route.params.policyID : undefined; - - // Both routes in WorkspaceNavigator should store a policyID in params, so here this param is also passed to the screen displayed in LHN in WorkspaceNavigator - routes.push({ - name: splitNavigatorLHNScreen, - params: { - policyID, - }, - }); - - if (route) { - routes.push(route); - } - return { - name: mapLhnToSplitNavigatorName[splitNavigatorLHNScreen], - state: getRoutesWithIndex(routes), - }; -} - // This function will return CentralPaneNavigator route or WorkspaceNavigator route. -function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): NavigationPartialRoute | undefined { +function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): NavigationPartialRoute | NavigationPartialRoute<'Search_Central_Pane'> | undefined { // Check for backTo param. One screen with different backTo value may need diferent screens visible under the overlay. if (route.params && 'backTo' in route.params && typeof route.params.backTo === 'string') { const stateForBackTo = getStateFromPath(route.params.backTo, config); @@ -172,27 +102,30 @@ function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): Navigat for (const [centralPaneName, RHPNames] of Object.entries(CENTRAL_PANE_TO_RHP_MAPPING)) { if (RHPNames.includes(route.name)) { const paramsFromRoute = getParamsFromRoute(centralPaneName); - return createSplitNavigator(CENTRAL_PANE_TO_TAB_MAPPING[centralPaneName] as SplitNavigatorLHNScreen, { - name: centralPaneName as SplitNavigatorScreenName, - params: pick(route.params, paramsFromRoute), - }); + return createSplitNavigator( + {name: CENTRAL_PANE_TO_TAB_MAPPING[centralPaneName as SplitNavigatorScreenName] as SplitNavigatorLHNScreen, params: pick(route.params, paramsFromRoute)}, + { + name: centralPaneName, + params: pick(route.params, paramsFromRoute), + }, + ); } } - // Check for WorkspaceNavigator - // for (const [workspaceScreenName, RHPNames] of Object.entries(WORKSPACE_SCREEN_TO_RHP_MAPPING)) { - // if (RHPNames.includes(route.name)) { - // const paramsFromRoute = getParamsFromRoute(workspaceScreenName); + if (SEARCH_RHP_SCREENS.includes(route.name)) { + const paramsFromRoute = getParamsFromRoute(SCREENS.SEARCH.CENTRAL_PANE); - // return createWorkspaceNavigator({name: workspaceScreenName as WorkspaceScreenName, params: pick(route.params, paramsFromRoute)}); - // } - // } + return { + name: SCREENS.SEARCH.CENTRAL_PANE, + params: pick(route.params, paramsFromRoute), + }; + } // check for valid reportID in the route params // if the reportID is valid, we should navigate back to screen report in CPN const reportID = (route.params as Record)?.reportID; if (ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportID) { - return {name: SCREENS.REPORT, params: {reportID}}; + return createSplitNavigator({name: SCREENS.HOME}, {name: SCREENS.REPORT, params: {reportID}}); } } @@ -230,13 +163,13 @@ function getAdaptedState(state: PartialState // metainfo.isCentralPaneAndBottomTabMandatory = false; // metainfo.isWorkspaceNavigatorMandatory = false; // If matchingRootRoute is undefined and it's a narrow layout, don't add a report screen under the RHP. - matchingRootRoute = matchingRootRoute ?? (!isNarrowLayout ? {name: SCREENS.REPORT} : undefined); + matchingRootRoute = matchingRootRoute ?? (!isNarrowLayout ? createSplitNavigator({name: SCREENS.HOME}, {name: SCREENS.REPORT}) : createSplitNavigator({name: SCREENS.HOME})); } // When we open a screen in RHP from WorkspaceNavigator, we need to add the appropriate screen in CentralPane. // Then, when we close WorkspaceNavigator, we will be redirected to the correct page in CentralPane. if (matchingRootRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - routes.push(createSplitNavigator(SCREENS.SETTINGS.ROOT, {name: SCREENS.SETTINGS.WORKSPACES})); + routes.push(createSplitNavigator({name: SCREENS.SETTINGS.ROOT}, {name: SCREENS.SETTINGS.WORKSPACES})); } if (matchingRootRoute && (!isNarrowLayout || !isRHPScreenOpenedFromLHN)) { @@ -267,7 +200,7 @@ function getAdaptedState(state: PartialState } : undefined; - routes.push(createSplitNavigator(SCREENS.HOME, splitNavigatorMainScreen)); + routes.push(createSplitNavigator({name: SCREENS.HOME}, splitNavigatorMainScreen)); // Separate ifs are necessary for typescript to see that we are not pushing undefined to the array. if (lhpNavigator) { @@ -288,7 +221,6 @@ function getAdaptedState(state: PartialState return { adaptedState: getRoutesWithIndex(routes), - // metainfo, }; } if (WorkspaceNavigator) { @@ -299,35 +231,24 @@ function getAdaptedState(state: PartialState const routes = []; routes.push( - createSplitNavigator(SCREENS.SETTINGS.ROOT, { - name: SCREENS.SETTINGS.WORKSPACES, - params: { - policyID, + createSplitNavigator( + {name: SCREENS.SETTINGS.ROOT}, + { + name: SCREENS.SETTINGS.WORKSPACES, + params: { + policyID, + }, }, - }), + ), ); routes.push(WorkspaceNavigator); return { adaptedState: getRoutesWithIndex(routes), - // metainfo, }; } - // if (centralPaneNavigator) { - // // Routes - // // - matching bottom tab - // // - found central pane - // const routes = []; - // const matchingBottomTabRoute = getMatchingBottomTabRouteForState(state); - // routes.push(createBottomTabNavigator(matchingBottomTabRoute, policyID)); - // routes.push(centralPaneNavigator); - - // return { - // adaptedState: getRoutesWithIndex(routes), - // // metainfo, - // }; - // } + if (attachmentsScreen) { // Routes // - matching bottom tab @@ -337,25 +258,25 @@ function getAdaptedState(state: PartialState const reportAttachments = attachmentsScreen as Route<'Attachments', RootStackParamList['Attachments']>; if (reportAttachments.params?.type === CONST.ATTACHMENT_TYPE.REPORT) { - const matchingBottomTabRoute = getMatchingBottomTabRouteForState(state); - routes.push(createBottomTabNavigator(matchingBottomTabRoute, policyID)); - if (!isNarrowLayout) { - routes.push({name: SCREENS.REPORT, params: {reportID: reportAttachments.params?.reportID ?? '-1'}}); - } + const splitNavigatorMainScreen = !isNarrowLayout + ? { + name: SCREENS.REPORT, + params: {reportID: reportAttachments.params?.reportID ?? '-1'}, + } + : undefined; + + routes.push(createSplitNavigator({name: SCREENS.HOME}, splitNavigatorMainScreen)); routes.push(reportAttachments); return { adaptedState: getRoutesWithIndex(routes), - // metainfo, }; } } // We need to make sure that this if only handles states where we deeplink to the bottom tab directly - return { adaptedState: state, - // metainfo, }; } diff --git a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts index 1db77f9917ff..0645a45e0924 100644 --- a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts +++ b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts @@ -8,7 +8,7 @@ import {CENTRAL_PANE_TO_TAB_MAPPING} from './TAB_TO_CENTRAL_PANE_MAPPING'; function getMatchingBottomTabRouteForState(state: State, policyID?: string): NavigationPartialRoute { const paramsWithPolicyID = policyID ? {policyID} : undefined; const defaultRoute = {name: SCREENS.HOME, params: paramsWithPolicyID}; - const isWorkspaceNavigatorOpened = state.routes.some((route) => route.name === NAVIGATORS.WORKSPACE_NAVIGATOR); + const isWorkspaceNavigatorOpened = state.routes.some((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR); if (isWorkspaceNavigatorOpened) { return {name: SCREENS.SETTINGS.ROOT, params: paramsWithPolicyID}; diff --git a/src/libs/Navigation/newLinkTo/index.ts b/src/libs/Navigation/newLinkTo/index.ts index 0f278a9dfc24..100491b04bd3 100644 --- a/src/libs/Navigation/newLinkTo/index.ts +++ b/src/libs/Navigation/newLinkTo/index.ts @@ -74,7 +74,7 @@ export default function linkTo(navigation: NavigationContainerRef; @@ -51,6 +52,16 @@ type NavigationPartialRoute = PartialRoute = NavigationState | PartialState>; +type SplitNavigatorLHNScreen = keyof typeof LHN_TO_SPLIT_NAVIGATOR_NAME; + +type SplitNavigatorParamListType = { + [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: SettingsSplitNavigatorParamList; + [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: ReportsSplitNavigatorParamList; + [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: WorkspaceSplitNavigatorParamList; +}; + +type SplitNavigatorByLHN = (typeof LHN_TO_SPLIT_NAVIGATOR_NAME)[T]; + type CentralPaneScreensParamList = { [SCREENS.REPORT]: { reportActionID: string; @@ -1559,7 +1570,7 @@ type CentralPaneName = keyof CentralPaneScreensParamList; type OnboardingFlowName = keyof OnboardingModalNavigatorParamList; -type SplitNavigatorScreenName = keyof WorkspaceSplitNavigatorParamList & keyof SettingsSplitNavigatorParamList & keyof ReportsSplitNavigatorParamList; +type SplitNavigatorScreenName = keyof (WorkspaceSplitNavigatorParamList & SettingsSplitNavigatorParamList & ReportsSplitNavigatorParamList); type SwitchPolicyIDParams = { policyID?: string; @@ -1636,4 +1647,7 @@ export type { MissingPersonalDetailsParamList, DebugParamList, SplitNavigatorScreenName, + SplitNavigatorLHNScreen, + SplitNavigatorParamListType, + SplitNavigatorByLHN, }; From 59660387ed39fab3f03a8238d97aee23f48b8e00 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 13 Sep 2024 07:48:00 +0200 Subject: [PATCH 018/257] Refactor switching policyID --- src/CONST.ts | 1 + .../CustomRouter.ts | 24 +++++++++++++++-- src/libs/Navigation/Navigation.ts | 24 +++++++++-------- src/libs/Navigation/dismissModalWithReport.ts | 12 +++++---- src/libs/Navigation/getTopmostReportId.ts | 26 ++++++++++++------- .../subscribePushNotification/index.ts | 5 ++-- src/libs/actions/Report.ts | 6 ++--- src/pages/WorkspaceSwitcherPage/index.tsx | 3 +-- .../SidebarScreen/BaseSidebarScreen.tsx | 14 +++++----- src/pages/workspace/WorkspaceProfilePage.tsx | 2 +- src/pages/workspace/WorkspacesListPage.tsx | 2 +- 11 files changed, 75 insertions(+), 44 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 25ba86ee3e1a..753102eacfa4 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -4200,6 +4200,7 @@ const CONST = { REPLACE: 'REPLACE', PUSH: 'PUSH', NAVIGATE: 'NAVIGATE', + SWITCH_POLICY_ID: 'SWITCH_POLICY_ID', }, }, TIME_PERIOD: { diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 57888ffd1635..8a0e085b6e58 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -90,8 +90,7 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { return { ...stackRouter, getStateForAction(state: StackNavigationState, action: CommonActions.Action | StackActionType | CustomRootStackActionType, configOptions: RouterConfigOptions) { - // TODO: Put this into const; - if (action.type === 'SWITCH_POLICY_ID') { + if (action.type === CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID) { const lastRoute = state.routes.at(-1); if (lastRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { const currentParams = lastRoute.params as RootStackParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; @@ -115,6 +114,27 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { if (lastRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { // TODO: handle change policy id of reports navigator. + if (action.payload.reportID) { + const newRoute = createSplitNavigator( + { + name: SCREENS.HOME, + }, + { + name: SCREENS.REPORT, + params: { + reportID: action.payload.reportID, + reportActionID: action.payload.reportActionID, + referrer: action.payload.referrer, + }, + }, + { + policyID: action.payload.policyID, + }, + ); + const newRoutes = [...state.routes, newRoute]; + return {...state, stale: true, routes: newRoutes, index: newRoutes.length - 1}; + } + const splitNavigatorMainScreen = getIsNarrowLayout() ? undefined : {name: SCREENS.REPORT, params: {reportID: ''}}; const newRoute = createSplitNavigator( diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 8d5deb0d8bfa..cd0016b757b3 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -26,8 +26,7 @@ import getMatchingBottomTabRouteForState from './linkingConfig/getMatchingBottom import navigationRef from './navigationRef'; import linkTo from './newLinkTo'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; -import switchPolicyID from './switchPolicyID'; -import type {NavigationStateRoute, RootStackParamList, State, StateOrRoute, SwitchPolicyIDParams} from './types'; +import type {NavigationStateRoute, RootStackParamList, State, StateOrRoute} from './types'; let resolveNavigationIsReadyPromise: () => void; const navigationIsReadyPromise = new Promise((resolve) => { @@ -429,18 +428,21 @@ function waitForProtectedRoutes() { }); } -function navigateWithSwitchPolicyID(params: SwitchPolicyIDParams) { - if (!canNavigate('navigateWithSwitchPolicyID')) { - return; - } - - return switchPolicyID(navigationRef.current, params); -} - function getTopMostCentralPaneRouteFromRootState() { return getTopmostCentralPaneRoute(navigationRef.getRootState() as State); } +type SwitchPolicyIDPayload = { + policyID?: string; + reportID?: number; + reportActionID?: string; + referrer?: string; +}; + +function switchPolicyID(payload: SwitchPolicyIDPayload) { + navigationRef.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID, payload}); +} + export default { setShouldPopAllStateOnUP, navigate, @@ -460,7 +462,7 @@ export default { getTopmostReportActionId, waitForProtectedRoutes, parseHybridAppUrl, - navigateWithSwitchPolicyID, + switchPolicyID, resetToHome, closeRHPFlow, setNavigationActionToMicrotaskQueue, diff --git a/src/libs/Navigation/dismissModalWithReport.ts b/src/libs/Navigation/dismissModalWithReport.ts index 0ddd2ab5bfc6..302dc68f09f8 100644 --- a/src/libs/Navigation/dismissModalWithReport.ts +++ b/src/libs/Navigation/dismissModalWithReport.ts @@ -51,11 +51,13 @@ function dismissModalWithReport(targetReport: OnyxEntry, navigationRef: const policyMemberAccountIDs = getPolicyEmployeeAccountIDs(policyID); const shouldOpenAllWorkspace = isEmptyObject(targetReport) ? true : !doesReportBelongToWorkspace(targetReport, policyMemberAccountIDs, policyID); - if (shouldOpenAllWorkspace) { - switchPolicyID(navigationRef, {route: ROUTES.HOME}); - } else { - switchPolicyID(navigationRef, {policyID, route: ROUTES.HOME}); - } + // @TODO Handle dismissing modal with switching a policyID + + // if (shouldOpenAllWorkspace) { + // switchPolicyID(navigationRef, {route: ROUTES.HOME}); + // } else { + // switchPolicyID(navigationRef, {policyID, route: ROUTES.HOME}); + // } const action: StackNavigationAction = getActionFromState(reportState, linkingConfig.config); if (action) { diff --git a/src/libs/Navigation/getTopmostReportId.ts b/src/libs/Navigation/getTopmostReportId.ts index dc53d040f087..d1d8bf2eacfc 100644 --- a/src/libs/Navigation/getTopmostReportId.ts +++ b/src/libs/Navigation/getTopmostReportId.ts @@ -1,5 +1,5 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; -import {isCentralPaneName} from '@libs/NavigationUtils'; +import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import type {RootStackParamList} from './types'; @@ -16,23 +16,29 @@ function getTopmostReportId(state: NavigationState | NavigationState isCentralPaneName(route.name)).at(-1); - if (!topmostCentralPane) { + const topmostReportsSplitNavigator = state.routes?.filter((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR).at(-1); + + if (!topmostReportsSplitNavigator) { return; } - const directReportParams = topmostCentralPane.params; - const directReportIdParam = directReportParams && 'reportID' in directReportParams && directReportParams?.reportID; + const topmostReport = topmostReportsSplitNavigator.state?.routes.filter((route) => route.name === SCREENS.REPORT).at(-1); - if (!topmostCentralPane.state && !directReportIdParam) { + if (!topmostReport) { return; } - if (directReportIdParam) { - return directReportIdParam; - } + // const directReportParams = topmostCentralPane.params; + // const directReportIdParam = directReportParams && 'reportID' in directReportParams && directReportParams?.reportID; + + // if (!topmostCentralPane.state && !directReportIdParam) { + // return; + // } + + // if (directReportIdParam) { + // return directReportIdParam; + // } - const topmostReport = topmostCentralPane.state?.routes.filter((route) => route.name === SCREENS.REPORT).at(-1); if (!topmostReport) { return; } diff --git a/src/libs/Notification/PushNotification/subscribePushNotification/index.ts b/src/libs/Notification/PushNotification/subscribePushNotification/index.ts index c1a1442b1e53..b4563e12ac8d 100644 --- a/src/libs/Notification/PushNotification/subscribePushNotification/index.ts +++ b/src/libs/Notification/PushNotification/subscribePushNotification/index.ts @@ -97,9 +97,10 @@ function navigateToReport({reportID, reportActionID}: ReportActionPushNotificati Log.info('[PushNotification] onSelected() - Navigation is ready. Navigating...', false, {reportID, reportActionID}); if (!reportBelongsToWorkspace) { - Navigation.navigateWithSwitchPolicyID({route: ROUTES.HOME}); + Navigation.switchPolicyID({policyID, reportID}); + } else { + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(String(reportID))); } - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(String(reportID))); } catch (error) { let errorMessage = String(error); if (error instanceof Error) { diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index f313ecbb3f48..482fdcd9638f 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1047,8 +1047,7 @@ function navigateToAndOpenReport( if (shouldDismissModal) { Navigation.dismissModalWithReport(report); } else { - Navigation.navigateWithSwitchPolicyID({route: ROUTES.HOME}); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(report?.reportID ?? '-1'), actionType); + Navigation.switchPolicyID({policyID: undefined, reportID: report?.reportID ?? '-1'}); } } @@ -2492,7 +2491,8 @@ function showReportActionNotification(reportID: string, reportAction: ReportActi const policyEmployeeAccountIDs = policyID ? getPolicyEmployeeAccountIDs(policyID) : []; const reportBelongsToWorkspace = policyID ? doesReportBelongToWorkspace(report, policyEmployeeAccountIDs, policyID) : false; if (!reportBelongsToWorkspace) { - Navigation.navigateWithSwitchPolicyID({route: ROUTES.HOME}); + Navigation.switchPolicyID({policyID: undefined, reportID, referrer: CONST.REFERRER.NOTIFICATION}); + return; } navigateFromNotification(reportID); }); diff --git a/src/pages/WorkspaceSwitcherPage/index.tsx b/src/pages/WorkspaceSwitcherPage/index.tsx index 83bb71ef15e2..bb74a8852880 100644 --- a/src/pages/WorkspaceSwitcherPage/index.tsx +++ b/src/pages/WorkspaceSwitcherPage/index.tsx @@ -92,8 +92,7 @@ function WorkspaceSwitcherPage() { Navigation.goBack(); if (policyID !== activeWorkspaceID) { - // Navigation.navigateWithSwitchPolicyID({policyID}); - navigationRef.dispatch({type: 'SWITCH_POLICY_ID', payload: {policyID}}); + Navigation.switchPolicyID({policyID}); } }, [activeWorkspaceID], diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx index 71a8587fb889..08ce4a7df94d 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx @@ -36,14 +36,14 @@ function BaseSidebarScreen() { Timing.start(CONST.TIMING.SIDEBAR_LOADED); }, []); - useEffect(() => { - if (!!activeWorkspace || activeWorkspaceID === undefined) { - return; - } + // useEffect(() => { + // if (!!activeWorkspace || activeWorkspaceID === undefined) { + // return; + // } - Navigation.navigateWithSwitchPolicyID({policyID: undefined}); - updateLastAccessedWorkspace(undefined); - }, [activeWorkspace, activeWorkspaceID]); + // Navigation.switchPolicyID({policyID: undefined}); + // updateLastAccessedWorkspace(undefined); + // }, [activeWorkspace, activeWorkspaceID]); return ( Date: Wed, 18 Sep 2024 16:09:37 +0200 Subject: [PATCH 019/257] improve routers --- .../createCustomBottomTabNavigator/TopBar.tsx | 2 + .../CustomRouter.ts | 179 ++++++----------- .../SplitStackRouter.ts | 44 ++++- .../createSplitStackNavigator/index.tsx | 7 +- .../createSplitStackNavigator/types.ts | 4 +- src/libs/Navigation/newLinkTo/index.ts | 182 +----------------- 6 files changed, 103 insertions(+), 315 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx index 4684eb9637be..0ce95aab0265 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx @@ -29,6 +29,8 @@ function TopBar({breadcrumbLabel, activeWorkspaceID, shouldDisplaySearch = true, const styles = useThemeStyles(); const theme = useTheme(); const {translate} = useLocalize(); + + // @TODO use policyID from state instead of activeWorkspaceID. It will help with glitching. const policy = usePolicy(activeWorkspaceID); const [session] = useOnyx(ONYXKEYS.SESSION, {selector: (sessionValue) => sessionValue && {authTokenType: sessionValue.authTokenType}}); const isAnonymousUser = Session.isAnonymousUser(session); diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 8a0e085b6e58..db56bad402e3 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -1,12 +1,10 @@ import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; -import {findFocusedRoute, getPathFromState, StackRouter} from '@react-navigation/native'; +import {findFocusedRoute, getPathFromState, StackActions, StackRouter} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/routers'; -import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import * as Localize from '@libs/Localize'; import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; import isSideModalNavigator from '@libs/Navigation/isSideModalNavigator'; import linkingConfig from '@libs/Navigation/linkingConfig'; -import createSplitNavigator from '@libs/Navigation/linkingConfig/createSplitNavigator'; import type {RootStackParamList, State} from '@libs/Navigation/types'; import {isOnboardingFlowName} from '@libs/NavigationUtils'; import * as SearchUtils from '@libs/SearchUtils'; @@ -27,6 +25,7 @@ function shouldPreventReset(state: StackNavigationState, action: if (isOnboardingFlowName(currentFocusedRoute?.name) && !isOnboardingFlowName(targetFocusedRoute?.name)) { Welcome.setOnboardingErrorMessage(Localize.translateLocal('onboarding.purpose.errorBackButton')); // We reset the URL as the browser sets it in a way that doesn't match the navigation state + // @TODO is it working? Maybe we should split it for platforms. // eslint-disable-next-line no-restricted-globals history.replaceState({}, '', getPathFromState(state, linkingConfig.config)); return true; @@ -49,39 +48,17 @@ function shouldDismissSideModalNavigator(state: StackNavigationState) { -// for (let i = state.routes.length - 1; i >= 0; i--) { -// const route = state.routes[i]; -// if (route.name === SCREENS.SEARCH.CENTRAL_PANE) { -// return extractPolicyIDFromQuery(route as NavigationPartialRoute); -// } -// if (route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { -// const params = route.params ? (route.params as RootStackParamList[typeof NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]) : undefined; -// return params?.policyID; -// } -// } -// } + // @TODO not sure about these properties. + reportID?: string; + reportActionID?: string; + referrer?: string; + }; +}; function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { const stackRouter = StackRouter(options); @@ -95,61 +72,38 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { if (lastRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { const currentParams = lastRoute.params as RootStackParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; const queryJSON = SearchUtils.buildSearchQueryJSON(currentParams.q); - let newParams = null; - if (!queryJSON) { - return; + return null; } - if (action.payload.policyID) { queryJSON.policyID = action.payload.policyID; } else { delete queryJSON.policyID; } - - newParams = {...currentParams, q: SearchUtils.buildSearchQueryString(queryJSON)}; - const newRoutes = [...state.routes, {...lastRoute, params: newParams}]; - return {...state, routes: newRoutes, index: newRoutes.length - 1}; + const newAction = StackActions.push(SCREENS.SEARCH.CENTRAL_PANE, { + ...currentParams, + q: SearchUtils.buildSearchQueryString(queryJSON), + }); + return stackRouter.getStateForAction(state, newAction, configOptions); } if (lastRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { - // TODO: handle change policy id of reports navigator. - + // @TODO: It would be great to avoid coupling switchPolicy with specific actions for report screen if (action.payload.reportID) { - const newRoute = createSplitNavigator( - { - name: SCREENS.HOME, - }, - { - name: SCREENS.REPORT, - params: { - reportID: action.payload.reportID, - reportActionID: action.payload.reportActionID, - referrer: action.payload.referrer, - }, - }, - { - policyID: action.payload.policyID, + const newAction = StackActions.push(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, { + policyID: action.payload.policyID, + screen: SCREENS.REPORT, + params: { + reportID: action.payload.reportID, + reportActionID: action.payload.reportActionID, + referrer: action.payload.referrer, }, - ); - const newRoutes = [...state.routes, newRoute]; - return {...state, stale: true, routes: newRoutes, index: newRoutes.length - 1}; + }); + return stackRouter.getStateForAction(state, newAction, configOptions); } - - const splitNavigatorMainScreen = getIsNarrowLayout() ? undefined : {name: SCREENS.REPORT, params: {reportID: ''}}; - - const newRoute = createSplitNavigator( - { - name: SCREENS.HOME, - }, - splitNavigatorMainScreen, - { - policyID: action.payload.policyID, - }, - ); - const newRoutes = [...state.routes, newRoute]; - return {...state, stale: true, routes: newRoutes, index: newRoutes.length - 1}; + const newAction = StackActions.push(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, {policyID: action.payload.policyID}); + return stackRouter.getStateForAction(state, newAction, configOptions); } - // In other cases, do nothing. + // We don't have other navigators that should handle switch policy action. return null; } @@ -160,68 +114,49 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { if (action.type === 'PUSH' && action.payload.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { const policyID = getPolicyIDFromState(state as State); - const currentParams = {...action.payload.params}; - action.payload.params = {...currentParams, policyID}; + + const modifiedAction = { + ...action, + payload: { + ...action.payload, + params: { + ...action.payload.params, + policyID, + }, + }, + }; + + return stackRouter.getStateForAction(state, modifiedAction, configOptions); } if (action.type === 'PUSH' && action.payload.name === SCREENS.SEARCH.CENTRAL_PANE) { const policyID = getPolicyIDFromState(state as State); const currentParams = action.payload.params as RootStackParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; const queryJSON = SearchUtils.buildSearchQueryJSON(currentParams.q); + if (!queryJSON) { - return; + return null; } + if (policyID) { queryJSON.policyID = policyID; } else { delete queryJSON.policyID; } - action.payload.params = {q: SearchUtils.buildSearchQueryString(queryJSON), isCustomQuery: false}; - } + const modifiedAction = { + ...action, + payload: { + ...action.payload, + params: { + ...action.payload.params, + q: SearchUtils.buildSearchQueryString(queryJSON), + }, + }, + }; - // TODO: I don't remember if the code below makes sense Wojtek :D but it's possible. - // One part seems redundant to the lines 102-108 above - // - // Copy existing policyID to the new screen. - // TODO: Can't figure out the types for - // if (action.type === 'PUSH' && isPushingScreenWithWorkspaceSwitcher(action)) { - // const policyID = extractPolicyIDFromState(state); - - // // If there is no policyID, continue with the default behavior. - // if (!policyID) { - // return stackRouter.getStateForAction(state, action, configOptions); - // } - - // // If there is, we need to add it to the new screen. - // // - // const modifiedAction = {...action}; - - // if (action.payload.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { - // modifiedAction.payload.params = {...action.payload.params, policyID}; - // } - - // if (action.payload.name === SCREENS.SEARCH.CENTRAL_PANE) { - // if (policyID) { - // const queryJSON = SearchUtils.buildSearchQueryJSON(params.q); - // if (queryJSON) { - // queryJSON.policyID = policyID; - // params.q = SearchUtils.buildSearchQueryString(queryJSON); - // } - // } else { - // const queryJSON = SearchUtils.buildSearchQueryJSON(params.q); - // if (queryJSON) { - // delete queryJSON.policyID; - // params.q = SearchUtils.buildSearchQueryString(queryJSON); - // } - // } - // action.payload.params = {...action.payload.params, policyID: extractPolicyIDFromState(state)}; - // } - - // // This shouldn't happen, but if it does, we don't want to break the app. - // console.error('Unhandled screen with workspace switcher:', action.payload.name); - // return; - // } + return stackRouter.getStateForAction(state, modifiedAction, configOptions); + } if (shouldDismissSideModalNavigator(state, action)) { const modifiedState = {...state, routes: state.routes.slice(0, -1), index: state.index !== 0 ? state.index - 1 : 0}; diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts index ef0af961540f..7bdb1ba22a3d 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts @@ -1,26 +1,36 @@ import type {CommonActions, ParamListBase, PartialState, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; -import {StackRouter} from '@react-navigation/native'; +import {StackActions, StackRouter} from '@react-navigation/native'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; +import navigationRef from '@libs/Navigation/navigationRef'; import type {SplitStackNavigatorRouterOptions} from './types'; type StackState = StackNavigationState | PartialState>; const isAtLeastOneInState = (state: StackState, screenName: string): boolean => state.routes.some((route) => route.name === screenName); -function adaptStateIfNecessary(state: StackState, sidebarScreen: string, defaultCentralScreen: string) { +type AdaptStateIfNecessaryArgs = { + state: StackState; + options: SplitStackNavigatorRouterOptions; +}; + +function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralScreen, parentRoute}}: AdaptStateIfNecessaryArgs) { const isNarrowLayout = getIsNarrowLayout(); + + // @TODO leftover from times when there was fullscreen navigator only for the workspaces. const workspaceCentralPane = state.routes.at(-1); + // There should always be sidebarScreen screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings. if (!isAtLeastOneInState(state, sidebarScreen)) { // @ts-expect-error Updating read only property // noinspection JSConstantReassignment state.stale = true; // eslint-disable-line - // This is necessary for ts to narrow type down to PartialState. + // This is necessary for typescript to narrow type down to PartialState. if (state.stale === true) { // Unshift the root screen to fill left pane. state.routes.unshift({ name: sidebarScreen, + // @TODO why we need to pass params here? params: workspaceCentralPane?.params, }); } @@ -31,13 +41,21 @@ function adaptStateIfNecessary(state: StackState, sidebarScreen: string, default // - defaultCentralScreen to cover central pane. if (!isNarrowLayout) { if (state.routes.length === 1 && state.routes[0].name === sidebarScreen) { + const rootState = navigationRef.getRootState(); + + // @TODO: If we have optimization for not rendering all split navigators, then last selected option won't be in the state. + // @TODO: Do we want to use previous selected screen if the policyID is different. + const previousSameNavigator = rootState?.routes.findLast((route) => route.name === parentRoute.name && route.state !== undefined); + const previousSelectedCentralScreen = + previousSameNavigator?.state?.routes && previousSameNavigator.state.routes.length > 1 ? previousSameNavigator.state.routes.at(-1)?.name : undefined; + // @ts-expect-error Updating read only property // noinspection JSConstantReassignment state.stale = true; // eslint-disable-line // Push the default settings central pane screen. if (state.stale === true) { state.routes.push({ - name: defaultCentralScreen, + name: previousSelectedCentralScreen ?? defaultCentralScreen, params: state.routes.at(0)?.params, }); } @@ -61,9 +79,9 @@ function SplitStackRouter(options: SplitStackNavigatorRouterOptions) { getStateForAction(state: StackNavigationState, action: CommonActions.Action | StackActionType, configOptions: RouterConfigOptions) { if (isPushingSidebarOnCentralPane(state, action, options)) { if (getIsNarrowLayout()) { - // TODO: It's possible that it's better to push whole new SplitNavigator in such case. Not sure yet. - // Pop to top on narrow layout. - return {...state, routes: [state.routes.at(0)], index: 0}; + // @TODO: It's possible that it's better to push whole new SplitNavigator in such case. Not sure yet. + const newAction = StackActions.popToTop(); + return stackRouter.getStateForAction(state, newAction, configOptions); } // On wide screen do nothing as we want to keep the central pane screen and the sidebar is visible. return state; @@ -72,7 +90,11 @@ function SplitStackRouter(options: SplitStackNavigatorRouterOptions) { }, getInitialState({routeNames, routeParamList, routeGetIdList}: RouterConfigOptions) { const initialState = stackRouter.getInitialState({routeNames, routeParamList, routeGetIdList}); - adaptStateIfNecessary(initialState, options.sidebarScreen, options.defaultCentralScreen); + + adaptStateIfNecessary({ + state: initialState, + options, + }); // If we needed to modify the state we need to rehydrate it to get keys for new routes. if (initialState.stale) { @@ -82,7 +104,11 @@ function SplitStackRouter(options: SplitStackNavigatorRouterOptions) { return initialState; }, getRehydratedState(partialState: StackState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): StackNavigationState { - adaptStateIfNecessary(partialState, options.sidebarScreen, options.defaultCentralScreen); + adaptStateIfNecessary({ + state: partialState, + options, + }); + const state = stackRouter.getRehydratedState(partialState, {routeNames, routeParamList, routeGetIdList}); return state; }, diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index ea3c8ecad21b..d90b60d2ac4d 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -1,5 +1,5 @@ import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native'; -import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; +import {createNavigatorFactory, useNavigationBuilder, useRoute} from '@react-navigation/native'; import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; import {StackView} from '@react-navigation/stack'; import React from 'react'; @@ -22,6 +22,8 @@ function SplitStackNavigator(props: SplitStackN const children = usePrepareSplitStackNavigatorChildren(props.children, props.sidebarScreen, screenOptions.homeScreen); + const route = useRoute(); + const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< StackNavigationState, SplitStackNavigatorRouterOptions, @@ -34,6 +36,9 @@ function SplitStackNavigator(props: SplitStackN initialRouteName: props.initialRouteName, sidebarScreen: props.sidebarScreen, defaultCentralScreen: props.defaultCentralScreen, + + // @TODO figure out if we can end in a situation where the state and route are not in sync. If so, we may need to figure out a getter. + parentRoute: route, }); useHandleScreenResize(navigation); diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts index 5e62b4e710a6..cc9db03c75ae 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts @@ -1,7 +1,7 @@ -import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; +import type {DefaultNavigatorOptions, ParamListBase, RouteProp, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; -type SplitStackNavigatorRouterOptions = StackRouterOptions & {defaultCentralScreen: string; sidebarScreen: string}; +type SplitStackNavigatorRouterOptions = StackRouterOptions & {defaultCentralScreen: string; sidebarScreen: string; parentRoute: RouteProp}; type SplitStackNavigatorProps = DefaultNavigatorOptions< ParamListBase, diff --git a/src/libs/Navigation/newLinkTo/index.ts b/src/libs/Navigation/newLinkTo/index.ts index 100491b04bd3..e19f02687f1c 100644 --- a/src/libs/Navigation/newLinkTo/index.ts +++ b/src/libs/Navigation/newLinkTo/index.ts @@ -24,7 +24,7 @@ function shouldDispatchAction(currentState: NavigationState, return true; } -export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string, isActiveRoute?: boolean) { +export default function linkTo(navigation: NavigationContainerRef | null, path: Route) { if (!navigation) { throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); } @@ -54,186 +54,6 @@ export default function linkTo(navigation: NavigationContainerRef; - // const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; - // // Creating path with /w/ included if necessary. - // const topmostCentralPaneRoute = getTopmostCentralPaneRoute(rootState); - // const policyIDs = !!topmostCentralPaneRoute?.params && 'policyIDs' in topmostCentralPaneRoute.params ? (topmostCentralPaneRoute?.params?.policyIDs as string) : ''; - // const extractedPolicyID = extractPolicyIDFromPath(`/${path}`); - // const policyIDFromState = getPolicyIDFromState(rootState); - // const policyID = extractedPolicyID ?? policyIDFromState ?? policyIDs; - // const lastRoute = rootState?.routes?.at(-1); - - // const isNarrowLayout = getIsNarrowLayout(); - - // const isWorkspaceScreenOnTop = lastRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR; - - // // policyIDs is present only on SCREENS.SEARCH.CENTRAL_PANE and it's displayed in the url as a query param, on the other pages this parameter is called policyID and it's shown in the url in the format: /w/:policyID - // if (policyID && !isWorkspaceScreenOnTop && !policyIDs) { - // // The stateFromPath doesn't include proper path if there is a policy passed with /w/id. - // // We need to replace the path in the state with the proper one. - // // To avoid this hacky solution we may want to create custom getActionFromState function in the future. - // replacePathInNestedState(stateFromPath, `/w/${policyID}${pathWithoutPolicyID}`); - // } - - // const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); - - // const isReportInRhpOpened = isReportOpenInRHP(rootState); - - // // If action type is different than NAVIGATE we can't change it to the PUSH safely - // if (action?.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { - // const actionPayloadParams = action.payload.params as ActionPayloadParams; - - // const topRouteName = lastRoute?.name; - - // // CentralPane screens aren't nested in any navigator, if actionPayloadParams?.screen is undefined, it means the screen name and parameters have to be read directly from action.payload - // const targetName = actionPayloadParams?.screen ?? action.payload.name; - // const targetParams = actionPayloadParams?.params ?? actionPayloadParams; - // const isTargetNavigatorOnTop = topRouteName === action.payload.name; - - // const isTargetScreenDifferentThanCurrent = !!(!topmostCentralPaneRoute || topmostCentralPaneRoute.name !== targetName); - // const areParamsDifferent = - // targetName === SCREENS.REPORT - // ? getTopmostReportId(rootState) !== getTopmostReportId(stateFromPath) - // : !shallowCompare( - // omitBy(topmostCentralPaneRoute?.params as Record | undefined, (value) => value === undefined), - // omitBy(targetParams as Record | undefined, (value) => value === undefined), - // ); - - // // If this action is navigating to the report screen and the top most navigator is different from the one we want to navigate - PUSH the new screen to the top of the stack by default - // if (isCentralPaneName(action.payload.name) && (isTargetScreenDifferentThanCurrent || areParamsDifferent)) { - // // We need to push a tab if the tab doesn't match the central pane route that we are going to push. - // const topmostBottomTabRoute = getTopmostBottomTabRoute(rootState); - // const policyIDsFromState = extractPolicyIDsFromState(stateFromPath); - // const matchingBottomTabRoute = getMatchingBottomTabRouteForState(stateFromPath, policyID || policyIDsFromState); - // const isOpeningSearch = matchingBottomTabRoute.name === SCREENS.SEARCH.BOTTOM_TAB; - // const isNewPolicyID = - // ((topmostBottomTabRoute?.params as Record)?.policyID ?? '') !== - // ((matchingBottomTabRoute?.params as Record)?.policyID ?? ''); - - // if (topmostBottomTabRoute && (topmostBottomTabRoute.name !== matchingBottomTabRoute.name || isNewPolicyID || isOpeningSearch)) { - // root.dispatch({ - // type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - // payload: matchingBottomTabRoute, - // }); - // } - - // if (type === CONST.NAVIGATION.TYPE.UP) { - // action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; - // } else { - // action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - // } - - // // If we navigate to SCREENS.SEARCH.CENTRAL_PANE, it's necessary to pass the current policyID, but we have to remember that this param is called policyIDs on this page - // if (targetName === SCREENS.SEARCH.CENTRAL_PANE && targetParams && policyID) { - // (targetParams as Record).policyIDs = policyID; - // } - - // // If the type is UP, we deeplinked into one of the RHP flows and we want to replace the current screen with the previous one in the flow - // // and at the same time we want the back button to go to the page we were before the deeplink - // } else if (type === CONST.NAVIGATION.TYPE.UP) { - // action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; - - // // If this action is navigating to ModalNavigator or WorkspaceNavigator and the last route on the root navigator is not already opened Navigator then push - // } else if ((action.payload.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR || isSideModalNavigator(action.payload.name)) && !isTargetNavigatorOnTop) { - // if (isSideModalNavigator(topRouteName)) { - // dismissModal(navigation); - // } - - // // If this RHP has mandatory central pane and bottom tab screens defined we need to push them. - // const {adaptedState, metainfo} = getAdaptedStateFromPath(path, linkingConfig.config); - // if (adaptedState && (metainfo.isCentralPaneAndBottomTabMandatory || metainfo.isWorkspaceNavigatorMandatory)) { - // const diff = getPartialStateDiff(rootState, adaptedState as State, metainfo); - // const diffActions = getActionsFromPartialDiff(diff); - // for (const diffAction of diffActions) { - // root.dispatch(diffAction); - // } - // } - // // All actions related to FullScreenNavigator on wide screen are pushed when comparing differences between rootState and adaptedState. - // if (action.payload.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - // return; - // } - // action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - - // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - // } else if (action.payload.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR) { - // // If path contains a policyID, we should invoke the navigate function - // const shouldNavigate = !!extractedPolicyID; - // const actionForBottomTabNavigator = getActionForBottomTabNavigator(action, rootState, policyID, shouldNavigate); - - // if (!actionForBottomTabNavigator) { - // return; - // } - - // root.dispatch(actionForBottomTabNavigator); - - // // If the layout is wide we need to push matching central pane route to the stack. - // if (!isNarrowLayout) { - // // stateFromPath should always include bottom tab navigator state, so getMatchingCentralPaneRouteForState will be always defined. - // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - // const matchingCentralPaneRoute = getMatchingCentralPaneRouteForState(stateFromPath, rootState)!; - // if (matchingCentralPaneRoute && 'name' in matchingCentralPaneRoute) { - // root.dispatch({ - // type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - // payload: { - // name: matchingCentralPaneRoute.name, - // params: matchingCentralPaneRoute.params, - // }, - // }); - // } - // } else { - // // If the layout is small we need to pop everything from the central pane so the bottom tab navigator is visible. - // root.dispatch({ - // type: 'POP_TO_TOP', - // target: rootState.key, - // }); - // } - // return; - // } - // } - - // if (action && 'payload' in action && action.payload && 'name' in action.payload && isSideModalNavigator(action.payload.name)) { - // // Information about the state may be in the params. - // const currentFocusedRoute = findFocusedRoute(extrapolateStateFromParams(rootState)); - // const targetFocusedRoute = findFocusedRoute(stateFromPath); - - // // If the current focused route is the same as the target focused route, we don't want to navigate. - // if ( - // currentFocusedRoute?.name === targetFocusedRoute?.name && - // shallowCompare(currentFocusedRoute?.params as Record, targetFocusedRoute?.params as Record) - // ) { - // return; - // } - - // const minimalAction = getMinimalAction(action, navigation.getRootState()); - // if (minimalAction) { - // // There are situations where a route already exists on the current navigation stack - // // But we want to push the same route instead of going back in the stack - // // Which would break the user navigation history - // if (!isActiveRoute && type === CONST.NAVIGATION.ACTION_TYPE.PUSH) { - // minimalAction.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - // } - // root.dispatch(minimalAction); - // return; - // } - // } - - // // When we navigate from the ReportScreen opened in RHP, this page shouldn't be removed from the navigation state to allow users to go back to it. - // if (isReportInRhpOpened && action) { - // action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - // } - - // if (action !== undefined) { - // root.dispatch(action); - // } else { - // root.reset(stateFromPath); - // } } From 49978c770451345167cd30efff5181f95db8e68b Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 18 Sep 2024 17:46:43 +0200 Subject: [PATCH 020/257] add setter to activeWorkspaceID context --- .../ActiveWorkspaceContext.tsx | 5 ++- .../ActiveWorkspaceProvider/index.tsx | 41 ++++++++++++------- src/components/Search/SearchPageHeader.tsx | 2 +- src/hooks/useActiveWorkspace.ts | 2 +- src/hooks/useReportIDs.tsx | 2 +- .../Navigation/AppNavigator/AuthScreens.tsx | 2 +- .../Navigators/ReportsSplitNavigator.tsx | 2 +- .../BottomTabBar.tsx | 2 +- .../CustomRouter.ts | 8 ++++ src/pages/WorkspaceSwitcherPage/index.tsx | 4 +- src/pages/home/ReportScreen.tsx | 2 +- src/pages/home/sidebar/SidebarLinksData.tsx | 2 +- .../SidebarScreen/BaseSidebarScreen.tsx | 2 +- src/pages/workspace/WorkspaceNewRoomPage.tsx | 2 +- src/pages/workspace/WorkspacesListPage.tsx | 2 +- 15 files changed, 52 insertions(+), 28 deletions(-) diff --git a/src/components/ActiveWorkspace/ActiveWorkspaceContext.tsx b/src/components/ActiveWorkspace/ActiveWorkspaceContext.tsx index 7908020d16d2..8e336a421b92 100644 --- a/src/components/ActiveWorkspace/ActiveWorkspaceContext.tsx +++ b/src/components/ActiveWorkspace/ActiveWorkspaceContext.tsx @@ -1,5 +1,8 @@ import {createContext} from 'react'; -const ActiveWorkspaceContext = createContext(undefined); +const ActiveWorkspaceContext = createContext<{activeWorkspaceID: string | undefined; setActiveWorkspaceID: (workspaceID: string | undefined) => void}>({ + activeWorkspaceID: undefined, + setActiveWorkspaceID: () => {}, +}); export default ActiveWorkspaceContext; diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index 011b58720d35..2f734909ec2d 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -1,5 +1,5 @@ import {useNavigationState} from '@react-navigation/native'; -import React, {useMemo} from 'react'; +import React, {useEffect, useMemo, useState} from 'react'; import ActiveWorkspaceContext from '@components/ActiveWorkspace/ActiveWorkspaceContext'; import * as SearchUtils from '@libs/SearchUtils'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -7,6 +7,8 @@ import SCREENS from '@src/SCREENS'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; function ActiveWorkspaceContextProvider({children}: ChildrenProps) { + const [activeWorkspaceID, setActiveWorkspaceID] = useState(undefined); + const lastPolicyRoute = useNavigationState((state) => state?.routes?.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.CENTRAL_PANE), ); @@ -14,22 +16,32 @@ function ActiveWorkspaceContextProvider({children}: ChildrenProps) { const policyIDFromRouteParam = lastPolicyRoute?.params && 'policyID' in lastPolicyRoute.params ? (lastPolicyRoute?.params?.policyID as string) : ''; const queryFromRouteParam = lastPolicyRoute?.params && 'q' in lastPolicyRoute.params ? (lastPolicyRoute.params.q as string) : ''; - const activeWorkspaceID = useMemo(() => { - if (policyIDFromRouteParam) { - return policyIDFromRouteParam; + useEffect(() => { + if (!policyIDFromRouteParam) { + return; } + setActiveWorkspaceID(policyIDFromRouteParam); + }, [policyIDFromRouteParam, setActiveWorkspaceID]); - if (queryFromRouteParam) { - const queryJSON = SearchUtils.buildSearchQueryJSON(queryFromRouteParam); - if (!queryJSON) { - return undefined; - } - - return SearchUtils.getPolicyIDFromSearchQuery(queryJSON); + useEffect(() => { + if (!queryFromRouteParam) { + return; } - return undefined; - }, [policyIDFromRouteParam, queryFromRouteParam]); + const queryJSON = SearchUtils.buildSearchQueryJSON(queryFromRouteParam); + if (!queryJSON) { + return undefined; + } + setActiveWorkspaceID(SearchUtils.getPolicyIDFromSearchQuery(queryJSON)); + }, [queryFromRouteParam]); + + const value = useMemo( + () => ({ + activeWorkspaceID, + setActiveWorkspaceID, + }), + [activeWorkspaceID, setActiveWorkspaceID], + ); // @TODO Remember to handle saving activeWorkspaceID in the session storage // const setActiveWorkspaceID = useCallback((workspaceID: string | undefined) => { @@ -41,7 +53,8 @@ function ActiveWorkspaceContextProvider({children}: ChildrenProps) { // } // }, []); - return {children}; + return {children}; } export default ActiveWorkspaceContextProvider; +export {}; diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index d2595f052db3..f50540346e6d 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -116,7 +116,7 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { const theme = useTheme(); const styles = useThemeStyles(); const {isOffline} = useNetwork(); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout(); const {selectedTransactions, clearSelectedTransactions, selectedReports} = useSearchContext(); const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE); diff --git a/src/hooks/useActiveWorkspace.ts b/src/hooks/useActiveWorkspace.ts index 11a986cdb053..568f1d73727c 100644 --- a/src/hooks/useActiveWorkspace.ts +++ b/src/hooks/useActiveWorkspace.ts @@ -1,7 +1,7 @@ import {useContext} from 'react'; import ActiveWorkspaceContext from '@components/ActiveWorkspace/ActiveWorkspaceContext'; -function useActiveWorkspace(): string { +function useActiveWorkspace(): {activeWorkspaceID: string | undefined; setActiveWorkspaceID: (workspaceID: string | undefined) => void} { return useContext(ActiveWorkspaceContext); } diff --git a/src/hooks/useReportIDs.tsx b/src/hooks/useReportIDs.tsx index d51d9e53c48c..b7d84cb25196 100644 --- a/src/hooks/useReportIDs.tsx +++ b/src/hooks/useReportIDs.tsx @@ -91,7 +91,7 @@ function ReportIDsContextProvider({ const {accountID} = useCurrentUserPersonalDetails(); const currentReportIDValue = useCurrentReportID(); const derivedCurrentReportID = currentReportIDForTests ?? currentReportIDValue?.currentReportID; - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const policyMemberAccountIDs = useMemo(() => getPolicyEmployeeListByIdWithoutCurrentUser(policies, activeWorkspaceID, accountID), [policies, activeWorkspaceID, accountID]); diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index bf008e8c131e..190b2872e973 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -237,7 +237,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie const {shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout(); const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); const {canUseDefaultRooms} = usePermissions(); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(onboardingIsMediumOrLargerScreenWidth), [screenOptions, onboardingIsMediumOrLargerScreenWidth]); const onboardingScreenOptions = useMemo( () => getOnboardingModalScreenOptions(shouldUseNarrowLayout, styles, StyleUtils, onboardingIsMediumOrLargerScreenWidth), diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index c52c97fef17a..2ad1d7a480c9 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -23,7 +23,7 @@ function shouldOpenOnAdminRoom() { function ReportsSplitNavigator() { const {canUseDefaultRooms} = usePermissions(); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); let initialReportID: string | undefined; const isInitialRender = useRef(true); diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 13c4d0e18b2d..accac709b6ea 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -64,7 +64,7 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { const theme = useTheme(); const styles = useThemeStyles(); const {translate} = useLocalize(); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const transactionViolations = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS); const [chatTabBrickRoad, setChatTabBrickRoad] = useState(getChatTabBrickRoad(activeWorkspaceID)); diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index db56bad402e3..21f684923f7e 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -1,6 +1,7 @@ import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; import {findFocusedRoute, getPathFromState, StackActions, StackRouter} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/routers'; +import useActiveWorkspace from '@hooks/useActiveWorkspace'; import * as Localize from '@libs/Localize'; import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; import isSideModalNavigator from '@libs/Navigation/isSideModalNavigator'; @@ -62,6 +63,7 @@ type CustomRootStackActionType = { function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { const stackRouter = StackRouter(options); + const {setActiveWorkspaceID} = useActiveWorkspace(); // @TODO: Make sure that everything works fine without compareAndAdaptState function return { @@ -75,15 +77,19 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { if (!queryJSON) { return null; } + if (action.payload.policyID) { queryJSON.policyID = action.payload.policyID; } else { delete queryJSON.policyID; } + const newAction = StackActions.push(SCREENS.SEARCH.CENTRAL_PANE, { ...currentParams, q: SearchUtils.buildSearchQueryString(queryJSON), }); + + setActiveWorkspaceID(action.payload.policyID); return stackRouter.getStateForAction(state, newAction, configOptions); } if (lastRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { @@ -101,6 +107,8 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { return stackRouter.getStateForAction(state, newAction, configOptions); } const newAction = StackActions.push(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, {policyID: action.payload.policyID}); + + setActiveWorkspaceID(action.payload.policyID); return stackRouter.getStateForAction(state, newAction, configOptions); } // We don't have other navigators that should handle switch policy action. diff --git a/src/pages/WorkspaceSwitcherPage/index.tsx b/src/pages/WorkspaceSwitcherPage/index.tsx index bb74a8852880..27a5321c1dd3 100644 --- a/src/pages/WorkspaceSwitcherPage/index.tsx +++ b/src/pages/WorkspaceSwitcherPage/index.tsx @@ -14,7 +14,7 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; +import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import {sortWorkspacesBySelected} from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -41,7 +41,7 @@ function WorkspaceSwitcherPage() { const {isOffline} = useNetwork(); const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); const {translate} = useLocalize(); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS); diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 00a672083214..47704002774d 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -109,7 +109,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro const reactionListRef = useRef(null); const {isOffline} = useNetwork(); const {shouldUseNarrowLayout, isInNarrowPaneModal} = useResponsiveLayout(); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const [modal] = useOnyx(ONYXKEYS.MODAL); const [isComposerFullSize] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_IS_COMPOSER_FULL_SIZE}${reportIDFromRoute}`, {initialValue: false}); const [accountManagerReportID] = useOnyx(ONYXKEYS.ACCOUNT_MANAGER_REPORT_ID, {initialValue: ''}); diff --git a/src/pages/home/sidebar/SidebarLinksData.tsx b/src/pages/home/sidebar/SidebarLinksData.tsx index d83b4758ce52..5b7faa9a20b2 100644 --- a/src/pages/home/sidebar/SidebarLinksData.tsx +++ b/src/pages/home/sidebar/SidebarLinksData.tsx @@ -34,7 +34,7 @@ type SidebarLinksDataProps = SidebarLinksDataOnyxProps & { function SidebarLinksData({insets, isLoadingApp = true, onLinkClick, priorityMode = CONST.PRIORITY_MODE.DEFAULT}: SidebarLinksDataProps) { const isFocused = useIsFocused(); const styles = useThemeStyles(); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const {translate} = useLocalize(); const {orderedReportIDs, currentReportID, policyMemberAccountIDs} = useReportIDs(); diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx index 08ce4a7df94d..e48b27ad67c7 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx @@ -27,7 +27,7 @@ const startTimer = () => { function BaseSidebarScreen() { const styles = useThemeStyles(); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const {translate} = useLocalize(); const [activeWorkspace] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activeWorkspaceID ?? -1}`); diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 28a1e9ad4a7a..481fc6c41402 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -55,7 +55,7 @@ function WorkspaceNewRoomPage() { const wasLoading = usePrevious(!!formState?.isLoading); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); const {isLoading = false, errorFields = {}} = formState ?? {}; - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const activeWorkspaceOrDefaultID = activeWorkspaceID ?? activePolicyID; diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 9cae9344c75b..03e31f1f1d76 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -115,7 +115,7 @@ function WorkspacesListPage() { const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); const [session] = useOnyx(ONYXKEYS.SESSION); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [policyIDToDelete, setPolicyIDToDelete] = useState(); From b39663e9337a04ff14b74c1b7ac5340bed55bf53 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 19 Sep 2024 12:53:06 +0200 Subject: [PATCH 021/257] Fix LHN paddings --- src/pages/Search/SearchPageBottomTab.tsx | 1 - src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx | 4 +--- src/pages/settings/InitialSettingsPage.tsx | 7 +++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/pages/Search/SearchPageBottomTab.tsx b/src/pages/Search/SearchPageBottomTab.tsx index ed9e5e0b8e92..5bfcae9e5c27 100644 --- a/src/pages/Search/SearchPageBottomTab.tsx +++ b/src/pages/Search/SearchPageBottomTab.tsx @@ -86,7 +86,6 @@ function SearchPageBottomTab({queryJSON, policyID, searchName}: SearchPageBottom return ( {!selectionMode?.isEnabled ? ( diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx index e48b27ad67c7..8b9e6103a1a9 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx @@ -47,11 +47,9 @@ function BaseSidebarScreen() { return ( {({insets}) => ( <> diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 9992230127b9..6652f4fc118f 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -401,9 +401,8 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr return ( {headerContent} @@ -413,7 +412,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr scrollEventThrottle={16} contentContainerStyle={[styles.w100]} showsVerticalScrollIndicator={false} - > + > {accountMenuItems} {workspaceMenuItems} {generalMenuItems} From 82fe6400e66085af135fa8ca8a35336d05f24e3e Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 19 Sep 2024 14:22:34 +0200 Subject: [PATCH 022/257] Refactor ActiveWorkspaceProvider useEffect --- .../ActiveWorkspaceProvider/index.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index 2f734909ec2d..d306226a85c2 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -17,23 +17,23 @@ function ActiveWorkspaceContextProvider({children}: ChildrenProps) { const queryFromRouteParam = lastPolicyRoute?.params && 'q' in lastPolicyRoute.params ? (lastPolicyRoute.params.q as string) : ''; useEffect(() => { - if (!policyIDFromRouteParam) { + if (policyIDFromRouteParam) { + setActiveWorkspaceID(policyIDFromRouteParam); return; } - setActiveWorkspaceID(policyIDFromRouteParam); - }, [policyIDFromRouteParam, setActiveWorkspaceID]); - useEffect(() => { - if (!queryFromRouteParam) { + if (queryFromRouteParam) { + const queryJSON = SearchUtils.buildSearchQueryJSON(queryFromRouteParam); + if (!queryJSON) { + setActiveWorkspaceID(undefined); + return; + } + setActiveWorkspaceID(SearchUtils.getPolicyIDFromSearchQuery(queryJSON)); return; } - const queryJSON = SearchUtils.buildSearchQueryJSON(queryFromRouteParam); - if (!queryJSON) { - return undefined; - } - setActiveWorkspaceID(SearchUtils.getPolicyIDFromSearchQuery(queryJSON)); - }, [queryFromRouteParam]); + setActiveWorkspaceID(undefined); + }, [policyIDFromRouteParam, queryFromRouteParam, setActiveWorkspaceID]); const value = useMemo( () => ({ From 9e5e6e34c6fe1d6c78670a7b66aed0464f0cc9ba Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 20 Sep 2024 12:05:31 +0200 Subject: [PATCH 023/257] Add navigateToReportWithPolicyCheck --- .../CustomRouter.ts | 67 ++++++++++------ src/libs/Navigation/Navigation.ts | 77 ++++++++++++++----- .../subscribePushNotification/index.ts | 9 +-- src/libs/actions/Report.ts | 13 +--- src/pages/ChatFinderPage/index.tsx | 2 +- src/pages/WorkspaceSwitcherPage/index.tsx | 2 +- src/pages/workspace/WorkspaceProfilePage.tsx | 2 +- src/pages/workspace/WorkspacesListPage.tsx | 2 +- 8 files changed, 106 insertions(+), 68 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 21f684923f7e..ab376ec4c45d 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -3,6 +3,7 @@ import {findFocusedRoute, getPathFromState, StackActions, StackRouter} from '@re import type {ParamListBase} from '@react-navigation/routers'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import * as Localize from '@libs/Localize'; +import Log from '@libs/Log'; import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; import isSideModalNavigator from '@libs/Navigation/isSideModalNavigator'; import linkingConfig from '@libs/Navigation/linkingConfig'; @@ -49,17 +50,14 @@ function shouldDismissSideModalNavigator(state: StackNavigationState); + const haveParamsPolicyID = action.payload.params && 'policyID' in action.payload.params; + let policyID; + + if (haveParamsPolicyID) { + policyID = (action.payload.params as Record)?.policyID; + setActiveWorkspaceID(policyID); + } else { + policyID = getPolicyIDFromState(state as State); + } const modifiedAction = { ...action, diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index cd0016b757b3..f20f27be1df9 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -4,6 +4,7 @@ import {CommonActions, getPathFromState, StackActions} from '@react-navigation/n import type {OnyxEntry} from 'react-native-onyx'; import Log from '@libs/Log'; import {isCentralPaneName, removePolicyIDParamFromState} from '@libs/NavigationUtils'; +import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils'; import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; @@ -11,11 +12,11 @@ import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import type {HybridAppRoute, Route} from '@src/ROUTES'; import ROUTES, {HYBRID_APP_ROUTES} from '@src/ROUTES'; -import {PROTECTED_SCREENS} from '@src/SCREENS'; +import SCREENS, {PROTECTED_SCREENS} from '@src/SCREENS'; import type {Report} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import originalCloseRHPFlow from './closeRHPFlow'; -import originalDismissModal from './dismissModal'; -import originalDismissModalWithReport from './dismissModalWithReport'; +import getPolicyIDFromState from './getPolicyIDFromState'; import getTopmostBottomTabRoute from './getTopmostBottomTabRoute'; import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute'; import originalGetTopmostReportActionId from './getTopmostReportActionID'; @@ -58,22 +59,12 @@ const getTopmostReportId = (state = navigationRef.getState()) => originalGetTopm // Re-exporting the getTopmostReportActionID here to fill in default value for state. The getTopmostReportActionID isn't defined in this file to avoid cyclic dependencies. const getTopmostReportActionId = (state = navigationRef.getState()) => originalGetTopmostReportActionId(state); -// Re-exporting the dismissModal here to fill in default value for navigationRef. The dismissModal isn't defined in this file to avoid cyclic dependencies. -const dismissModal = (reportID?: string, ref = navigationRef) => { - if (!reportID) { - originalDismissModal(ref); - return; - } - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - originalDismissModalWithReport({reportID, ...report}, ref); -}; // Re-exporting the closeRHPFlow here to fill in default value for navigationRef. The closeRHPFlow isn't defined in this file to avoid cyclic dependencies. const closeRHPFlow = (ref = navigationRef) => originalCloseRHPFlow(ref); // Re-exporting the dismissModalWithReport here to fill in default value for navigationRef. The dismissModalWithReport isn't defined in this file to avoid cyclic dependencies. // This method is needed because it allows to dismiss the modal and then open the report. Within this method is checked whether the report belongs to a specific workspace. Sometimes the report we want to check, hasn't been added to the Onyx yet. // Then we can pass the report as a param without getting it from the Onyx. -const dismissModalWithReport = (report: OnyxEntry, ref = navigationRef) => originalDismissModalWithReport(report, ref); /** Method for finding on which index in stack we are. */ function getActiveRouteIndex(stateOrRoute: StateOrRoute, index?: number): number | undefined { @@ -432,17 +423,60 @@ function getTopMostCentralPaneRouteFromRootState() { return getTopmostCentralPaneRoute(navigationRef.getRootState() as State); } -type SwitchPolicyIDPayload = { - policyID?: string; - reportID?: number; - reportActionID?: string; - referrer?: string; -}; +function switchPolicyID(policyID?: string) { + navigationRef.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID, payload: {policyID}}); +} + +type NavigateToReportWithPolicyCheckPayload = {report?: OnyxEntry; reportID?: string; reportActionID?: string; referrer?: string; policyIDToCheck?: string}; + +function navigateToReportWithPolicyCheck({report, reportID, reportActionID, referrer, policyIDToCheck}: NavigateToReportWithPolicyCheckPayload, ref = navigationRef) { + const targetReport = reportID ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] : report; + if (!targetReport) { + return; + } + + const policyID = policyIDToCheck ?? getPolicyIDFromState(navigationRef.getRootState() as State); + const policyMemberAccountIDs = getPolicyEmployeeAccountIDs(policyID); + const shouldOpenAllWorkspace = isEmptyObject(targetReport) ? true : !ReportUtils.doesReportBelongToWorkspace(targetReport, policyMemberAccountIDs, policyID); + + if ((shouldOpenAllWorkspace && !policyID) || !shouldOpenAllWorkspace) { + linkTo(ref.current, ROUTES.REPORT_WITH_ID.getRoute(targetReport.reportID, reportActionID, referrer)); + return; + } + + const params: Record = { + reportID: targetReport.reportID, + }; + + if (reportActionID) { + params.reportActionID = reportActionID; + } -function switchPolicyID(payload: SwitchPolicyIDPayload) { - navigationRef.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID, payload}); + if (referrer) { + params.referrer = referrer; + } + + ref.dispatch({ + ...StackActions.push(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, { + policyID: null, + screen: SCREENS.REPORT, + params, + }), + }); } +const dismissModal = (reportID?: string, ref = navigationRef) => { + ref.dispatch({type: 'DISMISS_MODAL'}); + if (!reportID) { + return; + } + navigateToReportWithPolicyCheck({reportID}); +}; +const dismissModalWithReport = (report: OnyxEntry) => { + dismissModal(); + navigateToReportWithPolicyCheck({report}); +}; + export default { setShouldPopAllStateOnUP, navigate, @@ -467,6 +501,7 @@ export default { closeRHPFlow, setNavigationActionToMicrotaskQueue, getTopMostCentralPaneRouteFromRootState, + navigateToReportWithPolicyCheck, }; export {navigationRef}; diff --git a/src/libs/Notification/PushNotification/subscribePushNotification/index.ts b/src/libs/Notification/PushNotification/subscribePushNotification/index.ts index b4563e12ac8d..ad162523b2c6 100644 --- a/src/libs/Notification/PushNotification/subscribePushNotification/index.ts +++ b/src/libs/Notification/PushNotification/subscribePushNotification/index.ts @@ -76,9 +76,6 @@ function navigateToReport({reportID, reportActionID}: ReportActionPushNotificati Log.info('[PushNotification] Navigating to report', false, {reportID, reportActionID}); const policyID = lastVisitedPath && extractPolicyIDFromPath(lastVisitedPath); - const report = ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; - const policyEmployeeAccountIDs = policyID ? getPolicyEmployeeAccountIDs(policyID) : []; - const reportBelongsToWorkspace = policyID && !isEmptyObject(report) && doesReportBelongToWorkspace(report, policyEmployeeAccountIDs, policyID); Navigation.isNavigationReady() .then(Navigation.waitForProtectedRoutes) @@ -96,11 +93,7 @@ function navigateToReport({reportID, reportActionID}: ReportActionPushNotificati } Log.info('[PushNotification] onSelected() - Navigation is ready. Navigating...', false, {reportID, reportActionID}); - if (!reportBelongsToWorkspace) { - Navigation.switchPolicyID({policyID, reportID}); - } else { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(String(reportID))); - } + Navigation.navigateToReportWithPolicyCheck({reportID, policyIDToCheck: policyID}); } catch (error) { let errorMessage = String(error); if (error instanceof Error) { diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 482fdcd9638f..67831346f4d3 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1045,10 +1045,9 @@ function navigateToAndOpenReport( // We want to pass newChat here because if anything is passed in that param (even an existing chat), we will try to create a chat on the server openReport(report?.reportID ?? '', '', userLogins, newChat, undefined, undefined, undefined, avatarFile); if (shouldDismissModal) { - Navigation.dismissModalWithReport(report); - } else { - Navigation.switchPolicyID({policyID: undefined, reportID: report?.reportID ?? '-1'}); + Navigation.dismissModal(); } + Navigation.navigateToReportWithPolicyCheck({report}); } /** @@ -2488,13 +2487,7 @@ function showReportActionNotification(reportID: string, reportAction: ReportActi const onClick = () => Modal.close(() => { const policyID = lastVisitedPath && extractPolicyIDFromPath(lastVisitedPath); - const policyEmployeeAccountIDs = policyID ? getPolicyEmployeeAccountIDs(policyID) : []; - const reportBelongsToWorkspace = policyID ? doesReportBelongToWorkspace(report, policyEmployeeAccountIDs, policyID) : false; - if (!reportBelongsToWorkspace) { - Navigation.switchPolicyID({policyID: undefined, reportID, referrer: CONST.REFERRER.NOTIFICATION}); - return; - } - navigateFromNotification(reportID); + Navigation.navigateToReportWithPolicyCheck({reportID, referrer: CONST.REFERRER.NOTIFICATION, policyIDToCheck: policyID}); }); if (reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE) { diff --git a/src/pages/ChatFinderPage/index.tsx b/src/pages/ChatFinderPage/index.tsx index aabf881a8bed..b18917e20b40 100644 --- a/src/pages/ChatFinderPage/index.tsx +++ b/src/pages/ChatFinderPage/index.tsx @@ -152,7 +152,7 @@ function ChatFinderPage({betas, isSearchingForReports, navigation}: ChatFinderPa } if (option.reportID) { - Navigation.closeAndNavigate(ROUTES.REPORT_WITH_ID.getRoute(option.reportID)); + Navigation.dismissModal(option.reportID); } else { Report.navigateToAndOpenReport(option.login ? [option.login] : []); } diff --git a/src/pages/WorkspaceSwitcherPage/index.tsx b/src/pages/WorkspaceSwitcherPage/index.tsx index 27a5321c1dd3..9eaee40853c3 100644 --- a/src/pages/WorkspaceSwitcherPage/index.tsx +++ b/src/pages/WorkspaceSwitcherPage/index.tsx @@ -92,7 +92,7 @@ function WorkspaceSwitcherPage() { Navigation.goBack(); if (policyID !== activeWorkspaceID) { - Navigation.switchPolicyID({policyID}); + Navigation.switchPolicyID(policyID); } }, [activeWorkspaceID], diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index a5d295f379a2..4c26e82c08c5 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -136,7 +136,7 @@ function WorkspaceProfilePage({policyDraft, policy: policyProp, currencyList = { // If the workspace being deleted is the active workspace, switch to the "All Workspaces" view if (activeWorkspaceID === policy?.id) { - Navigation.switchPolicyID({policyID: undefined}); + Navigation.switchPolicyID(undefined); } }, [policy?.id, policyName, activeWorkspaceID]); diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 03e31f1f1d76..a29e17ef61d2 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -132,7 +132,7 @@ function WorkspacesListPage() { // If the workspace being deleted is the active workspace, switch to the "All Workspaces" view if (activeWorkspaceID === policyIDToDelete) { - Navigation.switchPolicyID({policyID: undefined}); + Navigation.switchPolicyID(undefined); } }; From 578f6f356e5ad706d11064de6016ad245df5a81f Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 20 Sep 2024 13:38:10 +0200 Subject: [PATCH 024/257] Add MODAL_ROUTES_TO_DISMISS --- .../CustomRouter.ts | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index ab376ec4c45d..c0fddeaef940 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -16,6 +16,21 @@ import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import type {ResponsiveStackNavigatorRouterOptions} from './types'; +const MODAL_ROUTES_TO_DISMISS: string[] = [ + NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, + NAVIGATORS.LEFT_MODAL_NAVIGATOR, + NAVIGATORS.RIGHT_MODAL_NAVIGATOR, + NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR, + NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR, + SCREENS.NOT_FOUND, + SCREENS.ATTACHMENTS, + SCREENS.TRANSACTION_RECEIPT, + SCREENS.PROFILE_AVATAR, + SCREENS.WORKSPACE_AVATAR, + SCREENS.REPORT_AVATAR, + SCREENS.CONCIERGE, +]; + function shouldPreventReset(state: StackNavigationState, action: CommonActions.Action | StackActionType) { if (action.type !== CONST.NAVIGATION_ACTIONS.RESET || !action?.payload) { return false; @@ -103,25 +118,13 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { if (action.type === 'DISMISS_MODAL') { const lastRoute = state.routes.at(-1); const newAction = StackActions.pop(); - switch (lastRoute?.name) { - case NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR: - case NAVIGATORS.LEFT_MODAL_NAVIGATOR: - case NAVIGATORS.RIGHT_MODAL_NAVIGATOR: - case NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR: - case NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR: - case SCREENS.NOT_FOUND: - case SCREENS.ATTACHMENTS: - case SCREENS.TRANSACTION_RECEIPT: - case SCREENS.PROFILE_AVATAR: - case SCREENS.WORKSPACE_AVATAR: - case SCREENS.REPORT_AVATAR: - case SCREENS.CONCIERGE: - return stackRouter.getStateForAction(state, newAction, configOptions); - default: { - Log.hmmm('[Navigation] dismissModal failed because there is no modal stack to dismiss'); - } + + if (!lastRoute?.name || !MODAL_ROUTES_TO_DISMISS.includes(lastRoute?.name)) { + Log.hmmm('[Navigation] dismissModal failed because there is no modal stack to dismiss'); + return; } - return; + + return stackRouter.getStateForAction(state, newAction, configOptions); } // Don't let the user navigate back to a non-onboarding screen if they are currently on an onboarding screen and it's not finished. From 4fabb15fa19ea75d909359b99225add44c013458 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 20 Sep 2024 13:39:21 +0200 Subject: [PATCH 025/257] Refactor navigateToReportWithPolicyCheck --- src/libs/Navigation/Navigation.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index f20f27be1df9..b95fe2a7e32a 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -456,13 +456,13 @@ function navigateToReportWithPolicyCheck({report, reportID, reportActionID, refe params.referrer = referrer; } - ref.dispatch({ - ...StackActions.push(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, { + ref.dispatch( + StackActions.push(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, { policyID: null, screen: SCREENS.REPORT, params, }), - }); + ); } const dismissModal = (reportID?: string, ref = navigationRef) => { From 5ccfdeecc2808933b925b06644e89e3faa09710e Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 20 Sep 2024 15:20:52 +0200 Subject: [PATCH 026/257] remember state between tabs --- src/libs/Navigation/newLinkTo/index.ts | 6 ++-- src/pages/home/sidebar/BottomTabAvatar.tsx | 36 ++++++++++++++++++-- src/pages/workspace/WorkspaceInitialPage.tsx | 18 +++++++--- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/libs/Navigation/newLinkTo/index.ts b/src/libs/Navigation/newLinkTo/index.ts index e19f02687f1c..f8ac74d6e61f 100644 --- a/src/libs/Navigation/newLinkTo/index.ts +++ b/src/libs/Navigation/newLinkTo/index.ts @@ -24,7 +24,7 @@ function shouldDispatchAction(currentState: NavigationState, return true; } -export default function linkTo(navigation: NavigationContainerRef | null, path: Route) { +export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: typeof CONST.NAVIGATION.ACTION_TYPE.REPLACE) { if (!navigation) { throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); } @@ -49,7 +49,9 @@ export default function linkTo(navigation: NavigationContainerRef Navigation.navigate(ROUTES.SETTINGS)); + interceptAnonymousUser(() => { + const rootState = navigationRef.getRootState(); + const lastSettingsOrWorkspaceNavigatorRoute = rootState.routes.findLast( + (rootRoute) => rootRoute.name === NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR || rootRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, + ); + + // If there is a workspace navigator route, then we should open the workspace initial screen as it should be "remembered". + if (lastSettingsOrWorkspaceNavigatorRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { + const params = lastSettingsOrWorkspaceNavigatorRoute.params as AuthScreensParamList[typeof NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]; + + // Screens of this navigator should always have policyID + if ('params' in params && params.params?.policyID) { + Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(params.params.policyID)); + } + return; + } + + // If there is settings workspace screen in the settings navigator, then we should open the settings workspaces as it should be "remembered". + if ( + lastSettingsOrWorkspaceNavigatorRoute && + lastSettingsOrWorkspaceNavigatorRoute.state && + lastSettingsOrWorkspaceNavigatorRoute.state.routes.at(-1)?.name === SCREENS.SETTINGS.WORKSPACES + ) { + Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); + return; + } + + // Otherwise we should simply open the settings navigator. + // This case also covers if there is no route to remember. + Navigation.navigate(ROUTES.SETTINGS); + }); }, [isCreateMenuOpen, shouldUseNarrowLayout, route.name]); let children; diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index f7d45d277cd7..1644fdac1abc 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -24,14 +24,15 @@ import {isConnectionInProgress} from '@libs/actions/connections'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import getTopmostRouteName from '@libs/Navigation/getTopmostRouteName'; -import Navigation from '@libs/Navigation/Navigation'; +import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; -import type {WorkspaceNavigatorParamList} from '@navigation/types'; import * as Policy from '@userActions/Policy/Policy'; import * as ReimbursementAccount from '@userActions/ReimbursementAccount'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; +import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; @@ -67,7 +68,7 @@ type WorkspaceMenuItem = { badgeText?: string; }; -type WorkspaceInitialPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +type WorkspaceInitialPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; type PolicyFeatureStates = Record; @@ -378,7 +379,16 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac Navigation.resetToHome(); Navigation.isNavigationReady().then(() => Navigation.navigate(route.params?.backTo as Route)); } else { - Navigation.dismissModal(); + // @TODO This part could be done with the new goBack method when it will be implemented. + const previousRoute = navigationRef.getRootState().routes.at(-2); + + // If there is the settings split navigator we can dismiss safely + if (previousRoute?.name === NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR) { + Navigation.dismissModal(); + } else { + // If not, we are going to replace this route with the settings route + Navigation.navigate(ROUTES.SETTINGS_WORKSPACES, CONST.NAVIGATION.ACTION_TYPE.REPLACE); + } } }} policyAvatar={policyAvatar} From 6336d7f9a64c7b4a0c7473941639f962377e67f0 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 20 Sep 2024 15:53:02 +0200 Subject: [PATCH 027/257] Disable animation for settings workspaces screen --- .../Navigators/SettingsSplitNavigator.tsx | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx index 62a1af45f10b..f912c3f5a225 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx @@ -1,10 +1,14 @@ import React from 'react'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useStyleUtils from '@hooks/useStyleUtils'; +import useThemeStyles from '@hooks/useThemeStyles'; import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; import type {SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; import withPrepareCentralPaneScreen from '@src/components/withPrepareCentralPaneScreen'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; +import getRootNavigatorScreenOptions from '../getRootNavigatorScreenOptions'; const loadInitialSettingsPage = () => require('../../../../pages/settings/InitialSettingsPage').default; @@ -25,6 +29,11 @@ const CENTRAL_PANE_SETTINGS_SCREENS = { const Stack = createSplitStackNavigator(); function SettingsSplitNavigator() { + const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); + const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); + return ( - {Object.entries(CENTRAL_PANE_SETTINGS_SCREENS).map(([screenName, componentGetter]) => ( - - ))} + {Object.entries(CENTRAL_PANE_SETTINGS_SCREENS).map(([screenName, componentGetter]) => { + const options = {...screenOptions.centralPaneNavigator}; + + if (screenName === SCREENS.SETTINGS.WORKSPACES) { + options.animationEnabled = false; + } + + return ( + + ); + })} ); From 7e483b73f87e9594854f2d5a355f4ff53aacbb64 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 23 Sep 2024 07:34:05 +0200 Subject: [PATCH 028/257] Handle deeplinking to report with policyID in URL --- .../linkingConfig/getAdaptedStateFromPath.ts | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 15ecf12a3dea..ae47b8e0685e 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -137,7 +137,8 @@ function getAdaptedState(state: PartialState // }; // We need to check what is defined to know what we need to add. - const WorkspaceNavigator = state.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR); + const workspaceNavigator = state.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR); + const reportNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); const rhpNavigator = state.routes.find((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR); const lhpNavigator = state.routes.find((route) => route.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR); const onboardingModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR); @@ -223,7 +224,7 @@ function getAdaptedState(state: PartialState adaptedState: getRoutesWithIndex(routes), }; } - if (WorkspaceNavigator) { + if (workspaceNavigator) { // Routes // - default bottom tab // - default central pane on desktop layout @@ -242,7 +243,7 @@ function getAdaptedState(state: PartialState ), ); - routes.push(WorkspaceNavigator); + routes.push(workspaceNavigator); return { adaptedState: getRoutesWithIndex(routes), @@ -275,6 +276,19 @@ function getAdaptedState(state: PartialState } // We need to make sure that this if only handles states where we deeplink to the bottom tab directly + + // If policyID is defined, it should be passed to the reportNavigator params. + if (reportNavigator && policyID) { + const routes = []; + const reportNavigatorWithPolicyID = {...reportNavigator}; + reportNavigatorWithPolicyID.params = {...reportNavigatorWithPolicyID.params, policyID}; + routes.push(reportNavigatorWithPolicyID); + + return { + adaptedState: getRoutesWithIndex(routes), + }; + } + return { adaptedState: state, }; From 82d6df1f59ad2cda749bad01e7250beea8736b7f Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 24 Sep 2024 07:12:01 +0200 Subject: [PATCH 029/257] Test freezing split navigators --- .../withPrepareCentralPaneScreen/index.tsx | 3 ++- .../Navigation/AppNavigator/AuthScreens.tsx | 7 ++++--- .../Navigators/SettingsSplitNavigator.tsx | 19 +++++++++--------- .../createCustomStackNavigator/index.tsx | 20 +++++++++---------- .../Navigation/FreezeWrapper/index.native.tsx | 5 ++++- src/libs/Navigation/NavigationRoot.tsx | 2 ++ 6 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/components/withPrepareCentralPaneScreen/index.tsx b/src/components/withPrepareCentralPaneScreen/index.tsx index f53368188b3d..84ba31cd63fd 100644 --- a/src/components/withPrepareCentralPaneScreen/index.tsx +++ b/src/components/withPrepareCentralPaneScreen/index.tsx @@ -1,9 +1,10 @@ import type React from 'react'; +import freezeScreenWithLazyLoading from '@libs/freezeScreenWithLazyLoading'; /** * This higher-order function is dependent on the platform. On native platforms, screens that aren't already displayed in the navigation stack should be frozen to prevent unnecessary rendering. * It's handled this way only on mobile platforms because on the web, more than one screen is displayed in a wide layout, so these screens shouldn't be frozen. */ export default function withPrepareCentralPaneScreen(lazyComponent: () => React.ComponentType) { - return lazyComponent; + return freezeScreenWithLazyLoading(lazyComponent); } diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 190b2872e973..42419b46e637 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -9,6 +9,7 @@ import ComposeProviders from '@components/ComposeProviders'; import OptionsListContextProvider from '@components/OptionListContextProvider'; import {SearchContextProvider} from '@components/Search/SearchContext'; import SearchRouterModal from '@components/Search/SearchRouter/SearchRouterModal'; +import withPrepareCentralPaneScreen from '@components/withPrepareCentralPaneScreen'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useOnboardingFlowRouter from '@hooks/useOnboardingFlow'; import usePermissions from '@hooks/usePermissions'; @@ -429,17 +430,17 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie ReportsSplitNavigator)} /> SettingsSplitNavigator)} /> SearchPage)} initialParams={{q: buildSearchQueryString()}} /> require('../../../.. type Screens = Partial React.ComponentType>>; const CENTRAL_PANE_SETTINGS_SCREENS = { - [SCREENS.SETTINGS.WORKSPACES]: withPrepareCentralPaneScreen(() => require('../../../../pages/workspace/WorkspacesListPage').default), - [SCREENS.SETTINGS.PREFERENCES.ROOT]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/Preferences/PreferencesPage').default), - [SCREENS.SETTINGS.SECURITY]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/Security/SecuritySettingsPage').default), - [SCREENS.SETTINGS.PROFILE.ROOT]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/Profile/ProfilePage').default), - [SCREENS.SETTINGS.WALLET.ROOT]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/Wallet/WalletPage').default), - [SCREENS.SETTINGS.ABOUT]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/AboutPage/AboutPage').default), - [SCREENS.SETTINGS.TROUBLESHOOT]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/Troubleshoot/TroubleshootPage').default), - [SCREENS.SETTINGS.SAVE_THE_WORLD]: withPrepareCentralPaneScreen(() => require('../../../../pages/TeachersUnite/SaveTheWorldPage').default), - [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: withPrepareCentralPaneScreen(() => require('../../../../pages/settings/Subscription/SubscriptionSettingsPage').default), + [SCREENS.SETTINGS.WORKSPACES]: () => require('../../../../pages/workspace/WorkspacesListPage').default, + [SCREENS.SETTINGS.PREFERENCES.ROOT]: () => require('../../../../pages/settings/Preferences/PreferencesPage').default, + [SCREENS.SETTINGS.SECURITY]: () => require('../../../../pages/settings/Security/SecuritySettingsPage').default, + [SCREENS.SETTINGS.PROFILE.ROOT]: () => require('../../../../pages/settings/Profile/ProfilePage').default, + [SCREENS.SETTINGS.WALLET.ROOT]: () => require('../../../../pages/settings/Wallet/WalletPage').default, + [SCREENS.SETTINGS.ABOUT]: () => require('../../../../pages/settings/AboutPage/AboutPage').default, + [SCREENS.SETTINGS.TROUBLESHOOT]: () => require('../../../../pages/settings/Troubleshoot/TroubleshootPage').default, + [SCREENS.SETTINGS.SAVE_THE_WORLD]: () => require('../../../../pages/TeachersUnite/SaveTheWorldPage').default, + [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: () => require('../../../../pages/settings/Subscription/SubscriptionSettingsPage').default, } satisfies Screens; const Stack = createSplitStackNavigator(); diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx index af4407af6dc2..a5aa8552179f 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx @@ -2,7 +2,7 @@ import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@rea import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; import {StackView} from '@react-navigation/stack'; -import React, {useMemo} from 'react'; +import React from 'react'; import CustomRouter from './CustomRouter'; import type {ResponsiveStackNavigatorProps, ResponsiveStackNavigatorRouterOptions} from './types'; @@ -20,21 +20,21 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { initialRouteName: props.initialRouteName, }); - const stateToRender = useMemo(() => { - const routes = state.routes.slice(-3); - return { - ...state, - routes, - index: routes.length - 1, - }; - }, [state]); + // const stateToRender = useMemo(() => { + // const routes = state.routes.slice(-3); + // return { + // ...state, + // routes, + // index: routes.length - 1, + // }; + // }, [state]); return ( diff --git a/src/libs/Navigation/FreezeWrapper/index.native.tsx b/src/libs/Navigation/FreezeWrapper/index.native.tsx index b071a065bd31..219a3c24e4e3 100644 --- a/src/libs/Navigation/FreezeWrapper/index.native.tsx +++ b/src/libs/Navigation/FreezeWrapper/index.native.tsx @@ -16,7 +16,7 @@ function FreezeWrapper({keepVisible = false, children}: FreezeWrapperProps) { const isFocused = useIsFocused(); const navigation = useNavigation(); const currentRoute = useRoute(); - + console.log('currentRoute', currentRoute); useEffect(() => { const index = navigation.getState()?.routes.findIndex((route) => route.key === currentRoute.key) ?? 0; screenIndexRef.current = index; @@ -26,6 +26,9 @@ function FreezeWrapper({keepVisible = false, children}: FreezeWrapperProps) { useEffect(() => { const unsubscribe = navigation.addListener('state', () => { const navigationIndex = (navigation.getState()?.index ?? 0) - (screenIndexRef.current ?? 0); + if (shouldSetScreenBlurred(navigationIndex)) { + console.log('diff', navigation.getState()?.index ?? 0, screenIndexRef.current ?? 0); + } setIsScreenBlurred(shouldSetScreenBlurred(navigationIndex)); }); return () => unsubscribe(); diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 124e0ed541d6..99a38d8d0bf2 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -165,6 +165,8 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh // We want to clean saved scroll offsets for screens that aren't anymore in the state. cleanStaleScrollOffsets(state); + + console.log('state', state); }; return ( From d2ba718681e2b4c9bb4ef0b70c684582cd8caae3 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 24 Sep 2024 13:13:46 +0200 Subject: [PATCH 030/257] Remove state listener from FreezeWrapper --- .../index.native.tsx | 10 ---------- .../Navigation/FreezeWrapper/index.native.tsx | 16 ++-------------- .../shouldSetScreenBlurred/index.native.tsx | 12 ------------ .../Navigation/shouldSetScreenBlurred/index.tsx | 2 +- 4 files changed, 3 insertions(+), 37 deletions(-) delete mode 100644 src/components/withPrepareCentralPaneScreen/index.native.tsx delete mode 100644 src/libs/Navigation/shouldSetScreenBlurred/index.native.tsx diff --git a/src/components/withPrepareCentralPaneScreen/index.native.tsx b/src/components/withPrepareCentralPaneScreen/index.native.tsx deleted file mode 100644 index 84ba31cd63fd..000000000000 --- a/src/components/withPrepareCentralPaneScreen/index.native.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import type React from 'react'; -import freezeScreenWithLazyLoading from '@libs/freezeScreenWithLazyLoading'; - -/** - * This higher-order function is dependent on the platform. On native platforms, screens that aren't already displayed in the navigation stack should be frozen to prevent unnecessary rendering. - * It's handled this way only on mobile platforms because on the web, more than one screen is displayed in a wide layout, so these screens shouldn't be frozen. - */ -export default function withPrepareCentralPaneScreen(lazyComponent: () => React.ComponentType) { - return freezeScreenWithLazyLoading(lazyComponent); -} diff --git a/src/libs/Navigation/FreezeWrapper/index.native.tsx b/src/libs/Navigation/FreezeWrapper/index.native.tsx index 219a3c24e4e3..2ef0eaf8e289 100644 --- a/src/libs/Navigation/FreezeWrapper/index.native.tsx +++ b/src/libs/Navigation/FreezeWrapper/index.native.tsx @@ -10,31 +10,19 @@ type FreezeWrapperProps = ChildrenProps & { }; function FreezeWrapper({keepVisible = false, children}: FreezeWrapperProps) { - const [isScreenBlurred, setIsScreenBlurred] = useState(false); // we need to know the screen index to determine if the screen can be frozen const screenIndexRef = useRef(null); const isFocused = useIsFocused(); const navigation = useNavigation(); const currentRoute = useRoute(); - console.log('currentRoute', currentRoute); + const isBlurred = shouldSetScreenBlurred((navigation.getState()?.index ?? 0) - (screenIndexRef.current ?? 0)); useEffect(() => { const index = navigation.getState()?.routes.findIndex((route) => route.key === currentRoute.key) ?? 0; screenIndexRef.current = index; // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); - useEffect(() => { - const unsubscribe = navigation.addListener('state', () => { - const navigationIndex = (navigation.getState()?.index ?? 0) - (screenIndexRef.current ?? 0); - if (shouldSetScreenBlurred(navigationIndex)) { - console.log('diff', navigation.getState()?.index ?? 0, screenIndexRef.current ?? 0); - } - setIsScreenBlurred(shouldSetScreenBlurred(navigationIndex)); - }); - return () => unsubscribe(); - }, [isFocused, isScreenBlurred, navigation]); - - return {children}; + return {children}; } FreezeWrapper.displayName = 'FreezeWrapper'; diff --git a/src/libs/Navigation/shouldSetScreenBlurred/index.native.tsx b/src/libs/Navigation/shouldSetScreenBlurred/index.native.tsx deleted file mode 100644 index 4043fddb7372..000000000000 --- a/src/libs/Navigation/shouldSetScreenBlurred/index.native.tsx +++ /dev/null @@ -1,12 +0,0 @@ -/** - * @param navigationIndex - * - * Decides whether to set screen to blurred state. - * - * If the screen is more than 1 screen away from the current screen, freeze it, - * we don't want to freeze the screen if it's the previous screen because the freeze placeholder - * would be visible at the beginning of the back animation then - */ -const shouldSetScreenBlurred = (navigationIndex: number) => navigationIndex > 1; - -export default shouldSetScreenBlurred; diff --git a/src/libs/Navigation/shouldSetScreenBlurred/index.tsx b/src/libs/Navigation/shouldSetScreenBlurred/index.tsx index 14b45921bdb2..2461187046d8 100644 --- a/src/libs/Navigation/shouldSetScreenBlurred/index.tsx +++ b/src/libs/Navigation/shouldSetScreenBlurred/index.tsx @@ -8,6 +8,6 @@ * LHN, we have FlashList rendering in the back while we are on * Settings screen. */ -const shouldSetScreenBlurred = (navigationIndex: number) => navigationIndex >= 1; +const shouldSetScreenBlurred = (navigationIndex: number) => navigationIndex > 1; export default shouldSetScreenBlurred; From 83c94a610e69866bf29e03482b2dcc2e988208d9 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 24 Sep 2024 13:18:45 +0200 Subject: [PATCH 031/257] Freeze WorkspaceSplitNavigator --- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 42419b46e637..5a06f69236d1 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -443,6 +443,11 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie getComponent={withPrepareCentralPaneScreen(() => SearchPage)} initialParams={{q: buildSearchQueryString()}} /> + WorkspaceSplitNavigator)} + /> - Date: Tue, 18 Jun 2024 09:54:01 +0200 Subject: [PATCH 032/257] Replace FullScreenNavigator with SplitNavigator --- .../Navigators/WorkspaceSplitNavigator.tsx | 6 +- .../createSplitNavigator/index.tsx | 64 +++++++++++++++++++ .../createSplitNavigator/types.ts | 11 ++++ .../useNavigationReset/index.native.ts | 1 + .../useNavigationReset/index.ts | 14 ++++ .../usePrepareSplitNavigatorChildren.ts | 23 +++++++ 6 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts diff --git a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx index 19f37707e857..31a3c89a3fe1 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx @@ -1,11 +1,11 @@ import React from 'react'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; -type Screens = Partial React.ComponentType>>; +type Screens = Partial React.ComponentType>>; const loadWorkspaceInitialPage = () => require('../../../../pages/workspace/WorkspaceInitialPage').default; @@ -26,7 +26,7 @@ const CENTRAL_PANE_WORKSPACE_SCREENS = { [SCREENS.WORKSPACE.RULES]: () => require('../../../../pages/workspace/rules/PolicyRulesPage').default, } satisfies Screens; -const Stack = createSplitStackNavigator(); +const Stack = createSplitStackNavigator(); function WorkspaceNavigator() { return ( diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx new file mode 100644 index 000000000000..17ab209cfae8 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx @@ -0,0 +1,64 @@ +import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native'; +import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; +import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; +import {StackView} from '@react-navigation/stack'; +import React from 'react'; +import {View} from 'react-native'; +import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useStyleUtils from '@hooks/useStyleUtils'; +import useThemeStyles from '@hooks/useThemeStyles'; +import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; +import SplitRouter from './SplitRouter'; +import type {SplitNavigatorProps, SplitNavigatorRouterOptions} from './types'; +import useNavigationReset from './useNavigationReset'; +import usePrepareSplitNavigatorChildren from './usePrepareSplitNavigatorChildren'; + +function SplitNavigator(props: SplitNavigatorProps) { + const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); + const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); + + const children = usePrepareSplitNavigatorChildren(props.children, props.sidebarScreen, screenOptions.homeScreen); + + const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< + StackNavigationState, + SplitNavigatorRouterOptions, + StackActionHelpers, + StackNavigationOptions, + StackNavigationEventMap + >(SplitRouter, { + children, + screenOptions: screenOptions.centralPaneNavigator, + initialRouteName: props.initialRouteName, + sidebarScreen: props.sidebarScreen, + initialCentralPaneScreen: props.initialCentralPaneScreen, + }); + + useNavigationReset(navigation, shouldUseNarrowLayout); + + return ( + + + + + + + + ); +} + +SplitNavigator.displayName = 'SplitNavigator'; + +export default function () { + return createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, React.ComponentType>>( + SplitNavigator, + )(); +} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts new file mode 100644 index 000000000000..3b41f6f7a96d --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts @@ -0,0 +1,11 @@ +import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; +import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; + +type SplitNavigatorRouterOptions = StackRouterOptions & {initialCentralPaneScreen: string; sidebarScreen: string}; + +type SplitNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> & { + initialCentralPaneScreen: Extract; + sidebarScreen: Extract; +}; + +export type {SplitNavigatorProps, SplitNavigatorRouterOptions}; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts new file mode 100644 index 000000000000..5d5d30356781 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts @@ -0,0 +1 @@ +export default function useNavigationReset() {} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts new file mode 100644 index 000000000000..238fc1ca2928 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts @@ -0,0 +1,14 @@ +import type {NavigationHelpers, ParamListBase} from '@react-navigation/native'; +import {useEffect} from 'react'; +import navigationRef from '@libs/Navigation/navigationRef'; + +export default function useNavigationReset(navigation: NavigationHelpers, isSmallScreenWidth: boolean) { + useEffect(() => { + if (!navigationRef.isReady()) { + return; + } + // We need to separately reset state of this navigator to trigger getRehydratedState. + navigation.reset(navigation.getState()); + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps + }, [isSmallScreenWidth]); +} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts new file mode 100644 index 000000000000..ad05d1079328 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts @@ -0,0 +1,23 @@ +import type {StackNavigationOptions} from '@react-navigation/stack'; +import {Children, isValidElement, useMemo} from 'react'; +import type {ReactNode} from 'react'; + +export default function usePrepareSplitNavigatorChildren(screensNode: ReactNode, sidebarScreenName: string, sidebarScreenOptions: StackNavigationOptions) { + return useMemo( + () => + Children.toArray(screensNode).map((screen: ReactNode) => { + if (isValidElement(screen) && screen?.props?.name === sidebarScreenName) { + // If we found the element we wanted, clone it with the provided prop changes. + return { + ...screen, + props: { + ...screen.props, + options: sidebarScreenOptions, + }, + }; + } + return screen; + }), + [screensNode, sidebarScreenName, sidebarScreenOptions], + ); +} From 4e72842f2dd2bd68106369bae0a9af3cbe71c7d9 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 19 Jun 2024 11:49:28 +0200 Subject: [PATCH 033/257] Rename Split to SplitStack --- .../createSplitNavigator/index.tsx | 64 ------------------- .../createSplitNavigator/types.ts | 11 ---- .../usePrepareSplitNavigatorChildren.ts | 23 ------- .../createSplitStackNavigator/index.tsx | 2 + .../useNavigationReset/index.native.ts | 0 .../useNavigationReset/index.ts | 0 6 files changed, 2 insertions(+), 98 deletions(-) delete mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx delete mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts delete mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts rename src/libs/Navigation/AppNavigator/{createSplitNavigator => createSplitStackNavigator}/useNavigationReset/index.native.ts (100%) rename src/libs/Navigation/AppNavigator/{createSplitNavigator => createSplitStackNavigator}/useNavigationReset/index.ts (100%) diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx deleted file mode 100644 index 17ab209cfae8..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native'; -import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; -import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; -import {StackView} from '@react-navigation/stack'; -import React from 'react'; -import {View} from 'react-native'; -import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import useStyleUtils from '@hooks/useStyleUtils'; -import useThemeStyles from '@hooks/useThemeStyles'; -import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; -import SplitRouter from './SplitRouter'; -import type {SplitNavigatorProps, SplitNavigatorRouterOptions} from './types'; -import useNavigationReset from './useNavigationReset'; -import usePrepareSplitNavigatorChildren from './usePrepareSplitNavigatorChildren'; - -function SplitNavigator(props: SplitNavigatorProps) { - const styles = useThemeStyles(); - const StyleUtils = useStyleUtils(); - const {shouldUseNarrowLayout} = useResponsiveLayout(); - const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); - - const children = usePrepareSplitNavigatorChildren(props.children, props.sidebarScreen, screenOptions.homeScreen); - - const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< - StackNavigationState, - SplitNavigatorRouterOptions, - StackActionHelpers, - StackNavigationOptions, - StackNavigationEventMap - >(SplitRouter, { - children, - screenOptions: screenOptions.centralPaneNavigator, - initialRouteName: props.initialRouteName, - sidebarScreen: props.sidebarScreen, - initialCentralPaneScreen: props.initialCentralPaneScreen, - }); - - useNavigationReset(navigation, shouldUseNarrowLayout); - - return ( - - - - - - - - ); -} - -SplitNavigator.displayName = 'SplitNavigator'; - -export default function () { - return createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, React.ComponentType>>( - SplitNavigator, - )(); -} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts deleted file mode 100644 index 3b41f6f7a96d..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; -import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; - -type SplitNavigatorRouterOptions = StackRouterOptions & {initialCentralPaneScreen: string; sidebarScreen: string}; - -type SplitNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> & { - initialCentralPaneScreen: Extract; - sidebarScreen: Extract; -}; - -export type {SplitNavigatorProps, SplitNavigatorRouterOptions}; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts deleted file mode 100644 index ad05d1079328..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type {StackNavigationOptions} from '@react-navigation/stack'; -import {Children, isValidElement, useMemo} from 'react'; -import type {ReactNode} from 'react'; - -export default function usePrepareSplitNavigatorChildren(screensNode: ReactNode, sidebarScreenName: string, sidebarScreenOptions: StackNavigationOptions) { - return useMemo( - () => - Children.toArray(screensNode).map((screen: ReactNode) => { - if (isValidElement(screen) && screen?.props?.name === sidebarScreenName) { - // If we found the element we wanted, clone it with the provided prop changes. - return { - ...screen, - props: { - ...screen.props, - options: sidebarScreenOptions, - }, - }; - } - return screen; - }), - [screensNode, sidebarScreenName, sidebarScreenOptions], - ); -} diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index d90b60d2ac4d..08a3898a0991 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -12,6 +12,7 @@ import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRoot import SplitStackRouter from './SplitStackRouter'; import type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions} from './types'; import useHandleScreenResize from './useHandleScreenResize'; +import useNavigationReset from './useNavigationReset'; import usePrepareSplitStackNavigatorChildren from './usePrepareSplitStackNavigatorChildren'; function SplitStackNavigator(props: SplitStackNavigatorProps) { @@ -42,6 +43,7 @@ function SplitStackNavigator(props: SplitStackN }); useHandleScreenResize(navigation); + useNavigationReset(navigation, shouldUseNarrowLayout); return ( diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts rename to src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts rename to src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts From 8b590d18c130bb19df18b1b675804b58d70789c8 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 19 Jun 2024 11:55:32 +0200 Subject: [PATCH 034/257] Rename useNavigationReset to useHandleScreenResize --- .../createSplitStackNavigator/index.tsx | 2 -- .../useNavigationReset/index.native.ts | 1 - .../useNavigationReset/index.ts | 14 -------------- 3 files changed, 17 deletions(-) delete mode 100644 src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts delete mode 100644 src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index 08a3898a0991..d90b60d2ac4d 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -12,7 +12,6 @@ import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRoot import SplitStackRouter from './SplitStackRouter'; import type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions} from './types'; import useHandleScreenResize from './useHandleScreenResize'; -import useNavigationReset from './useNavigationReset'; import usePrepareSplitStackNavigatorChildren from './usePrepareSplitStackNavigatorChildren'; function SplitStackNavigator(props: SplitStackNavigatorProps) { @@ -43,7 +42,6 @@ function SplitStackNavigator(props: SplitStackN }); useHandleScreenResize(navigation); - useNavigationReset(navigation, shouldUseNarrowLayout); return ( diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts deleted file mode 100644 index 5d5d30356781..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts +++ /dev/null @@ -1 +0,0 @@ -export default function useNavigationReset() {} diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts deleted file mode 100644 index 238fc1ca2928..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type {NavigationHelpers, ParamListBase} from '@react-navigation/native'; -import {useEffect} from 'react'; -import navigationRef from '@libs/Navigation/navigationRef'; - -export default function useNavigationReset(navigation: NavigationHelpers, isSmallScreenWidth: boolean) { - useEffect(() => { - if (!navigationRef.isReady()) { - return; - } - // We need to separately reset state of this navigator to trigger getRehydratedState. - navigation.reset(navigation.getState()); - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, [isSmallScreenWidth]); -} From 72dbdf1c84b35f524a2c16be8f4ddae29083eabe Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 19 Jun 2024 13:45:01 +0200 Subject: [PATCH 035/257] Rename FullScreenNavigator to WorkspaceNavigator --- src/libs/Navigation/dismissModalWithReport.ts | 1 - src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/dismissModalWithReport.ts b/src/libs/Navigation/dismissModalWithReport.ts index 302dc68f09f8..9d0cb05251fc 100644 --- a/src/libs/Navigation/dismissModalWithReport.ts +++ b/src/libs/Navigation/dismissModalWithReport.ts @@ -16,7 +16,6 @@ import getPolicyIDFromState from './getPolicyIDFromState'; import getStateFromPath from './getStateFromPath'; import getTopmostReportId from './getTopmostReportId'; import linkingConfig from './linkingConfig'; -import switchPolicyID from './switchPolicyID'; import type {RootStackParamList, StackNavigationAction, State} from './types'; // This function is in a separate file than Navigation.ts to avoid cyclic dependency. diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index ae47b8e0685e..d393f92c1981 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -4,7 +4,8 @@ import pick from 'lodash/pick'; import type {TupleToUnion} from 'type-fest'; import {isAnonymousUser} from '@libs/actions/Session'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import type {NavigationPartialRoute, RootStackParamList, SplitNavigatorScreenName} from '@libs/Navigation/types'; +import type {CentralPaneName, NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; +import {isCentralPaneName} from '@libs/NavigationUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; From 557d7aaeb52f5b39f9e6db00e66b5c507e595981 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 25 Jul 2024 12:02:04 +0200 Subject: [PATCH 036/257] Add BottomTabBar to WorkspaceInitialPage and SettingsWorkspaces --- src/pages/workspace/WorkspacesListPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index a29e17ef61d2..95d1459062d0 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -108,7 +108,7 @@ function WorkspacesListPage() { const styles = useThemeStyles(); const {translate} = useLocalize(); const {isOffline} = useNetwork(); - const {shouldUseNarrowLayout, isMediumScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout, isSmallScreenWidth, isMediumScreenWidth} = useResponsiveLayout(); const [allConnectionSyncProgresses] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS); const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); From ac3fc8fa4f68760d31a121660a2a99e1d6c81976 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 25 Jul 2024 14:50:48 +0200 Subject: [PATCH 037/257] Fix pressing settings tab when navigating deeper into workspaces --- src/pages/home/sidebar/BottomTabAvatar.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index 5b1ae9e7206f..7871003a4e16 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -49,6 +49,12 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT return; } + if (route.name === SCREENS.WORKSPACE.INITIAL) { + Navigation.dismissModal(); + Navigation.goBack(ROUTES.SETTINGS); + return; + } + if (route.name === SCREENS.WORKSPACE.INITIAL) { Navigation.dismissModal(); return; From ae70ac4c0188703b89c9981950ea1f5e438bed70 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 6 Aug 2024 18:18:37 +0200 Subject: [PATCH 038/257] fix pressing on settings tab while in workspace navigator --- src/pages/home/sidebar/BottomTabAvatar.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index 7871003a4e16..8ccac728f852 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -51,7 +51,6 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT if (route.name === SCREENS.WORKSPACE.INITIAL) { Navigation.dismissModal(); - Navigation.goBack(ROUTES.SETTINGS); return; } From 19bf5d90761d62af2c92b112105e95b57300b07e Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 3 Sep 2024 12:33:23 +0200 Subject: [PATCH 039/257] Add todo comments for new navigation logic, adjust split navigators, adjust getAdaptedState --- .../Navigators/SettingsSplitNavigator.tsx | 2 +- .../linkingConfig/getAdaptedStateFromPath.ts | 22 +++++++++++++++++++ src/libs/Navigation/linkingConfig/index.ts | 2 +- src/pages/WorkspaceSwitcherPage/index.tsx | 2 +- src/pages/settings/InitialSettingsPage.tsx | 3 ++- 5 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx index 9ab421a9ef3d..21becf1f7fa9 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx @@ -4,10 +4,10 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; +import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; import type {SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; -import getRootNavigatorScreenOptions from '../getRootNavigatorScreenOptions'; const loadInitialSettingsPage = () => require('../../../../pages/settings/InitialSettingsPage').default; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index d393f92c1981..e63b0a4b937c 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -69,6 +69,28 @@ function getParamsFromRoute(screenName: string): string[] { return route.match(/(?<=[:?&])(\w+)(?=[/=?&]|$)/g) ?? []; } +function createSplitNavigator(splitNavigatorLHNScreen: SplitNavigatorLHNScreen, route?: NavigationPartialRoute): NavigationPartialRoute { + const routes = []; + + const policyID = route?.params && 'policyID' in route.params ? route.params.policyID : undefined; + + // Both routes in WorkspaceNavigator should store a policyID in params, so here this param is also passed to the screen displayed in LHN in WorkspaceNavigator + routes.push({ + name: splitNavigatorLHNScreen, + params: { + policyID, + }, + }); + + if (route) { + routes.push(route); + } + return { + name: mapLhnToSplitNavigatorName[splitNavigatorLHNScreen], + state: getRoutesWithIndex(routes), + }; +} + // This function will return CentralPaneNavigator route or WorkspaceNavigator route. function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): NavigationPartialRoute | NavigationPartialRoute<'Search_Central_Pane'> | undefined { // Check for backTo param. One screen with different backTo value may need diferent screens visible under the overlay. diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index 1f556aa67809..7bb5e8ae5b5a 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -15,7 +15,7 @@ const linkingConfig: LinkingOptions = { return adaptedState; }, subscribe, - getPathFromState: customGetPathFromState, + // getPathFromState: customGetPathFromState, prefixes, config, }; diff --git a/src/pages/WorkspaceSwitcherPage/index.tsx b/src/pages/WorkspaceSwitcherPage/index.tsx index 9eaee40853c3..277e5431992e 100644 --- a/src/pages/WorkspaceSwitcherPage/index.tsx +++ b/src/pages/WorkspaceSwitcherPage/index.tsx @@ -18,8 +18,8 @@ import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import {sortWorkspacesBySelected} from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import {getWorkspacesBrickRoads, getWorkspacesUnreadStatuses} from '@libs/WorkspacesSettingsUtils'; import type {BrickRoad} from '@libs/WorkspacesSettingsUtils'; +import {getWorkspacesBrickRoads, getWorkspacesUnreadStatuses} from '@libs/WorkspacesSettingsUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 6652f4fc118f..32ca20741d07 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -47,6 +47,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; +import type * as OnyxTypes from '@src/types/onyx'; import type {Icon as TIcon} from '@src/types/onyx/OnyxCommon'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; @@ -412,7 +413,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr scrollEventThrottle={16} contentContainerStyle={[styles.w100]} showsVerticalScrollIndicator={false} - > + > {accountMenuItems} {workspaceMenuItems} {generalMenuItems} From fdb6e13e3adc269e129ea2d0715b2430bf779c0c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Sat, 7 Sep 2024 11:29:20 +0200 Subject: [PATCH 040/257] Refactor useActiveWorkspace --- src/components/ActiveWorkspaceProvider/index.tsx | 4 ++-- src/hooks/useReportIDs.tsx | 2 +- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 2 +- .../AppNavigator/Navigators/ReportsSplitNavigator.tsx | 2 +- src/libs/Navigation/linkingConfig/index.ts | 2 +- src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx | 2 -- src/pages/workspace/WorkspaceNewRoomPage.tsx | 2 +- src/pages/workspace/WorkspaceProfilePage.tsx | 1 - 8 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index d306226a85c2..0e3680e2a819 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -1,5 +1,5 @@ import {useNavigationState} from '@react-navigation/native'; -import React, {useEffect, useMemo, useState} from 'react'; +import React, {useEffect, useMemo} from 'react'; import ActiveWorkspaceContext from '@components/ActiveWorkspace/ActiveWorkspaceContext'; import * as SearchUtils from '@libs/SearchUtils'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -7,7 +7,7 @@ import SCREENS from '@src/SCREENS'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; function ActiveWorkspaceContextProvider({children}: ChildrenProps) { - const [activeWorkspaceID, setActiveWorkspaceID] = useState(undefined); + const activeWorkspaceID = useNavigationState(getPolicyIDFromState); const lastPolicyRoute = useNavigationState((state) => state?.routes?.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.CENTRAL_PANE), diff --git a/src/hooks/useReportIDs.tsx b/src/hooks/useReportIDs.tsx index b7d84cb25196..d51d9e53c48c 100644 --- a/src/hooks/useReportIDs.tsx +++ b/src/hooks/useReportIDs.tsx @@ -91,7 +91,7 @@ function ReportIDsContextProvider({ const {accountID} = useCurrentUserPersonalDetails(); const currentReportIDValue = useCurrentReportID(); const derivedCurrentReportID = currentReportIDForTests ?? currentReportIDValue?.currentReportID; - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); const policyMemberAccountIDs = useMemo(() => getPolicyEmployeeListByIdWithoutCurrentUser(policies, activeWorkspaceID, accountID), [policies, activeWorkspaceID, accountID]); diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 5a06f69236d1..f158f0743c19 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -238,7 +238,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie const {shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout(); const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); const {canUseDefaultRooms} = usePermissions(); - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(onboardingIsMediumOrLargerScreenWidth), [screenOptions, onboardingIsMediumOrLargerScreenWidth]); const onboardingScreenOptions = useMemo( () => getOnboardingModalScreenOptions(shouldUseNarrowLayout, styles, StyleUtils, onboardingIsMediumOrLargerScreenWidth), diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index 2ad1d7a480c9..c52c97fef17a 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -23,7 +23,7 @@ function shouldOpenOnAdminRoom() { function ReportsSplitNavigator() { const {canUseDefaultRooms} = usePermissions(); - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); let initialReportID: string | undefined; const isInitialRender = useRef(true); diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index 7bb5e8ae5b5a..1f556aa67809 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -15,7 +15,7 @@ const linkingConfig: LinkingOptions = { return adaptedState; }, subscribe, - // getPathFromState: customGetPathFromState, + getPathFromState: customGetPathFromState, prefixes, config, }; diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx index 8b9e6103a1a9..a9377a9b9b27 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx @@ -5,11 +5,9 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import {updateLastAccessedWorkspace} from '@libs/actions/Policy/Policy'; import * as Browser from '@libs/Browser'; import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import TopBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar'; -import Navigation from '@libs/Navigation/Navigation'; import Performance from '@libs/Performance'; import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import Timing from '@userActions/Timing'; diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 481fc6c41402..28a1e9ad4a7a 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -55,7 +55,7 @@ function WorkspaceNewRoomPage() { const wasLoading = usePrevious(!!formState?.isLoading); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); const {isLoading = false, errorFields = {}} = formState ?? {}; - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); const activeWorkspaceOrDefaultID = activeWorkspaceID ?? activePolicyID; diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index 4c26e82c08c5..985e5df0eeca 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -14,7 +14,6 @@ import * as Illustrations from '@components/Icon/Illustrations'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import Section from '@components/Section'; -import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import usePermissions from '@hooks/usePermissions'; From 0488fd28377fbd8ed3fd506f4890f852e86edeb3 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 11 Sep 2024 11:53:37 +0200 Subject: [PATCH 041/257] Add createSplitNavigator --- .../ActiveWorkspaceProvider/index.tsx | 2 - .../CustomRouter.ts | 1 - .../linkingConfig/getAdaptedStateFromPath.ts | 41 ++++--------------- 3 files changed, 8 insertions(+), 36 deletions(-) diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index 0e3680e2a819..983d1b1a7795 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -7,8 +7,6 @@ import SCREENS from '@src/SCREENS'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; function ActiveWorkspaceContextProvider({children}: ChildrenProps) { - const activeWorkspaceID = useNavigationState(getPolicyIDFromState); - const lastPolicyRoute = useNavigationState((state) => state?.routes?.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.CENTRAL_PANE), ); diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index c0fddeaef940..c5bc46107249 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -1,7 +1,6 @@ import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; import {findFocusedRoute, getPathFromState, StackActions, StackRouter} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/routers'; -import useActiveWorkspace from '@hooks/useActiveWorkspace'; import * as Localize from '@libs/Localize'; import Log from '@libs/Log'; import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index e63b0a4b937c..e127eaea11d0 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -4,8 +4,7 @@ import pick from 'lodash/pick'; import type {TupleToUnion} from 'type-fest'; import {isAnonymousUser} from '@libs/actions/Session'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import type {CentralPaneName, NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; -import {isCentralPaneName} from '@libs/NavigationUtils'; +import type {NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; @@ -69,28 +68,6 @@ function getParamsFromRoute(screenName: string): string[] { return route.match(/(?<=[:?&])(\w+)(?=[/=?&]|$)/g) ?? []; } -function createSplitNavigator(splitNavigatorLHNScreen: SplitNavigatorLHNScreen, route?: NavigationPartialRoute): NavigationPartialRoute { - const routes = []; - - const policyID = route?.params && 'policyID' in route.params ? route.params.policyID : undefined; - - // Both routes in WorkspaceNavigator should store a policyID in params, so here this param is also passed to the screen displayed in LHN in WorkspaceNavigator - routes.push({ - name: splitNavigatorLHNScreen, - params: { - policyID, - }, - }); - - if (route) { - routes.push(route); - } - return { - name: mapLhnToSplitNavigatorName[splitNavigatorLHNScreen], - state: getRoutesWithIndex(routes), - }; -} - // This function will return CentralPaneNavigator route or WorkspaceNavigator route. function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): NavigationPartialRoute | NavigationPartialRoute<'Search_Central_Pane'> | undefined { // Check for backTo param. One screen with different backTo value may need diferent screens visible under the overlay. @@ -107,16 +84,14 @@ function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): Navigat } } - // If we know that backTo targets the root route (full screen) we want to use it. - const fullScreenNavigator = stateForBackTo.routes.find((rt) => rt.name === NAVIGATORS.WORKSPACE_NAVIGATOR); - if (fullScreenNavigator && fullScreenNavigator.state) { - return fullScreenNavigator as NavigationPartialRoute; - } + const splitNavigator = stateForBackTo.routes.find( + // eslint-disable-next-line @typescript-eslint/no-shadow + (route) => route.name.endsWith('SplitNavigator'), + ); - // If we know that backTo targets a central pane screen we want to use it. - const centralPaneScreen = stateForBackTo.routes.find((rt) => isCentralPaneName(rt.name)); - if (centralPaneScreen) { - return centralPaneScreen as NavigationPartialRoute; + // If we know that backTo targets the root route (central pane or full screen) we want to use it. + if (splitNavigator && splitNavigator.state) { + return splitNavigator as NavigationPartialRoute; } } } From bc2adfe4be93792310e1c041499bcb1165233c7c Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 18 Sep 2024 16:09:37 +0200 Subject: [PATCH 042/257] improve routers --- .../AppNavigator/createCustomStackNavigator/CustomRouter.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index c5bc46107249..f5498b91a3a7 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -89,13 +89,11 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { if (!queryJSON) { return null; } - if (action.payload.policyID) { queryJSON.policyID = action.payload.policyID; } else { delete queryJSON.policyID; } - const newAction = StackActions.push(SCREENS.SEARCH.CENTRAL_PANE, { ...currentParams, q: SearchUtils.buildSearchQueryString(queryJSON), From 6d6d0abaafd4ef59c1070adeaee149a15be441cd Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 18 Sep 2024 17:46:43 +0200 Subject: [PATCH 043/257] add setter to activeWorkspaceID context --- src/components/ActiveWorkspaceProvider/index.tsx | 6 ++++-- src/hooks/useReportIDs.tsx | 2 +- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 2 +- .../AppNavigator/Navigators/ReportsSplitNavigator.tsx | 2 +- .../AppNavigator/createCustomStackNavigator/CustomRouter.ts | 3 +++ src/pages/workspace/WorkspaceNewRoomPage.tsx | 2 +- 6 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index 983d1b1a7795..1a9e32edf866 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -1,5 +1,5 @@ import {useNavigationState} from '@react-navigation/native'; -import React, {useEffect, useMemo} from 'react'; +import React, {useEffect, useMemo, useState} from 'react'; import ActiveWorkspaceContext from '@components/ActiveWorkspace/ActiveWorkspaceContext'; import * as SearchUtils from '@libs/SearchUtils'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -7,6 +7,8 @@ import SCREENS from '@src/SCREENS'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; function ActiveWorkspaceContextProvider({children}: ChildrenProps) { + const [activeWorkspaceID, setActiveWorkspaceID] = useState(undefined); + const lastPolicyRoute = useNavigationState((state) => state?.routes?.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.CENTRAL_PANE), ); @@ -55,4 +57,4 @@ function ActiveWorkspaceContextProvider({children}: ChildrenProps) { } export default ActiveWorkspaceContextProvider; -export {}; +export {}; \ No newline at end of file diff --git a/src/hooks/useReportIDs.tsx b/src/hooks/useReportIDs.tsx index d51d9e53c48c..b7d84cb25196 100644 --- a/src/hooks/useReportIDs.tsx +++ b/src/hooks/useReportIDs.tsx @@ -91,7 +91,7 @@ function ReportIDsContextProvider({ const {accountID} = useCurrentUserPersonalDetails(); const currentReportIDValue = useCurrentReportID(); const derivedCurrentReportID = currentReportIDForTests ?? currentReportIDValue?.currentReportID; - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const policyMemberAccountIDs = useMemo(() => getPolicyEmployeeListByIdWithoutCurrentUser(policies, activeWorkspaceID, accountID), [policies, activeWorkspaceID, accountID]); diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index f158f0743c19..5a06f69236d1 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -238,7 +238,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie const {shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout(); const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); const {canUseDefaultRooms} = usePermissions(); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(onboardingIsMediumOrLargerScreenWidth), [screenOptions, onboardingIsMediumOrLargerScreenWidth]); const onboardingScreenOptions = useMemo( () => getOnboardingModalScreenOptions(shouldUseNarrowLayout, styles, StyleUtils, onboardingIsMediumOrLargerScreenWidth), diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index c52c97fef17a..2ad1d7a480c9 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -23,7 +23,7 @@ function shouldOpenOnAdminRoom() { function ReportsSplitNavigator() { const {canUseDefaultRooms} = usePermissions(); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); let initialReportID: string | undefined; const isInitialRender = useRef(true); diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index f5498b91a3a7..c0fddeaef940 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -1,6 +1,7 @@ import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; import {findFocusedRoute, getPathFromState, StackActions, StackRouter} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/routers'; +import useActiveWorkspace from '@hooks/useActiveWorkspace'; import * as Localize from '@libs/Localize'; import Log from '@libs/Log'; import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; @@ -89,11 +90,13 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { if (!queryJSON) { return null; } + if (action.payload.policyID) { queryJSON.policyID = action.payload.policyID; } else { delete queryJSON.policyID; } + const newAction = StackActions.push(SCREENS.SEARCH.CENTRAL_PANE, { ...currentParams, q: SearchUtils.buildSearchQueryString(queryJSON), diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 28a1e9ad4a7a..481fc6c41402 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -55,7 +55,7 @@ function WorkspaceNewRoomPage() { const wasLoading = usePrevious(!!formState?.isLoading); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); const {isLoading = false, errorFields = {}} = formState ?? {}; - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const activeWorkspaceOrDefaultID = activeWorkspaceID ?? activePolicyID; From 40e6e1e3abebaf7559ce18661aa213e7330a6da5 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 19 Sep 2024 12:53:06 +0200 Subject: [PATCH 044/257] Fix LHN paddings --- src/pages/settings/InitialSettingsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 32ca20741d07..4a014fdcfb25 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -413,7 +413,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr scrollEventThrottle={16} contentContainerStyle={[styles.w100]} showsVerticalScrollIndicator={false} - > + > {accountMenuItems} {workspaceMenuItems} {generalMenuItems} From 9ff0e0560af7706895b9a09eaf94d68b4a7b62d9 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 20 Sep 2024 15:20:52 +0200 Subject: [PATCH 045/257] remember state between tabs --- src/pages/home/sidebar/BottomTabAvatar.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index 8ccac728f852..5b1ae9e7206f 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -54,11 +54,6 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT return; } - if (route.name === SCREENS.WORKSPACE.INITIAL) { - Navigation.dismissModal(); - return; - } - interceptAnonymousUser(() => { const rootState = navigationRef.getRootState(); const lastSettingsOrWorkspaceNavigatorRoute = rootState.routes.findLast( From 0a374ccfb9363f2734b760887264aa4274d49e92 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 20 Sep 2024 15:53:02 +0200 Subject: [PATCH 046/257] Disable animation for settings workspaces screen --- .../AppNavigator/Navigators/SettingsSplitNavigator.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx index 21becf1f7fa9..28d520aa9832 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx @@ -8,6 +8,7 @@ import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRoot import type {SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; +import getRootNavigatorScreenOptions from '../getRootNavigatorScreenOptions'; const loadInitialSettingsPage = () => require('../../../../pages/settings/InitialSettingsPage').default; From 51895f5c62dd4e079bb0194f6fe19bd607a37da6 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 24 Sep 2024 07:27:21 +0200 Subject: [PATCH 047/257] Add getStateToRender to createSplitStackNavigator, splits types fixes --- .../Navigators/SettingsSplitNavigator.tsx | 1 - .../CustomRouter.ts | 2 +- .../createSplitStackNavigator/index.tsx | 23 ++++++++++++++++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx index 28d520aa9832..21becf1f7fa9 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx @@ -8,7 +8,6 @@ import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRoot import type {SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; -import getRootNavigatorScreenOptions from '../getRootNavigatorScreenOptions'; const loadInitialSettingsPage = () => require('../../../../pages/settings/InitialSettingsPage').default; diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index c0fddeaef940..829d173659a3 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -121,7 +121,7 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { if (!lastRoute?.name || !MODAL_ROUTES_TO_DISMISS.includes(lastRoute?.name)) { Log.hmmm('[Navigation] dismissModal failed because there is no modal stack to dismiss'); - return; + return null; } return stackRouter.getStateForAction(state, newAction, configOptions); diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index d90b60d2ac4d..80cf27eb1fe6 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -2,7 +2,7 @@ import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@rea import {createNavigatorFactory, useNavigationBuilder, useRoute} from '@react-navigation/native'; import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; import {StackView} from '@react-navigation/stack'; -import React from 'react'; +import React, {useMemo} from 'react'; import {View} from 'react-native'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -14,10 +14,25 @@ import type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions} from '. import useHandleScreenResize from './useHandleScreenResize'; import usePrepareSplitStackNavigatorChildren from './usePrepareSplitStackNavigatorChildren'; +function getStateToRender(state: StackNavigationState, isSmallScreenWidth: boolean): StackNavigationState { + const sidebarScreenRoute = state.routes.at(0); + const centralScreenRoutes = state.routes.slice(1); + const routes = isSmallScreenWidth ? state.routes.slice(-2) : [sidebarScreenRoute, ...centralScreenRoutes.slice(-2)]; + + // Routes passed to the state have to be defined + const definedRoutes = routes.filter((route) => route !== undefined); + + return { + ...state, + routes: definedRoutes, + index: routes.length - 1, + }; +} + function SplitStackNavigator(props: SplitStackNavigatorProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const {shouldUseNarrowLayout} = useResponsiveLayout(); + const {isSmallScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout(); const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); const children = usePrepareSplitStackNavigatorChildren(props.children, props.sidebarScreen, screenOptions.homeScreen); @@ -43,6 +58,8 @@ function SplitStackNavigator(props: SplitStackN useHandleScreenResize(navigation); + const stateToRender = useMemo(() => getStateToRender(state, isSmallScreenWidth), [state, isSmallScreenWidth]); + return ( @@ -50,7 +67,7 @@ function SplitStackNavigator(props: SplitStackN From 44b9c7bae4e8b688a777c873d12556cbb0837f13 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 24 Sep 2024 09:58:27 +0200 Subject: [PATCH 048/257] Fix switching between home and workspace settings --- src/pages/home/sidebar/BottomTabAvatar.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index 5b1ae9e7206f..d479cd411dbd 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -10,7 +10,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; -import type {AuthScreensParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -62,11 +62,10 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT // If there is a workspace navigator route, then we should open the workspace initial screen as it should be "remembered". if (lastSettingsOrWorkspaceNavigatorRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - const params = lastSettingsOrWorkspaceNavigatorRoute.params as AuthScreensParamList[typeof NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]; - + const params = lastSettingsOrWorkspaceNavigatorRoute.state?.routes.at(0)?.params as WorkspaceSplitNavigatorParamList[typeof SCREENS.WORKSPACE.INITIAL]; // Screens of this navigator should always have policyID - if ('params' in params && params.params?.policyID) { - Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(params.params.policyID)); + if (params.policyID) { + Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(params.policyID)); } return; } From 3ba0aaf2c4ea3cb6a48175590db6fa824fd61c8f Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 26 Sep 2024 15:38:12 +0200 Subject: [PATCH 049/257] Fix navigating from BottomTabAvatar when current route is WorkspaceInitialPage --- src/pages/home/sidebar/BottomTabAvatar.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index d479cd411dbd..d34fd052434d 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -50,7 +50,15 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT } if (route.name === SCREENS.WORKSPACE.INITIAL) { - Navigation.dismissModal(); + const previousRoute = navigationRef.getRootState().routes.at(-2); + + // If there is the settings split navigator we can dismiss safely + if (previousRoute?.name === NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR) { + Navigation.dismissModal(); + } else { + // If not, we are going to replace this route with the settings route + Navigation.navigate(ROUTES.SETTINGS_WORKSPACES, CONST.NAVIGATION.ACTION_TYPE.REPLACE); + } return; } From 32288b1b3d910a70aa00a0b7f20bb0ae9e053e04 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 27 Sep 2024 17:19:40 +0200 Subject: [PATCH 050/257] Fix flickering in frozen split navigators --- .../Navigation/AppNavigator/AuthScreens.tsx | 49 ++++++------------- .../index.native.tsx => FreezeWrapper.tsx} | 4 +- src/libs/Navigation/FreezeWrapper/index.tsx | 46 ----------------- src/libs/Navigation/NavigationRoot.tsx | 2 - 4 files changed, 17 insertions(+), 84 deletions(-) rename src/libs/Navigation/{FreezeWrapper/index.native.tsx => FreezeWrapper.tsx} (89%) delete mode 100644 src/libs/Navigation/FreezeWrapper/index.tsx diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 5a06f69236d1..53de4eac29d4 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -1,7 +1,7 @@ import React, {memo, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import Onyx, {withOnyx} from 'react-native-onyx'; +import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import ActiveGuidesEventListener from '@components/ActiveGuidesEventListener'; import ActiveWorkspaceContextProvider from '@components/ActiveWorkspaceProvider'; @@ -35,7 +35,6 @@ import {buildSearchQueryString} from '@libs/SearchUtils'; import * as SessionUtils from '@libs/SessionUtils'; import ConnectionCompletePage from '@pages/ConnectionCompletePage'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; -import SearchPage from '@pages/Search/SearchPage'; import DesktopSignInRedirectPage from '@pages/signin/DesktopSignInRedirectPage'; import * as App from '@userActions/App'; import * as Download from '@userActions/Download'; @@ -65,22 +64,8 @@ import ExplanationModalNavigator from './Navigators/ExplanationModalNavigator'; import FeatureTrainingModalNavigator from './Navigators/FeatureTrainingModalNavigator'; import LeftModalNavigator from './Navigators/LeftModalNavigator'; import OnboardingModalNavigator from './Navigators/OnboardingModalNavigator'; -import ReportsSplitNavigator from './Navigators/ReportsSplitNavigator'; import RightModalNavigator from './Navigators/RightModalNavigator'; -import SettingsSplitNavigator from './Navigators/SettingsSplitNavigator'; import WelcomeVideoModalNavigator from './Navigators/WelcomeVideoModalNavigator'; -import WorkspaceSplitNavigator from './Navigators/WorkspaceSplitNavigator'; - -type AuthScreensProps = { - /** Session of currently logged in user */ - session: OnyxEntry; - - /** The report ID of the last opened public room as anonymous user */ - lastOpenedPublicRoomID: OnyxEntry; - - /** The last Onyx update ID was applied to the client */ - initialLastUpdateIDAppliedToClient: OnyxEntry; -}; const loadReportAttachments = () => require('../../../pages/home/report/ReportAttachments').default; const loadValidateLoginPage = () => require('../../../pages/ValidateLoginPage').default; @@ -94,6 +79,11 @@ const loadReportAvatar = () => require('../../../pages/Rep const loadReceiptView = () => require('../../../pages/TransactionReceiptPage').default; const loadWorkspaceJoinUser = () => require('@pages/workspace/WorkspaceJoinUserPage').default; +const loadReportSplitNavigator = withPrepareCentralPaneScreen(() => require('./Navigators/ReportsSplitNavigator').default); +const loadSettingsSplitNavigator = withPrepareCentralPaneScreen(() => require('./Navigators/SettingsSplitNavigator').default); +const loadWorkspaceSplitNavigator = withPrepareCentralPaneScreen(() => require('./Navigators/WorkspaceSplitNavigator').default); +const loadSearchPage = withPrepareCentralPaneScreen(() => require('@pages/Search/SearchPage').default); + function shouldOpenOnAdminRoom() { const url = getCurrentUrl(); return url ? new URL(url).searchParams.get('openOnAdminRoom') === 'true' : false; @@ -232,7 +222,10 @@ const modalScreenListenersWithCancelSearch = { }, }; -function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDAppliedToClient}: AuthScreensProps) { +function AuthScreens() { + const [session] = useOnyx(ONYXKEYS.SESSION); + const [lastOpenedPublicRoomID] = useOnyx(ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID); + const [initialLastUpdateIDAppliedToClient] = useOnyx(ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout(); @@ -430,23 +423,23 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie ReportsSplitNavigator)} + getComponent={loadReportSplitNavigator} /> SettingsSplitNavigator)} + getComponent={loadSettingsSplitNavigator} /> SearchPage)} + getComponent={loadSearchPage} initialParams={{q: buildSearchQueryString()}} /> WorkspaceSplitNavigator)} + getComponent={loadWorkspaceSplitNavigator} /> true); - -export default withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, - lastOpenedPublicRoomID: { - key: ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID, - }, - initialLastUpdateIDAppliedToClient: { - key: ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT, - }, -})(AuthScreensMemoized); +export default memo(AuthScreens, () => true); diff --git a/src/libs/Navigation/FreezeWrapper/index.native.tsx b/src/libs/Navigation/FreezeWrapper.tsx similarity index 89% rename from src/libs/Navigation/FreezeWrapper/index.native.tsx rename to src/libs/Navigation/FreezeWrapper.tsx index 2ef0eaf8e289..aa6e302cdbd0 100644 --- a/src/libs/Navigation/FreezeWrapper/index.native.tsx +++ b/src/libs/Navigation/FreezeWrapper.tsx @@ -1,8 +1,8 @@ import {useIsFocused, useNavigation, useRoute} from '@react-navigation/native'; -import React, {useEffect, useRef, useState} from 'react'; +import React, {useEffect, useRef} from 'react'; import {Freeze} from 'react-freeze'; -import shouldSetScreenBlurred from '@libs/Navigation/shouldSetScreenBlurred'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; +import shouldSetScreenBlurred from './shouldSetScreenBlurred'; type FreezeWrapperProps = ChildrenProps & { /** Prop to disable freeze */ diff --git a/src/libs/Navigation/FreezeWrapper/index.tsx b/src/libs/Navigation/FreezeWrapper/index.tsx deleted file mode 100644 index 7219666b1b18..000000000000 --- a/src/libs/Navigation/FreezeWrapper/index.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import {useIsFocused, useNavigation, useRoute} from '@react-navigation/native'; -import React, {useEffect, useLayoutEffect, useRef, useState} from 'react'; -import {Freeze} from 'react-freeze'; -import shouldSetScreenBlurred from '@libs/Navigation/shouldSetScreenBlurred'; -import type ChildrenProps from '@src/types/utils/ChildrenProps'; - -type FreezeWrapperProps = ChildrenProps & { - /** Prop to disable freeze */ - keepVisible?: boolean; -}; - -function FreezeWrapper({keepVisible = false, children}: FreezeWrapperProps) { - const [isScreenBlurred, setIsScreenBlurred] = useState(false); - const [freezed, setFreezed] = useState(false); - // we need to know the screen index to determine if the screen can be frozen - const screenIndexRef = useRef(null); - const isFocused = useIsFocused(); - const navigation = useNavigation(); - const currentRoute = useRoute(); - - useEffect(() => { - const index = navigation.getState()?.routes.findIndex((route) => route.key === currentRoute.key) ?? 0; - screenIndexRef.current = index; - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - const unsubscribe = navigation.addListener('state', () => { - const navigationIndex = (navigation.getState()?.index ?? 0) - (screenIndexRef.current ?? 0); - setIsScreenBlurred(shouldSetScreenBlurred(navigationIndex)); - }); - return () => unsubscribe(); - }, [isFocused, isScreenBlurred, navigation]); - - // Decouple the Suspense render task so it won't be interuptted by React's concurrent mode - // and stuck in an infinite loop - useLayoutEffect(() => { - setFreezed(!isFocused && isScreenBlurred && !keepVisible); - }, [isFocused, isScreenBlurred, keepVisible]); - - return {children}; -} - -FreezeWrapper.displayName = 'FreezeWrapper'; - -export default FreezeWrapper; diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 99a38d8d0bf2..124e0ed541d6 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -165,8 +165,6 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh // We want to clean saved scroll offsets for screens that aren't anymore in the state. cleanStaleScrollOffsets(state); - - console.log('state', state); }; return ( From 784cf89c7069d0fa137851b24b0066474ee3ad34 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 30 Sep 2024 07:32:13 +0200 Subject: [PATCH 051/257] Fix lint in createCustomStackNavigator/index.tsx --- .../AppNavigator/createCustomStackNavigator/index.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx index a5aa8552179f..8c98002e5c7b 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx @@ -20,15 +20,6 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { initialRouteName: props.initialRouteName, }); - // const stateToRender = useMemo(() => { - // const routes = state.routes.slice(-3); - // return { - // ...state, - // routes, - // index: routes.length - 1, - // }; - // }, [state]); - return ( Date: Mon, 7 Oct 2024 14:22:04 +0200 Subject: [PATCH 052/257] Add missing import to AuthScreens, fix styles in SearchPage --- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 53de4eac29d4..9eba945176a5 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -1,7 +1,7 @@ import React, {memo, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import Onyx from 'react-native-onyx'; +import Onyx, {useOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import ActiveGuidesEventListener from '@components/ActiveGuidesEventListener'; import ActiveWorkspaceContextProvider from '@components/ActiveWorkspaceProvider'; From 5bb5b16090153917fcf28399ba1e4753ad84b2e4 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 7 Oct 2024 14:53:18 +0200 Subject: [PATCH 053/257] Fix styles in SearchPage --- src/pages/Search/SearchPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 57fbbcd80d57..d7c06dc689ef 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -93,7 +93,7 @@ function SearchPage({route}: SearchPageProps) { )} - <> + - + )} From 94aaab10afca3bde8a9614c94b3c4453fe2b2b5b Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Thu, 3 Oct 2024 13:22:57 +0200 Subject: [PATCH 054/257] move all mappings to one directory RELATIONS --- .../CENTRAL_PANE_TO_RHP_MAPPING.ts | 0 .../LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts | 0 .../{ => RELATIONS}/SEARCH_RHP_SCREENS.ts | 0 .../TAB_TO_CENTRAL_PANE_MAPPING.ts | 0 .../WORKSPACE_SCREEN_TO_RHP_MAPPING.ts | 0 .../linkingConfig/RELATIONS/index.ts | 0 .../linkingConfig/createSplitNavigator.ts | 2 +- .../linkingConfig/getAdaptedStateFromPath.ts | 22 +++++++++++-------- .../getMatchingBottomTabRouteForState.ts | 2 +- .../getMatchingCentralPaneRouteForState.ts | 2 +- src/libs/Navigation/types.ts | 2 +- 11 files changed, 17 insertions(+), 13 deletions(-) rename src/libs/Navigation/linkingConfig/{ => RELATIONS}/CENTRAL_PANE_TO_RHP_MAPPING.ts (100%) rename src/libs/Navigation/linkingConfig/{ => RELATIONS}/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts (100%) rename src/libs/Navigation/linkingConfig/{ => RELATIONS}/SEARCH_RHP_SCREENS.ts (100%) rename src/libs/Navigation/linkingConfig/{ => RELATIONS}/TAB_TO_CENTRAL_PANE_MAPPING.ts (100%) rename src/libs/Navigation/linkingConfig/{ => RELATIONS}/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts (100%) create mode 100644 src/libs/Navigation/linkingConfig/RELATIONS/index.ts diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts rename to src/libs/Navigation/linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts diff --git a/src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts rename to src/libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts diff --git a/src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts rename to src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts diff --git a/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts rename to src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts diff --git a/src/libs/Navigation/linkingConfig/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts rename to src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/index.ts b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts b/src/libs/Navigation/linkingConfig/createSplitNavigator.ts index b016e535052e..aa1a1bef6760 100644 --- a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts +++ b/src/libs/Navigation/linkingConfig/createSplitNavigator.ts @@ -1,6 +1,6 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; import type {NavigationPartialRoute, SplitNavigatorByLHN, SplitNavigatorLHNScreen, SplitNavigatorParamListType} from '@libs/Navigation/types'; -import LHN_TO_SPLIT_NAVIGATOR_NAME from './LHN_TO_SPLIT_NAVIGATOR_MAPPING'; +import LHN_TO_SPLIT_NAVIGATOR_NAME from './RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING'; type ExtractRouteType = Extract; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index e127eaea11d0..0d4dc60758d6 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -13,12 +13,12 @@ import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Screen} from '@src/SCREENS'; import SCREENS from '@src/SCREENS'; -import CENTRAL_PANE_TO_RHP_MAPPING from './CENTRAL_PANE_TO_RHP_MAPPING'; import config, {normalizedConfigs} from './config'; import createSplitNavigator from './createSplitNavigator'; +import CENTRAL_PANE_TO_RHP_MAPPING from './RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING'; +import SEARCH_RHP_SCREENS from './RELATIONS/SEARCH_RHP_SCREENS'; +import {CENTRAL_PANE_TO_TAB_MAPPING} from './RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING'; import replacePathInNestedState from './replacePathInNestedState'; -import SEARCH_RHP_SCREENS from './SEARCH_RHP_SCREENS'; -import {CENTRAL_PANE_TO_TAB_MAPPING} from './TAB_TO_CENTRAL_PANE_MAPPING'; const RHP_SCREENS_OPENED_FROM_LHN = [ SCREENS.SETTINGS.SHARE_CODE, @@ -134,9 +134,11 @@ function getAdaptedState(state: PartialState // isWorkspaceNavigatorMandatory: true, // }; + // @TODO: It's possible we don't need such granularity of getting split navigators. Maybe just splitNavigator is enough. // We need to check what is defined to know what we need to add. - const workspaceNavigator = state.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR); - const reportNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + const workspaceSplitNavigator = state.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR); + const reportsSplitNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + const rhpNavigator = state.routes.find((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR); const lhpNavigator = state.routes.find((route) => route.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR); const onboardingModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR); @@ -182,6 +184,7 @@ function getAdaptedState(state: PartialState // metainfo, }; } + if (lhpNavigator ?? onboardingModalNavigator ?? welcomeVideoModalNavigator ?? featureTrainingModalNavigator) { // Routes // - default bottom tab @@ -222,7 +225,8 @@ function getAdaptedState(state: PartialState adaptedState: getRoutesWithIndex(routes), }; } - if (workspaceNavigator) { + + if (workspaceSplitNavigator) { // Routes // - default bottom tab // - default central pane on desktop layout @@ -241,7 +245,7 @@ function getAdaptedState(state: PartialState ), ); - routes.push(workspaceNavigator); + routes.push(workspaceSplitNavigator); return { adaptedState: getRoutesWithIndex(routes), @@ -276,9 +280,9 @@ function getAdaptedState(state: PartialState // We need to make sure that this if only handles states where we deeplink to the bottom tab directly // If policyID is defined, it should be passed to the reportNavigator params. - if (reportNavigator && policyID) { + if (reportsSplitNavigator && policyID) { const routes = []; - const reportNavigatorWithPolicyID = {...reportNavigator}; + const reportNavigatorWithPolicyID = {...reportsSplitNavigator}; reportNavigatorWithPolicyID.params = {...reportNavigatorWithPolicyID.params, policyID}; routes.push(reportNavigatorWithPolicyID); diff --git a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts index 0645a45e0924..7dc6093d7942 100644 --- a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts +++ b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts @@ -2,7 +2,7 @@ import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRo import type {BottomTabName, NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -import {CENTRAL_PANE_TO_TAB_MAPPING} from './TAB_TO_CENTRAL_PANE_MAPPING'; +import {CENTRAL_PANE_TO_TAB_MAPPING} from './RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING'; // Get the route that matches the topmost central pane route in the navigation stack. e.g REPORT -> HOME function getMatchingBottomTabRouteForState(state: State, policyID?: string): NavigationPartialRoute { diff --git a/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts index cec00f705127..7ce8cd5daac8 100644 --- a/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts +++ b/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts @@ -2,7 +2,7 @@ import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute' import type {AuthScreensParamList, CentralPaneName, NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -import TAB_TO_CENTRAL_PANE_MAPPING from './TAB_TO_CENTRAL_PANE_MAPPING'; +import TAB_TO_CENTRAL_PANE_MAPPING from './RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING'; /** * @param state - react-navigation state diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 926d288d9a61..6e2e2526e8de 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -21,7 +21,7 @@ import type {HybridAppRoute, Route as Routes} from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type EXIT_SURVEY_REASON_FORM_INPUT_IDS from '@src/types/form/ExitSurveyReasonForm'; import type {ConnectionName, SageIntacctMappingName} from '@src/types/onyx/Policy'; -import type LHN_TO_SPLIT_NAVIGATOR_NAME from './linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING'; +import type LHN_TO_SPLIT_NAVIGATOR_NAME from './linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING'; type NavigationRef = NavigationContainerRefWithCurrent; From d499b5c1321a02535c16fdf90c69fdbc7bedf5c4 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Thu, 3 Oct 2024 14:20:26 +0200 Subject: [PATCH 055/257] remove old linkTo --- src/libs/Navigation/Navigation.ts | 2 +- src/libs/Navigation/linkTo/index.ts | 234 +++--------------- .../getActionForBottomTabNavigator.ts | 50 ---- .../Navigation/newLinkTo/getMinimalAction.ts | 42 ---- src/libs/Navigation/newLinkTo/index.ts | 61 ----- src/libs/Navigation/newLinkTo/types.ts | 11 - 6 files changed, 37 insertions(+), 363 deletions(-) delete mode 100644 src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts delete mode 100644 src/libs/Navigation/newLinkTo/getMinimalAction.ts delete mode 100644 src/libs/Navigation/newLinkTo/index.ts delete mode 100644 src/libs/Navigation/newLinkTo/types.ts diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index b95fe2a7e32a..961aad46c5cf 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -24,8 +24,8 @@ import originalGetTopmostReportId from './getTopmostReportId'; import isReportOpenInRHP from './isReportOpenInRHP'; import linkingConfig from './linkingConfig'; import getMatchingBottomTabRouteForState from './linkingConfig/getMatchingBottomTabRouteForState'; +import linkTo from './linkTo'; import navigationRef from './navigationRef'; -import linkTo from './newLinkTo'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; import type {NavigationStateRoute, RootStackParamList, State, StateOrRoute} from './types'; diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 872a64d3cc8d..f8ac74d6e61f 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -1,223 +1,61 @@ import {getActionFromState} from '@react-navigation/core'; import type {NavigationContainerRef, NavigationState, PartialState} from '@react-navigation/native'; import {findFocusedRoute} from '@react-navigation/native'; -import omitBy from 'lodash/omitBy'; -import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import isReportOpenInRHP from '@libs/Navigation/isReportOpenInRHP'; -import {isCentralPaneName} from '@libs/NavigationUtils'; -import shallowCompare from '@libs/ObjectUtils'; -import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; -import getActionsFromPartialDiff from '@navigation/AppNavigator/getActionsFromPartialDiff'; -import getPartialStateDiff from '@navigation/AppNavigator/getPartialStateDiff'; -import dismissModal from '@navigation/dismissModal'; -import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; -import extrapolateStateFromParams from '@navigation/extrapolateStateFromParams'; -import getPolicyIDFromState from '@navigation/getPolicyIDFromState'; +import {shallowCompare} from '@libs/ObjectUtils'; +import {getPathWithoutPolicyID} from '@libs/PolicyUtils'; import getStateFromPath from '@navigation/getStateFromPath'; -import getTopmostBottomTabRoute from '@navigation/getTopmostBottomTabRoute'; -import getTopmostCentralPaneRoute from '@navigation/getTopmostCentralPaneRoute'; -import getTopmostReportId from '@navigation/getTopmostReportId'; -import isSideModalNavigator from '@navigation/isSideModalNavigator'; import linkingConfig from '@navigation/linkingConfig'; -import getAdaptedStateFromPath from '@navigation/linkingConfig/getAdaptedStateFromPath'; -import getMatchingBottomTabRouteForState from '@navigation/linkingConfig/getMatchingBottomTabRouteForState'; -import getMatchingCentralPaneRouteForState from '@navigation/linkingConfig/getMatchingCentralPaneRouteForState'; -import replacePathInNestedState from '@navigation/linkingConfig/replacePathInNestedState'; -import type {NavigationRoot, RootStackParamList, StackNavigationAction, State} from '@navigation/types'; +import type {RootStackParamList, StackNavigationAction} from '@navigation/types'; import CONST from '@src/CONST'; -import NAVIGATORS from '@src/NAVIGATORS'; import type {Route} from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; -import getActionForBottomTabNavigator from './getActionForBottomTabNavigator'; import getMinimalAction from './getMinimalAction'; -import type {ActionPayloadParams} from './types'; -export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string, isActiveRoute?: boolean) { - if (!navigation) { - throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); - } - let root: NavigationRoot = navigation; - let current: NavigationRoot | undefined; - // Traverse up to get the root navigation - // eslint-disable-next-line no-cond-assign - while ((current = root.getParent())) { - root = current; - } - - const pathWithoutPolicyID = getPathWithoutPolicyID(`/${path}`) as Route; - const rootState = navigation.getRootState() as NavigationState; - const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; - // Creating path with /w/ included if necessary. - const topmostCentralPaneRoute = getTopmostCentralPaneRoute(rootState); - - const extractedPolicyID = extractPolicyIDFromPath(`/${path}`); - const policyIDFromState = getPolicyIDFromState(rootState); - const policyID = extractedPolicyID ?? policyIDFromState; - const lastRoute = rootState?.routes?.at(-1); +function shouldDispatchAction(currentState: NavigationState, stateFromPath: PartialState>) { + const currentFocusedRoute = findFocusedRoute(currentState); + const targetFocusedRoute = findFocusedRoute(stateFromPath); - const isNarrowLayout = getIsNarrowLayout(); + const areNamesEqual = currentFocusedRoute?.name === targetFocusedRoute?.name; + const areParamsEqual = shallowCompare(currentFocusedRoute?.params as Record | undefined, targetFocusedRoute?.params as Record | undefined); - const isWorkspaceScreenOnTop = lastRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR; - - // policyID on SCREENS.SEARCH.CENTRAL_PANE can be present only as part of SearchQuery, while on other pages it's stored in the url in the format: /w/:policyID/ - if (policyID && !isWorkspaceScreenOnTop && !policyIDFromState) { - // The stateFromPath doesn't include proper path if there is a policy passed with /w/id. - // We need to replace the path in the state with the proper one. - // To avoid this hacky solution we may want to create custom getActionFromState function in the future. - replacePathInNestedState(stateFromPath, `/w/${policyID}${pathWithoutPolicyID}`); + if (areNamesEqual && areParamsEqual) { + return false; } - const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); - - const isReportInRhpOpened = isReportOpenInRHP(rootState); - - // If action type is different than NAVIGATE we can't change it to the PUSH safely - if (action?.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { - const actionPayloadParams = action.payload.params as ActionPayloadParams; - - const topRouteName = lastRoute?.name; - - // CentralPane screens aren't nested in any navigator, if actionPayloadParams?.screen is undefined, it means the screen name and parameters have to be read directly from action.payload - const targetName = actionPayloadParams?.screen ?? action.payload.name; - const targetParams = actionPayloadParams?.params ?? actionPayloadParams; - const isTargetNavigatorOnTop = topRouteName === action.payload.name; - - const isTargetScreenDifferentThanCurrent = !!(!topmostCentralPaneRoute || topmostCentralPaneRoute.name !== targetName); - const areParamsDifferent = - targetName === SCREENS.REPORT - ? getTopmostReportId(rootState) !== getTopmostReportId(stateFromPath) - : !shallowCompare( - omitBy(topmostCentralPaneRoute?.params as Record | undefined, (value) => value === undefined), - omitBy(targetParams as Record | undefined, (value) => value === undefined), - ); - - // If this action is navigating to the report screen and the top most navigator is different from the one we want to navigate - PUSH the new screen to the top of the stack by default - if (isCentralPaneName(action.payload.name) && (isTargetScreenDifferentThanCurrent || areParamsDifferent)) { - // We need to push a tab if the tab doesn't match the central pane route that we are going to push. - const topmostBottomTabRoute = getTopmostBottomTabRoute(rootState); - - const focusedRoute = findFocusedRoute(stateFromPath); - const policyIDFromQuery = extractPolicyIDFromQuery(focusedRoute); - const matchingBottomTabRoute = getMatchingBottomTabRouteForState(stateFromPath, policyID ?? policyIDFromQuery); - const isOpeningSearch = matchingBottomTabRoute.name === SCREENS.SEARCH.BOTTOM_TAB; - const isNewPolicyID = - ((topmostBottomTabRoute?.params as Record)?.policyID ?? '') !== - ((matchingBottomTabRoute?.params as Record)?.policyID ?? ''); - - if (topmostBottomTabRoute && (topmostBottomTabRoute.name !== matchingBottomTabRoute.name || isNewPolicyID || isOpeningSearch)) { - root.dispatch({ - type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - payload: matchingBottomTabRoute, - }); - } - - if (type === CONST.NAVIGATION.TYPE.UP) { - action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; - } else { - action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - } - - // If the type is UP, we deeplinked into one of the RHP flows and we want to replace the current screen with the previous one in the flow - // and at the same time we want the back button to go to the page we were before the deeplink - } else if (type === CONST.NAVIGATION.TYPE.UP) { - if (!areParamsDifferent && isSideModalNavigator(lastRoute?.name) && topmostCentralPaneRoute?.name === targetName) { - dismissModal(navigation); - return; - } - action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; - - // If this action is navigating to ModalNavigator or WorkspaceNavigator and the last route on the root navigator is not already opened Navigator then push - } else if ((action.payload.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR || isSideModalNavigator(action.payload.name)) && !isTargetNavigatorOnTop) { - if (isSideModalNavigator(topRouteName)) { - dismissModal(navigation); - } - - // If this RHP has mandatory central pane and bottom tab screens defined we need to push them. - const {adaptedState, metainfo} = getAdaptedStateFromPath(path, linkingConfig.config); - if (adaptedState && (metainfo.isCentralPaneAndBottomTabMandatory || metainfo.isWorkspaceNavigatorMandatory)) { - const diff = getPartialStateDiff(rootState, adaptedState as State, metainfo); - const diffActions = getActionsFromPartialDiff(diff); - for (const diffAction of diffActions) { - root.dispatch(diffAction); - } - } - // All actions related to FullScreenNavigator on wide screen are pushed when comparing differences between rootState and adaptedState. - if (action.payload.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - return; - } - action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; + return true; +} - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - } else if (action.payload.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR) { - // If path contains a policyID, we should invoke the navigate function - const shouldNavigate = !!extractedPolicyID; - const actionForBottomTabNavigator = getActionForBottomTabNavigator(action, rootState, policyID, shouldNavigate); +export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: typeof CONST.NAVIGATION.ACTION_TYPE.REPLACE) { + if (!navigation) { + throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); + } - if (!actionForBottomTabNavigator) { - return; - } + const pathWithoutPolicyID = getPathWithoutPolicyID(`/${path}`) as Route; - root.dispatch(actionForBottomTabNavigator); + // This is the state generated with the default getStateFromPath function. + // It won't include the whole state that will be generated for this path but the focused route will be correct. + // It is necessary because getActionFromState will generate RESET action for whole state generated with our custom getStateFromPath function. + const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; + const currentState = navigation.getRootState() as NavigationState; + const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); - // If the layout is wide we need to push matching central pane route to the stack. - if (!isNarrowLayout) { - // stateFromPath should always include bottom tab navigator state, so getMatchingCentralPaneRouteForState will be always defined. - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const matchingCentralPaneRoute = getMatchingCentralPaneRouteForState(stateFromPath, rootState)!; - if (matchingCentralPaneRoute && 'name' in matchingCentralPaneRoute) { - root.dispatch({ - type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - payload: { - name: matchingCentralPaneRoute.name, - params: matchingCentralPaneRoute.params, - }, - }); - } - } else { - // If the layout is small we need to pop everything from the central pane so the bottom tab navigator is visible. - root.dispatch({ - type: 'POP_TO_TOP', - target: rootState.key, - }); - } - return; - } + // We don't want to dispatch action to push/replace with exactly the same route that is already focused. + if (!shouldDispatchAction(currentState, stateFromPath)) { + return; } - if (action && 'payload' in action && action.payload && 'name' in action.payload && isSideModalNavigator(action.payload.name)) { - // Information about the state may be in the params. - const currentFocusedRoute = findFocusedRoute(extrapolateStateFromParams(rootState)); - const targetFocusedRoute = findFocusedRoute(stateFromPath); - - // If the current focused route is the same as the target focused route, we don't want to navigate. - if ( - currentFocusedRoute?.name === targetFocusedRoute?.name && - shallowCompare(currentFocusedRoute?.params as Record, targetFocusedRoute?.params as Record) - ) { - return; - } - - const minimalAction = getMinimalAction(action, navigation.getRootState()); - if (minimalAction) { - // There are situations where a route already exists on the current navigation stack - // But we want to push the same route instead of going back in the stack - // Which would break the user navigation history - if (!isActiveRoute && type === CONST.NAVIGATION.ACTION_TYPE.PUSH) { - minimalAction.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - } - root.dispatch(minimalAction); - return; - } + // If there is no action, just reset the whole state. + if (!action) { + navigation.resetRoot(stateFromPath); + return; } - // When we navigate from the ReportScreen opened in RHP, this page shouldn't be removed from the navigation state to allow users to go back to it. - if (isReportInRhpOpened && action) { + if (type === CONST.NAVIGATION.ACTION_TYPE.REPLACE) { + action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; + } else if (action.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { + // We want to PUSH by default to add entries to the browser history. action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; } - if (action !== undefined) { - root.dispatch(action); - } else { - root.reset(stateFromPath); - } + const minimalAction = getMinimalAction(action, navigation.getRootState()); + navigation.dispatch(minimalAction); } diff --git a/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts b/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts deleted file mode 100644 index 85580d068ad7..000000000000 --- a/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type {NavigationAction, NavigationState} from '@react-navigation/native'; -import type {Writable} from 'type-fest'; -import type {RootStackParamList, StackNavigationAction} from '@libs/Navigation/types'; -import getTopmostBottomTabRoute from '@navigation/getTopmostBottomTabRoute'; -import CONST from '@src/CONST'; -import type {ActionPayloadParams} from './types'; - -// Because we need to change the type to push, we also need to set target for this action to the bottom tab navigator. -function getActionForBottomTabNavigator( - action: StackNavigationAction, - state: NavigationState, - policyID?: string, - shouldNavigate?: boolean, -): Writable | undefined { - const bottomTabNavigatorRoute = state.routes.at(0); - if (!bottomTabNavigatorRoute || bottomTabNavigatorRoute.state === undefined || !action || action.type !== CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { - return; - } - - const params = action.payload.params as ActionPayloadParams; - let payloadParams = params.params as Record; - const screen = params.screen; - - if (policyID && !payloadParams?.policyID) { - payloadParams = {...payloadParams, policyID}; - } else if (!policyID) { - delete payloadParams?.policyID; - } - - // Check if the current bottom tab is the same as the one we want to navigate to. If it is, we don't need to do anything. - const bottomTabCurrentTab = getTopmostBottomTabRoute(state); - const bottomTabParams = bottomTabCurrentTab?.params as Record; - - // Verify if the policyID is different than the one we are currently on. If it is, we need to navigate to the new policyID. - const isNewPolicy = bottomTabParams?.policyID !== payloadParams?.policyID; - if (bottomTabCurrentTab?.name === screen && !shouldNavigate && !isNewPolicy) { - return; - } - - return { - type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - payload: { - name: screen, - params: payloadParams, - }, - target: bottomTabNavigatorRoute.state.key, - }; -} - -export default getActionForBottomTabNavigator; diff --git a/src/libs/Navigation/newLinkTo/getMinimalAction.ts b/src/libs/Navigation/newLinkTo/getMinimalAction.ts deleted file mode 100644 index ff01b3b8333b..000000000000 --- a/src/libs/Navigation/newLinkTo/getMinimalAction.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type {NavigationAction, NavigationState} from '@react-navigation/native'; -import type {Writable} from 'type-fest'; -import type {State} from '@navigation/types'; -import type {ActionPayload} from './types'; - -/** - * Motivation for this function is described in NAVIGATION.md - * - * @param action action generated by getActionFromState - * @param state The root state - * @returns minimalAction minimal action is the action that we should dispatch - */ -function getMinimalAction(action: NavigationAction, state: NavigationState): Writable { - let currentAction: NavigationAction = action; - let currentState: State | undefined = state; - let currentTargetKey: string | undefined; - - while (currentAction.payload && 'name' in currentAction.payload && currentState?.routes[currentState.index ?? -1].name === currentAction.payload.name) { - if (!currentState?.routes[currentState.index ?? -1].state) { - break; - } - - currentState = currentState?.routes[currentState.index ?? -1].state; - currentTargetKey = currentState?.key; - - const payload = currentAction.payload as ActionPayload; - - // Creating new smaller action - currentAction = { - type: currentAction.type, - payload: { - name: payload?.params?.screen, - params: payload?.params?.params, - path: payload?.params?.path, - }, - target: currentTargetKey, - }; - } - return currentAction; -} - -export default getMinimalAction; diff --git a/src/libs/Navigation/newLinkTo/index.ts b/src/libs/Navigation/newLinkTo/index.ts deleted file mode 100644 index f8ac74d6e61f..000000000000 --- a/src/libs/Navigation/newLinkTo/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {getActionFromState} from '@react-navigation/core'; -import type {NavigationContainerRef, NavigationState, PartialState} from '@react-navigation/native'; -import {findFocusedRoute} from '@react-navigation/native'; -import {shallowCompare} from '@libs/ObjectUtils'; -import {getPathWithoutPolicyID} from '@libs/PolicyUtils'; -import getStateFromPath from '@navigation/getStateFromPath'; -import linkingConfig from '@navigation/linkingConfig'; -import type {RootStackParamList, StackNavigationAction} from '@navigation/types'; -import CONST from '@src/CONST'; -import type {Route} from '@src/ROUTES'; -import getMinimalAction from './getMinimalAction'; - -function shouldDispatchAction(currentState: NavigationState, stateFromPath: PartialState>) { - const currentFocusedRoute = findFocusedRoute(currentState); - const targetFocusedRoute = findFocusedRoute(stateFromPath); - - const areNamesEqual = currentFocusedRoute?.name === targetFocusedRoute?.name; - const areParamsEqual = shallowCompare(currentFocusedRoute?.params as Record | undefined, targetFocusedRoute?.params as Record | undefined); - - if (areNamesEqual && areParamsEqual) { - return false; - } - - return true; -} - -export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: typeof CONST.NAVIGATION.ACTION_TYPE.REPLACE) { - if (!navigation) { - throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); - } - - const pathWithoutPolicyID = getPathWithoutPolicyID(`/${path}`) as Route; - - // This is the state generated with the default getStateFromPath function. - // It won't include the whole state that will be generated for this path but the focused route will be correct. - // It is necessary because getActionFromState will generate RESET action for whole state generated with our custom getStateFromPath function. - const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; - const currentState = navigation.getRootState() as NavigationState; - const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); - - // We don't want to dispatch action to push/replace with exactly the same route that is already focused. - if (!shouldDispatchAction(currentState, stateFromPath)) { - return; - } - - // If there is no action, just reset the whole state. - if (!action) { - navigation.resetRoot(stateFromPath); - return; - } - - if (type === CONST.NAVIGATION.ACTION_TYPE.REPLACE) { - action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; - } else if (action.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { - // We want to PUSH by default to add entries to the browser history. - action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - } - - const minimalAction = getMinimalAction(action, navigation.getRootState()); - navigation.dispatch(minimalAction); -} diff --git a/src/libs/Navigation/newLinkTo/types.ts b/src/libs/Navigation/newLinkTo/types.ts deleted file mode 100644 index 254a4cdef2a5..000000000000 --- a/src/libs/Navigation/newLinkTo/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -type ActionPayloadParams = { - screen?: string; - params?: unknown; - path?: string; -}; - -type ActionPayload = { - params?: ActionPayloadParams; -}; - -export type {ActionPayload, ActionPayloadParams}; From 18216bc95b2a39f1ad41dc92acfad33e3d42c9ee Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Mon, 7 Oct 2024 17:18:07 +0200 Subject: [PATCH 056/257] refactor getAdaptedState --- .../linkingConfig/RELATIONS/SEARCH_TO_RHP.ts | 25 ++ .../RELATIONS/SETTINGS_TO_RHP.ts | 62 ++++ .../linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts | 17 + .../RELATIONS/SIDEBAR_TO_SPLIT.ts | 10 + .../RELATIONS/WORKSPACE_TO_RHP.ts | 217 ++++++++++++ .../linkingConfig/RELATIONS/index.ts | 29 ++ src/libs/Navigation/linkingConfig/config.ts | 2 +- .../linkingConfig/getAdaptedStateFromPath.ts | 329 ++++++------------ 8 files changed, 471 insertions(+), 220 deletions(-) create mode 100644 src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts create mode 100755 src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts create mode 100644 src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts create mode 100644 src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT.ts create mode 100755 src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts new file mode 100644 index 000000000000..9d50f1735d94 --- /dev/null +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts @@ -0,0 +1,25 @@ +import SCREENS from '@src/SCREENS'; + +const SEARCH_TO_RHP: string[] = [ + SCREENS.SEARCH.REPORT_RHP, + SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_CURRENCY_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_DATE_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_DESCRIPTION_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_MERCHANT_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_REPORT_ID_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_AMOUNT_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_CATEGORY_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_KEYWORD_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_TAX_RATE_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_EXPENSE_TYPE_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_TAG_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_FROM_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_TO_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_IN_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_CARD_RHP, + SCREENS.SEARCH.SAVED_SEARCH_RENAME_RHP, +]; + +export default SEARCH_TO_RHP; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts new file mode 100755 index 000000000000..824fc072d686 --- /dev/null +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts @@ -0,0 +1,62 @@ +import SCREENS from '@src/SCREENS'; + +// const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = { +const CENTRAL_PANE_TO_RHP_MAPPING: Record = { + [SCREENS.SETTINGS.PROFILE.ROOT]: [ + SCREENS.SETTINGS.PROFILE.DISPLAY_NAME, + SCREENS.SETTINGS.PROFILE.CONTACT_METHODS, + SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS, + SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_VALIDATE_ACTION, + SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD, + SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER, + SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_DATE, + SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_TIME, + SCREENS.SETTINGS.PROFILE.STATUS, + SCREENS.SETTINGS.PROFILE.PRONOUNS, + SCREENS.SETTINGS.PROFILE.TIMEZONE, + SCREENS.SETTINGS.PROFILE.TIMEZONE_SELECT, + SCREENS.SETTINGS.PROFILE.LEGAL_NAME, + SCREENS.SETTINGS.PROFILE.DATE_OF_BIRTH, + SCREENS.SETTINGS.PROFILE.ADDRESS, + SCREENS.SETTINGS.PROFILE.ADDRESS_COUNTRY, + SCREENS.SETTINGS.SHARE_CODE, + SCREENS.SETTINGS.EXIT_SURVEY.REASON, + SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE, + SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM, + ], + [SCREENS.SETTINGS.PREFERENCES.ROOT]: [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, SCREENS.SETTINGS.PREFERENCES.LANGUAGE, SCREENS.SETTINGS.PREFERENCES.THEME], + [SCREENS.SETTINGS.WALLET.ROOT]: [ + SCREENS.SETTINGS.WALLET.DOMAIN_CARD, + SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.NAME, + SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.PHONE, + SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.ADDRESS, + SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.CONFIRM, + SCREENS.SETTINGS.WALLET.TRANSFER_BALANCE, + SCREENS.SETTINGS.WALLET.CHOOSE_TRANSFER_ACCOUNT, + SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS, + SCREENS.SETTINGS.WALLET.CARD_ACTIVATE, + SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD, + SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS, + ], + [SCREENS.SETTINGS.SECURITY]: [ + SCREENS.SETTINGS.TWO_FACTOR_AUTH, + SCREENS.SETTINGS.CLOSE, + SCREENS.SETTINGS.DELEGATE.ADD_DELEGATE, + SCREENS.SETTINGS.DELEGATE.DELEGATE_ROLE, + SCREENS.SETTINGS.DELEGATE.DELEGATE_CONFIRM, + SCREENS.SETTINGS.DELEGATE.DELEGATE_MAGIC_CODE, + ], + [SCREENS.SETTINGS.ABOUT]: [SCREENS.SETTINGS.APP_DOWNLOAD_LINKS], + [SCREENS.SETTINGS.SAVE_THE_WORLD]: [SCREENS.I_KNOW_A_TEACHER, SCREENS.INTRO_SCHOOL_PRINCIPAL, SCREENS.I_AM_A_TEACHER], + [SCREENS.SETTINGS.TROUBLESHOOT]: [SCREENS.SETTINGS.CONSOLE], + [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: [ + SCREENS.SETTINGS.SUBSCRIPTION.ADD_PAYMENT_CARD, + SCREENS.SETTINGS.SUBSCRIPTION.SIZE, + SCREENS.SETTINGS.SUBSCRIPTION.DISABLE_AUTO_RENEW_SURVEY, + SCREENS.SETTINGS.SUBSCRIPTION.REQUEST_EARLY_CANCELLATION, + SCREENS.SETTINGS.SUBSCRIPTION.CHANGE_BILLING_CURRENCY, + SCREENS.SETTINGS.SUBSCRIPTION.CHANGE_PAYMENT_CURRENCY, + ], +}; + +export default CENTRAL_PANE_TO_RHP_MAPPING; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts new file mode 100644 index 000000000000..ba006376940e --- /dev/null +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts @@ -0,0 +1,17 @@ +import SCREENS from '@src/SCREENS'; + +const SIDEBAR_TO_RHP: Record = { + // @TODO are those really all to home? + [SCREENS.HOME]: [ + SCREENS.SETTINGS.SHARE_CODE, + SCREENS.SETTINGS.PROFILE.STATUS, + SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, + SCREENS.MONEY_REQUEST.CREATE, + SCREENS.SETTINGS.EXIT_SURVEY.REASON, + SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE, + SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM, + SCREENS.HOME, + ], +}; + +export default SIDEBAR_TO_RHP; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT.ts new file mode 100644 index 000000000000..597f6dcd4ccb --- /dev/null +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT.ts @@ -0,0 +1,10 @@ +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; + +const SIDEBAR_TO_SPLIT = { + [SCREENS.SETTINGS.ROOT]: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, + [SCREENS.HOME]: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, + [SCREENS.WORKSPACE.INITIAL]: NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, +}; + +export default SIDEBAR_TO_SPLIT; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts new file mode 100755 index 000000000000..51c8642bd7cb --- /dev/null +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts @@ -0,0 +1,217 @@ +import type {WorkspaceScreenName} from '@libs/Navigation/types'; +import SCREENS from '@src/SCREENS'; + +const WORKSPACE_TO_RHP: Partial> = { + [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.ADDRESS, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE], + [SCREENS.WORKSPACE.MEMBERS]: [ + SCREENS.WORKSPACE.INVITE, + SCREENS.WORKSPACE.INVITE_MESSAGE, + SCREENS.WORKSPACE.MEMBER_DETAILS, + SCREENS.WORKSPACE.MEMBER_NEW_CARD, + SCREENS.WORKSPACE.OWNER_CHANGE_CHECK, + SCREENS.WORKSPACE.OWNER_CHANGE_SUCCESS, + SCREENS.WORKSPACE.OWNER_CHANGE_ERROR, + SCREENS.WORKSPACE.OWNER_CHANGE_ERROR, + SCREENS.WORKSPACE.MEMBERS_IMPORT, + SCREENS.WORKSPACE.MEMBERS_IMPORTED, + ], + [SCREENS.WORKSPACE.WORKFLOWS]: [ + SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_NEW, + SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EDIT, + SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EXPENSES_FROM, + SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_APPROVER, + SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY, + SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET, + SCREENS.WORKSPACE.WORKFLOWS_PAYER, + ], + [SCREENS.WORKSPACE.ACCOUNTING.ROOT]: [ + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CLASSES, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_TAXES, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_LOCATIONS, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CUSTOMERS, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_INVOICE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_COMPANY_CARD_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_NON_REIMBURSABLE_DEFAULT_VENDOR_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_CHART_OF_ACCOUNTS, + SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION, + SCREENS.WORKSPACE.ACCOUNTING.XERO_CUSTOMER, + SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES, + SCREENS.WORKSPACE.ACCOUNTING.XERO_TRACKING_CATEGORIES, + SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_TRACKING_CATEGORY, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_PURCHASE_BILL_DATE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_STATUS_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_PREFERRED_EXPORTER_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_BANK_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_SUBSIDIARY_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_REUSE_EXISTING_CONNECTIONS, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_TOKEN_INPUT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_MAPPING, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_VIEW, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_EDIT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_LIST_ADD, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_SEGMENT_ADD, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_PREFERRED_EXPORTER_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_DATE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_DESTINATION_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_VENDOR_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_PAYABLE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_JOURNAL_POSTING_PREFERENCE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_RECEIVABLE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_INVOICE_ITEM_PREFERENCE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_INVOICE_ITEM_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_TAX_POSTING_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_PROVINCIAL_TAX_POSTING_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_REIMBURSEMENT_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_COLLECTION_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPENSE_REPORT_APPROVAL_LEVEL_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_VENDOR_BILL_APPROVAL_LEVEL_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_JOURNAL_ENTRY_APPROVAL_LEVEL_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_APPROVAL_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_CUSTOM_FORM_ID, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PREREQUISITES, + SCREENS.WORKSPACE.ACCOUNTING.ENTER_SAGE_INTACCT_CREDENTIALS, + SCREENS.WORKSPACE.ACCOUNTING.EXISTING_SAGE_INTACCT_CONNECTIONS, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ENTITY, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_MAPPING_TYPE, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_TOGGLE_MAPPING, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_USER_DIMENSIONS, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ADD_USER_DIMENSION, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EDIT_USER_DIMENSION, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PREFERRED_EXPORTER, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EXPORT_DATE, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_REIMBURSABLE_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_REIMBURSABLE_DESTINATION, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_DESTINATION, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_DEFAULT_VENDOR, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_CREDIT_CARD_ACCOUNT, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PAYMENT_ACCOUNT, + SCREENS.WORKSPACE.ACCOUNTING.CARD_RECONCILIATION, + SCREENS.WORKSPACE.ACCOUNTING.RECONCILIATION_ACCOUNT_SETTINGS, + ], + [SCREENS.WORKSPACE.TAXES]: [ + SCREENS.WORKSPACE.TAXES_SETTINGS, + SCREENS.WORKSPACE.TAX_CREATE, + SCREENS.WORKSPACE.TAXES_SETTINGS_CUSTOM_TAX_NAME, + SCREENS.WORKSPACE.TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT, + SCREENS.WORKSPACE.TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT, + SCREENS.WORKSPACE.TAX_CREATE, + SCREENS.WORKSPACE.TAX_EDIT, + SCREENS.WORKSPACE.TAX_NAME, + SCREENS.WORKSPACE.TAX_VALUE, + SCREENS.WORKSPACE.TAX_CODE, + ], + [SCREENS.WORKSPACE.TAGS]: [ + SCREENS.WORKSPACE.TAGS_SETTINGS, + SCREENS.WORKSPACE.TAGS_EDIT, + SCREENS.WORKSPACE.TAG_CREATE, + SCREENS.WORKSPACE.TAG_SETTINGS, + SCREENS.WORKSPACE.TAG_EDIT, + SCREENS.WORKSPACE.TAG_LIST_VIEW, + SCREENS.WORKSPACE.TAG_GL_CODE, + SCREENS.WORKSPACE.TAG_APPROVER, + SCREENS.WORKSPACE.TAGS_IMPORT, + SCREENS.WORKSPACE.TAGS_IMPORTED, + ], + [SCREENS.WORKSPACE.CATEGORIES]: [ + SCREENS.WORKSPACE.CATEGORY_CREATE, + SCREENS.WORKSPACE.CATEGORY_SETTINGS, + SCREENS.WORKSPACE.CATEGORIES_IMPORT, + SCREENS.WORKSPACE.CATEGORIES_IMPORTED, + SCREENS.WORKSPACE.CATEGORIES_SETTINGS, + SCREENS.WORKSPACE.CATEGORY_EDIT, + SCREENS.WORKSPACE.CATEGORY_GL_CODE, + SCREENS.WORKSPACE.CATEGORY_PAYROLL_CODE, + SCREENS.WORKSPACE.CATEGORY_DEFAULT_TAX_RATE, + SCREENS.WORKSPACE.CATEGORY_FLAG_AMOUNTS_OVER, + SCREENS.WORKSPACE.CATEGORY_DESCRIPTION_HINT, + SCREENS.WORKSPACE.CATEGORY_APPROVER, + SCREENS.WORKSPACE.CATEGORY_REQUIRE_RECEIPTS_OVER, + ], + [SCREENS.WORKSPACE.DISTANCE_RATES]: [ + SCREENS.WORKSPACE.CREATE_DISTANCE_RATE, + SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS, + SCREENS.WORKSPACE.DISTANCE_RATE_EDIT, + SCREENS.WORKSPACE.DISTANCE_RATE_TAX_RECLAIMABLE_ON_EDIT, + SCREENS.WORKSPACE.DISTANCE_RATE_TAX_RATE_EDIT, + SCREENS.WORKSPACE.DISTANCE_RATE_DETAILS, + ], + [SCREENS.WORKSPACE.REPORT_FIELDS]: [ + SCREENS.WORKSPACE.REPORT_FIELDS_CREATE, + SCREENS.WORKSPACE.REPORT_FIELDS_SETTINGS, + SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES, + SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE, + SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS, + SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE, + SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE, + ], + [SCREENS.WORKSPACE.INVOICES]: [SCREENS.WORKSPACE.INVOICES_COMPANY_NAME, SCREENS.WORKSPACE.INVOICES_COMPANY_WEBSITE], + [SCREENS.WORKSPACE.COMPANY_CARDS]: [ + SCREENS.WORKSPACE.COMPANY_CARDS_SELECT_FEED, + SCREENS.WORKSPACE.COMPANY_CARDS_ADD_NEW, + SCREENS.WORKSPACE.COMPANY_CARDS_TYPE, + SCREENS.WORKSPACE.COMPANY_CARDS_INSTRUCTIONS, + SCREENS.WORKSPACE.COMPANY_CARDS_NAME, + SCREENS.WORKSPACE.COMPANY_CARDS_DETAILS, + SCREENS.WORKSPACE.COMPANY_CARDS_SELECT_FEED, + SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS, + SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS_FEED_NAME, + SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS, + SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS_FEED_NAME, + SCREENS.WORKSPACE.COMPANY_CARDS_ASSIGN_CARD, + SCREENS.WORKSPACE.COMPANY_CARD_DETAILS, + SCREENS.WORKSPACE.COMPANY_CARD_NAME, + SCREENS.WORKSPACE.COMPANY_CARD_EXPORT, + ], + [SCREENS.WORKSPACE.EXPENSIFY_CARD]: [ + SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW, + SCREENS.WORKSPACE.EXPENSIFY_CARD_BANK_ACCOUNT, + SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS, + SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_ACCOUNT, + SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_FREQUENCY, + SCREENS.WORKSPACE.EXPENSIFY_CARD_DETAILS, + SCREENS.WORKSPACE.EXPENSIFY_CARD_NAME, + SCREENS.WORKSPACE.EXPENSIFY_CARD_LIMIT, + SCREENS.WORKSPACE.EXPENSIFY_CARD_LIMIT_TYPE, + ], + [SCREENS.WORKSPACE.RULES]: [ + SCREENS.WORKSPACE.RULES_CUSTOM_NAME, + SCREENS.WORKSPACE.RULES_AUTO_APPROVE_REPORTS_UNDER, + SCREENS.WORKSPACE.RULES_RANDOM_REPORT_AUDIT, + SCREENS.WORKSPACE.RULES_AUTO_PAY_REPORTS_UNDER, + SCREENS.WORKSPACE.RULES_RECEIPT_REQUIRED_AMOUNT, + SCREENS.WORKSPACE.RULES_MAX_EXPENSE_AMOUNT, + SCREENS.WORKSPACE.RULES_MAX_EXPENSE_AGE, + SCREENS.WORKSPACE.RULES_BILLABLE_DEFAULT, + ], +}; + +export default WORKSPACE_TO_RHP; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/index.ts b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts index e69de29bb2d1..4e3e6d7543e2 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/index.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts @@ -0,0 +1,29 @@ +import SEARCH_TO_RHP from './SEARCH_TO_RHP'; +import SETTINGS_TO_RHP from './SETTINGS_TO_RHP'; +import SIDEBAR_TO_RHP from './SIDEBAR_TO_RHP'; +import SIDEBAR_TO_SPLIT from './SIDEBAR_TO_SPLIT'; +import WORKSPACE_TO_RHP from './WORKSPACE_TO_RHP'; + +// @TODO: fix types +function createInverseRelation(relations: Record): Record { + const reversedRelations = {} as Record; + + Object.entries(relations).forEach(([key, values]) => { + const valuesWithType = values as K[]; + valuesWithType.forEach((value: K) => { + reversedRelations[value] = key as T; + }); + }); + return reversedRelations; +} + +export default { + SETTINGS_TO_RHP, + RHP_TO_SETTINGS: createInverseRelation(SETTINGS_TO_RHP), + RHP_TO_WORKSPACE: createInverseRelation(WORKSPACE_TO_RHP), + RHP_TO_SIDEBAR: createInverseRelation(SIDEBAR_TO_RHP), + SEARCH_TO_RHP, + SIDEBAR_TO_RHP, + WORKSPACE_TO_RHP, + SIDEBAR_TO_SPLIT, +}; diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 210db4ef6fad..aa541bf12f5b 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -10,7 +10,7 @@ import createNormalizedConfigs from './createNormalizedConfigs'; // Moved to a separate file to avoid cyclic dependencies. const config: LinkingOptions['config'] = { // initialRouteName: NAVIGATORS.BOTTOM_TAB_NAVIGATOR, - initialRouteName: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, + // initialRouteName: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, screens: { // Main Routes [SCREENS.VALIDATE_LOGIN]: ROUTES.VALIDATE_LOGIN, diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 0d4dc60758d6..07dc2863c3ca 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -1,62 +1,26 @@ import type {NavigationState, PartialState, Route} from '@react-navigation/native'; import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import pick from 'lodash/pick'; -import type {TupleToUnion} from 'type-fest'; import {isAnonymousUser} from '@libs/actions/Session'; -import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import type {NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; +import type {NavigationPartialRoute, RootStackParamList, SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; -import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Screen} from '@src/SCREENS'; import SCREENS from '@src/SCREENS'; import config, {normalizedConfigs} from './config'; import createSplitNavigator from './createSplitNavigator'; -import CENTRAL_PANE_TO_RHP_MAPPING from './RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING'; -import SEARCH_RHP_SCREENS from './RELATIONS/SEARCH_RHP_SCREENS'; -import {CENTRAL_PANE_TO_TAB_MAPPING} from './RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING'; +import RELATIONS from './RELATIONS'; import replacePathInNestedState from './replacePathInNestedState'; -const RHP_SCREENS_OPENED_FROM_LHN = [ - SCREENS.SETTINGS.SHARE_CODE, - SCREENS.SETTINGS.PROFILE.STATUS, - SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, - SCREENS.MONEY_REQUEST.CREATE, - SCREENS.SETTINGS.EXIT_SURVEY.REASON, - SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE, - SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM, -] satisfies Screen[]; - -const mapLhnToSplitNavigatorName = { - [SCREENS.SETTINGS.ROOT]: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, - [SCREENS.HOME]: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, - [SCREENS.WORKSPACE.INITIAL]: NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, -}; - -type RHPScreenOpenedFromLHN = TupleToUnion; - -type Metainfo = { - // Sometimes modal screens don't have information about what should be visible under the overlay. - // That means such screen can have different screens under the overlay depending on what was already in the state. - // If the screens in the bottom tab and central pane are not mandatory for this state, we want to have this information. - // It will help us later with creating proper diff betwen current and desired state. - isCentralPaneAndBottomTabMandatory: boolean; - isWorkspaceNavigatorMandatory: boolean; -}; - type GetAdaptedStateReturnType = { adaptedState: ReturnType; - // metainfo: Metainfo; }; type GetAdaptedStateFromPath = (...args: [...Parameters, shouldReplacePathInNestedState?: boolean]) => GetAdaptedStateReturnType; -type SplitNavigatorLHNScreen = keyof typeof mapLhnToSplitNavigatorName; -type SplitNavigator = (typeof mapLhnToSplitNavigatorName)[SplitNavigatorLHNScreen]; - // The function getPathFromState that we are using in some places isn't working correctly without defined index. const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState => ({routes, index: routes.length - 1}); @@ -68,226 +32,154 @@ function getParamsFromRoute(screenName: string): string[] { return route.match(/(?<=[:?&])(\w+)(?=[/=?&]|$)/g) ?? []; } -// This function will return CentralPaneNavigator route or WorkspaceNavigator route. -function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): NavigationPartialRoute | NavigationPartialRoute<'Search_Central_Pane'> | undefined { - // Check for backTo param. One screen with different backTo value may need diferent screens visible under the overlay. - if (route.params && 'backTo' in route.params && typeof route.params.backTo === 'string') { - const stateForBackTo = getStateFromPath(route.params.backTo, config); - if (stateForBackTo) { - // If there is rhpNavigator in the state generated for backTo url, we want to get root route matching to this rhp screen. - const rhpNavigator = stateForBackTo.routes.find((rt) => rt.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR); - if (rhpNavigator && rhpNavigator.state) { - const isRHPinState = stateForBackTo.routes.at(0)?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR; - - if (isRHPinState) { - return getMatchingRootRouteForRHPRoute(findFocusedRoute(stateForBackTo) as NavigationPartialRoute); - } - } - - const splitNavigator = stateForBackTo.routes.find( - // eslint-disable-next-line @typescript-eslint/no-shadow - (route) => route.name.endsWith('SplitNavigator'), - ); - - // If we know that backTo targets the root route (central pane or full screen) we want to use it. - if (splitNavigator && splitNavigator.state) { - return splitNavigator as NavigationPartialRoute; - } - } +function isRouteWithBackToParam(route: NavigationPartialRoute): route is Route { + return route.params !== undefined && 'backTo' in route.params && typeof route.params.backTo === 'string'; +} + +function isRouteWithReportID(route: NavigationPartialRoute): route is Route { + return route.params !== undefined && 'reportID' in route.params && typeof route.params.reportID === 'string'; +} + +function getMatchingFullScreenRouteForState(state: PartialState>) { + const focusedRoute = findFocusedRoute(state); + + if (!focusedRoute) { + return undefined; } - // Check for CentralPaneNavigator - for (const [centralPaneName, RHPNames] of Object.entries(CENTRAL_PANE_TO_RHP_MAPPING)) { - if (RHPNames.includes(route.name)) { - const paramsFromRoute = getParamsFromRoute(centralPaneName); - return createSplitNavigator( - {name: CENTRAL_PANE_TO_TAB_MAPPING[centralPaneName as SplitNavigatorScreenName] as SplitNavigatorLHNScreen, params: pick(route.params, paramsFromRoute)}, - { - name: centralPaneName, - params: pick(route.params, paramsFromRoute), - }, - ); + // Check for backTo param. One screen with different backTo value may need different screens visible under the overlay. + if (isRouteWithBackToParam(focusedRoute)) { + const stateForBackTo = getStateFromPath(focusedRoute.params.backTo, config); + + // This may happen if the backTo url is invalid. + const lastRoute = stateForBackTo?.routes.at(-1); + if (!stateForBackTo || !lastRoute || lastRoute.name === SCREENS.NOT_FOUND) { + return undefined; } + + const isLastRouteFullScreen = isFullScreenRoute(lastRoute); + + // If the state for back to last route is a full screen route, we can use it + if (isLastRouteFullScreen) { + return lastRoute; + } + + // If not, get the matching full screen route for the back to state. + return getMatchingFullScreenRouteForState(stateForBackTo as PartialState>); } - if (SEARCH_RHP_SCREENS.includes(route.name)) { + if (RELATIONS.SEARCH_TO_RHP.includes(focusedRoute.name)) { const paramsFromRoute = getParamsFromRoute(SCREENS.SEARCH.CENTRAL_PANE); return { name: SCREENS.SEARCH.CENTRAL_PANE, - params: pick(route.params, paramsFromRoute), + params: pick(focusedRoute.params, paramsFromRoute), }; } - // check for valid reportID in the route params - // if the reportID is valid, we should navigate back to screen report in CPN - const reportID = (route.params as Record)?.reportID; - if (ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportID) { - return createSplitNavigator({name: SCREENS.HOME}, {name: SCREENS.REPORT, params: {reportID}}); + if (RELATIONS.RHP_TO_SIDEBAR[focusedRoute.name]) { + // @TODO: Figure out better types for this. + return createSplitNavigator({ + name: RELATIONS.RHP_TO_SIDEBAR[focusedRoute.name] as typeof SCREENS.HOME, + }); } -} -function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { - const isNarrowLayout = getIsNarrowLayout(); - // const metainfo = { - // isCentralPaneAndBottomTabMandatory: true, - // isWorkspaceNavigatorMandatory: true, - // }; - - // @TODO: It's possible we don't need such granularity of getting split navigators. Maybe just splitNavigator is enough. - // We need to check what is defined to know what we need to add. - const workspaceSplitNavigator = state.routes.find((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR); - const reportsSplitNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); - - const rhpNavigator = state.routes.find((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR); - const lhpNavigator = state.routes.find((route) => route.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR); - const onboardingModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR); - const welcomeVideoModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.WELCOME_VIDEO_MODAL_NAVIGATOR); - const attachmentsScreen = state.routes.find((route) => route.name === SCREENS.ATTACHMENTS); - const featureTrainingModalNavigator = state.routes.find((route) => route.name === NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR); - - if (rhpNavigator) { - // Routes - // - matching bottom tab - // - matching root route for rhp - // - found rhp - - // This one will be defined because rhpNavigator is defined. - const focusedRHPRoute = findFocusedRoute(state); - const routes = []; - - if (focusedRHPRoute) { - let matchingRootRoute = getMatchingRootRouteForRHPRoute(focusedRHPRoute); - const isRHPScreenOpenedFromLHN = focusedRHPRoute?.name && RHP_SCREENS_OPENED_FROM_LHN.includes(focusedRHPRoute?.name as RHPScreenOpenedFromLHN); - // This may happen if this RHP doesn't have a route that should be under the overlay defined. - if (!matchingRootRoute || isRHPScreenOpenedFromLHN) { - // metainfo.isCentralPaneAndBottomTabMandatory = false; - // metainfo.isWorkspaceNavigatorMandatory = false; - // If matchingRootRoute is undefined and it's a narrow layout, don't add a report screen under the RHP. - matchingRootRoute = matchingRootRoute ?? (!isNarrowLayout ? createSplitNavigator({name: SCREENS.HOME}, {name: SCREENS.REPORT}) : createSplitNavigator({name: SCREENS.HOME})); - } - - // When we open a screen in RHP from WorkspaceNavigator, we need to add the appropriate screen in CentralPane. - // Then, when we close WorkspaceNavigator, we will be redirected to the correct page in CentralPane. - if (matchingRootRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - routes.push(createSplitNavigator({name: SCREENS.SETTINGS.ROOT}, {name: SCREENS.SETTINGS.WORKSPACES})); - } - - if (matchingRootRoute && (!isNarrowLayout || !isRHPScreenOpenedFromLHN)) { - routes.push(matchingRootRoute); - } - } + // @TODO We can think about handling it in one condition. + if (RELATIONS.RHP_TO_WORKSPACE[focusedRoute.name]) { + const paramsFromRoute = getParamsFromRoute(SCREENS.SEARCH.CENTRAL_PANE); - routes.push(rhpNavigator); - return { - adaptedState: getRoutesWithIndex(routes), - // metainfo, - }; + return createSplitNavigator( + { + name: SCREENS.WORKSPACE.INITIAL, + }, + { + name: RELATIONS.RHP_TO_WORKSPACE[focusedRoute.name], + params: { + ...pick(focusedRoute.params, paramsFromRoute), + }, + }, + ); } - if (lhpNavigator ?? onboardingModalNavigator ?? welcomeVideoModalNavigator ?? featureTrainingModalNavigator) { - // Routes - // - default bottom tab - // - default central pane on desktop layout - // - found lhp / onboardingModalNavigator - - // There is no screen in these navigators that would have mandatory central pane, bottom tab or workspace navigator. - // metainfo.isCentralPaneAndBottomTabMandatory = false; - // metainfo.isWorkspaceNavigatorMandatory = false; - const routes = []; + if (RELATIONS.RHP_TO_SETTINGS[focusedRoute.name]) { + const paramsFromRoute = getParamsFromRoute(SCREENS.SEARCH.CENTRAL_PANE); - const splitNavigatorMainScreen = !isNarrowLayout - ? { - name: SCREENS.REPORT, - } - : undefined; + return createSplitNavigator( + { + name: SCREENS.SETTINGS.ROOT, + }, + { + name: RELATIONS.RHP_TO_SETTINGS[focusedRoute.name] as keyof SettingsSplitNavigatorParamList, + params: { + ...pick(focusedRoute.params, paramsFromRoute), + }, + }, + ); + } - routes.push(createSplitNavigator({name: SCREENS.HOME}, splitNavigatorMainScreen)); + // @TODO should we push this route on narrow layout? + // @TODO maybe we can handle this with regular flow. + if (isRouteWithReportID(focusedRoute)) { + const reportID = focusedRoute.params.reportID; + const paramsFromRoute = getParamsFromRoute(SCREENS.REPORT); - // Separate ifs are necessary for typescript to see that we are not pushing undefined to the array. - if (lhpNavigator) { - routes.push(lhpNavigator); + if (!ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportID) { + return; } - if (onboardingModalNavigator) { - routes.push(onboardingModalNavigator); - } + return createSplitNavigator( + { + name: SCREENS.HOME, + }, + { + name: SCREENS.REPORT, + params: { + reportID: '-1', + ...pick(focusedRoute.params, paramsFromRoute), + }, + }, + ); + } - if (welcomeVideoModalNavigator) { - routes.push(welcomeVideoModalNavigator); - } + return undefined; +} - if (featureTrainingModalNavigator) { - routes.push(featureTrainingModalNavigator); - } +const FULL_SCREEN_ROUTES: string[] = [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, SCREENS.SEARCH.CENTRAL_PANE]; - return { - adaptedState: getRoutesWithIndex(routes), - }; - } +function isFullScreenRoute(route: NavigationPartialRoute): boolean { + return FULL_SCREEN_ROUTES.includes(route.name); +} - if (workspaceSplitNavigator) { - // Routes - // - default bottom tab - // - default central pane on desktop layout - // - found workspace navigator +function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { + const fullScreenRoute = state.routes.find(isFullScreenRoute); + const reportsSplitNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + // If policyID is defined, it should be passed to the reportNavigator params. + if (reportsSplitNavigator && policyID) { const routes = []; - routes.push( - createSplitNavigator( - {name: SCREENS.SETTINGS.ROOT}, - { - name: SCREENS.SETTINGS.WORKSPACES, - params: { - policyID, - }, - }, - ), - ); - - routes.push(workspaceSplitNavigator); + const reportNavigatorWithPolicyID = {...reportsSplitNavigator}; + reportNavigatorWithPolicyID.params = {...reportNavigatorWithPolicyID.params, policyID}; + routes.push(reportNavigatorWithPolicyID); return { adaptedState: getRoutesWithIndex(routes), }; } - if (attachmentsScreen) { - // Routes - // - matching bottom tab - // - central pane (report screen) of the attachment - // - found report attachments - const routes = []; - const reportAttachments = attachmentsScreen as Route<'Attachments', RootStackParamList['Attachments']>; - - if (reportAttachments.params?.type === CONST.ATTACHMENT_TYPE.REPORT) { - const splitNavigatorMainScreen = !isNarrowLayout - ? { - name: SCREENS.REPORT, - params: {reportID: reportAttachments.params?.reportID ?? '-1'}, - } - : undefined; - - routes.push(createSplitNavigator({name: SCREENS.HOME}, splitNavigatorMainScreen)); - routes.push(reportAttachments); + // If there is no full screen route in the root, we want to add it. + if (!fullScreenRoute) { + const matchingRootRoute = getMatchingFullScreenRouteForState(state); + // If there is a matching root route, add it to the state. + if (matchingRootRoute) { return { - adaptedState: getRoutesWithIndex(routes), + adaptedState: getRoutesWithIndex([matchingRootRoute, ...state.routes]), }; } - } - - // We need to make sure that this if only handles states where we deeplink to the bottom tab directly - - // If policyID is defined, it should be passed to the reportNavigator params. - if (reportsSplitNavigator && policyID) { - const routes = []; - const reportNavigatorWithPolicyID = {...reportsSplitNavigator}; - reportNavigatorWithPolicyID.params = {...reportNavigatorWithPolicyID.params, policyID}; - routes.push(reportNavigatorWithPolicyID); + // If not, add the default full screen route. return { - adaptedState: getRoutesWithIndex(routes), + adaptedState: getRoutesWithIndex([{name: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR}, ...state.routes]), }; } @@ -321,4 +213,3 @@ const getAdaptedStateFromPath: GetAdaptedStateFromPath = (path, options, shouldR }; export default getAdaptedStateFromPath; -export type {Metainfo}; From 6860510e343784e449d1ce360a50dfbf0d06a35a Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Mon, 7 Oct 2024 17:38:19 +0200 Subject: [PATCH 057/257] fix prettier --- src/components/ActiveWorkspaceProvider/index.tsx | 2 +- src/pages/settings/InitialSettingsPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index 1a9e32edf866..d306226a85c2 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -57,4 +57,4 @@ function ActiveWorkspaceContextProvider({children}: ChildrenProps) { } export default ActiveWorkspaceContextProvider; -export {}; \ No newline at end of file +export {}; diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 4a014fdcfb25..32ca20741d07 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -413,7 +413,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr scrollEventThrottle={16} contentContainerStyle={[styles.w100]} showsVerticalScrollIndicator={false} - > + > {accountMenuItems} {workspaceMenuItems} {generalMenuItems} From 5f6fe491f5f0a3d26265bcc8e95bc51d515d9294 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 8 Oct 2024 09:04:24 +0200 Subject: [PATCH 058/257] Remove w param from navigate when navigating to chats from bottom tab --- .../createCustomBottomTabNavigator/BottomTabBar.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index accac709b6ea..7e0d153adbc3 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -24,7 +24,6 @@ import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFl import variables from '@styles/variables'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; @@ -76,9 +75,9 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { if (selectedTab === SCREENS.HOME) { return; } - const route = activeWorkspaceID ? (`/w/${activeWorkspaceID}/${ROUTES.HOME}` as Route) : ROUTES.HOME; - Navigation.navigate(route); - }, [activeWorkspaceID, selectedTab]); + + Navigation.navigate(ROUTES.HOME); + }, [selectedTab]); const navigateToSearch = useCallback(() => { if (selectedTab === SCREENS.SEARCH.BOTTOM_TAB) { From 4fe5789c76351343d0435827dd0ee06f736376f0 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 30 Sep 2024 13:18:10 +0200 Subject: [PATCH 059/257] Add template of goUp --- src/libs/Navigation/Navigation.ts | 186 ++++++++++++------- src/pages/home/sidebar/BottomTabAvatar.tsx | 12 +- src/pages/workspace/WorkspaceInitialPage.tsx | 11 +- 3 files changed, 119 insertions(+), 90 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 961aad46c5cf..c864985bcfd5 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -1,9 +1,9 @@ -import {findFocusedRoute} from '@react-navigation/core'; +import {findFocusedRoute, getActionFromState} from '@react-navigation/core'; import type {EventArg, NavigationContainerEventMap} from '@react-navigation/native'; import {CommonActions, getPathFromState, StackActions} from '@react-navigation/native'; import type {OnyxEntry} from 'react-native-onyx'; import Log from '@libs/Log'; -import {isCentralPaneName, removePolicyIDParamFromState} from '@libs/NavigationUtils'; +import {removePolicyIDParamFromState} from '@libs/NavigationUtils'; import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils'; import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; @@ -17,17 +17,17 @@ import type {Report} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import originalCloseRHPFlow from './closeRHPFlow'; import getPolicyIDFromState from './getPolicyIDFromState'; -import getTopmostBottomTabRoute from './getTopmostBottomTabRoute'; +import getStateFromPath from './getStateFromPath'; import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute'; import originalGetTopmostReportActionId from './getTopmostReportActionID'; import originalGetTopmostReportId from './getTopmostReportId'; import isReportOpenInRHP from './isReportOpenInRHP'; import linkingConfig from './linkingConfig'; -import getMatchingBottomTabRouteForState from './linkingConfig/getMatchingBottomTabRouteForState'; import linkTo from './linkTo'; +import getMinimalAction from './linkTo/getMinimalAction'; import navigationRef from './navigationRef'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; -import type {NavigationStateRoute, RootStackParamList, State, StateOrRoute} from './types'; +import type {NavigationStateRoute, RootStackParamList, StackNavigationAction, State, StateOrRoute} from './types'; let resolveNavigationIsReadyPromise: () => void; const navigationIsReadyPromise = new Promise((resolve) => { @@ -111,8 +111,8 @@ function parseHybridAppUrl(url: HybridAppRoute | Route): Route { * @param path - Path that you are looking for. * @return - Returns distance to path or -1 if the path is not found in root navigator. */ -function getDistanceFromPathInRootNavigator(path?: string): number { - let currentState = navigationRef.getRootState(); +function getDistanceFromPathInRootNavigator(state: State, path?: string): number { + let currentState = {...state}; for (let index = 0; index < 5; index++) { if (!currentState.routes.length) { @@ -188,7 +188,7 @@ function navigate(route: Route = ROUTES.HOME, type?: string) { linkTo(navigationRef.current, route, type, isActiveRoute(route)); } -function newGoBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopToTop = false) { +function goUp(fallbackRoute: Route) { if (!canNavigate('goBack')) { return; } @@ -197,17 +197,57 @@ function newGoBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldP Log.hmmm('[Navigation] Unable to go back'); return; } - navigationRef.current.goBack(); - if (fallbackRoute) { - /** - * Cases to handle: - * 1. RHP - * 2. fallbackRoute is in the current navigator - * 3. fallbackRoute is in the different navigator - * 4. fallbackRoute isn't present in the current state - */ + const rootState = navigationRef.current?.getRootState(); + const lastRoute = rootState?.routes.at(-1); + + const route = findFocusedRoute(getStateFromPath(fallbackRoute)); + const routeName = route?.name; + + if (!routeName) { + return; + } + + if (rootState?.routeNames?.includes(route?.name)) { + if (rootState?.routes.at(-2)?.name === routeName) { + navigationRef.current.dispatch(StackActions.pop()); + return; + } + navigate(fallbackRoute, 'REPLACE'); + return; + } + + if (lastRoute?.state?.routeNames?.includes(route?.name)) { + const distanceFromPathInRootNavigator = getDistanceFromPathInRootNavigator(lastRoute?.state, fallbackRoute ?? ''); + if (distanceFromPathInRootNavigator > 0) { + navigationRef.current.dispatch({...StackActions.pop(distanceFromPathInRootNavigator), target: lastRoute?.key}); + return; + } + navigate(fallbackRoute, 'REPLACE'); + return; + } + + const secondToLastRoute = rootState?.routes.at(-2); + + if (secondToLastRoute?.state?.routeNames?.includes(route?.name)) { + navigationRef.current.dispatch(StackActions.pop()); + const distanceFromPathInRootNavigator = getDistanceFromPathInRootNavigator(secondToLastRoute?.state, fallbackRoute ?? ''); + if (distanceFromPathInRootNavigator > 0) { + navigationRef.current.dispatch({...StackActions.pop(distanceFromPathInRootNavigator), target: secondToLastRoute?.key}); + return; + } + const routes = navigationRef.current.getRootState().routes; + const stateFromPath = getStateFromPath(fallbackRoute); + const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); + if (!action) { + return; + } + const minimalAction = getMinimalAction(action, {...rootState, routes: routes.slice(0, -1), index: rootState.index - 1}); + navigationRef.dispatch(minimalAction); + return; } + + navigate(fallbackRoute, 'REPLACE'); } /** @@ -228,65 +268,70 @@ function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopT } } - if (!navigationRef.current?.canGoBack()) { - Log.hmmm('[Navigation] Unable to go back'); + if (fallbackRoute) { + goUp(fallbackRoute); return; } - const isFirstRouteInNavigator = !getActiveRouteIndex(navigationRef.current.getState()); - if (isFirstRouteInNavigator) { - const rootState = navigationRef.getRootState(); - const lastRoute = rootState.routes.at(-1); - // If the user comes from a different flow (there is more than one route in ModalNavigator) we should go back to the previous flow on UP button press instead of using the fallbackRoute. - if ((lastRoute?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || lastRoute?.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR) && (lastRoute.state?.index ?? 0) > 0) { - navigationRef.current.goBack(); - return; - } - } - - if (shouldEnforceFallback || (isFirstRouteInNavigator && fallbackRoute)) { - navigate(fallbackRoute, 'REPLACE'); + if (!navigationRef.current?.canGoBack()) { + Log.hmmm('[Navigation] Unable to go back'); return; } - const isCentralPaneFocused = isCentralPaneName(findFocusedRoute(navigationRef.current.getState())?.name); - const distanceFromPathInRootNavigator = getDistanceFromPathInRootNavigator(fallbackRoute ?? ''); - - if (isCentralPaneFocused && fallbackRoute) { - // Allow CentralPane to use UP with fallback route if the path is not found in root navigator. - if (distanceFromPathInRootNavigator === -1) { - navigate(fallbackRoute, 'REPLACE'); - return; - } - - // Add possibility to go back more than one screen in root navigator if that screen is on the stack. - if (distanceFromPathInRootNavigator > 0) { - navigationRef.current.dispatch(StackActions.pop(distanceFromPathInRootNavigator)); - return; - } - } - - // If the central pane is focused, it's possible that we navigated from other central pane with different matching bottom tab. - if (isCentralPaneFocused) { - const rootState = navigationRef.getRootState(); - const stateAfterPop = {routes: rootState.routes.slice(0, -1)} as State; - const topmostCentralPaneRouteAfterPop = getTopmostCentralPaneRoute(stateAfterPop); - - const topmostBottomTabRoute = getTopmostBottomTabRoute(rootState as State); - const matchingBottomTabRoute = getMatchingBottomTabRouteForState(stateAfterPop); - - // If the central pane is defined after the pop action, we need to check if it's synced with the bottom tab screen. - // If not, we need to pop to the bottom tab screen/screens to sync it with the new central pane. - if (topmostCentralPaneRouteAfterPop && topmostBottomTabRoute?.name !== matchingBottomTabRoute.name) { - const bottomTabNavigator = rootState.routes.find((item: NavigationStateRoute) => item.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR)?.state; - - if (bottomTabNavigator && bottomTabNavigator.index) { - const matchingIndex = bottomTabNavigator.routes.findLastIndex((item) => item.name === matchingBottomTabRoute.name); - const indexToPop = matchingIndex !== -1 ? bottomTabNavigator.index - matchingIndex : undefined; - navigationRef.current.dispatch({...StackActions.pop(indexToPop), target: bottomTabNavigator?.key}); - } - } - } + // const isFirstRouteInNavigator = !getActiveRouteIndex(navigationRef.current.getState()); + // if (isFirstRouteInNavigator) { + // const rootState = navigationRef.getRootState(); + // const lastRoute = rootState.routes.at(-1); + // // If the user comes from a different flow (there is more than one route in ModalNavigator) we should go back to the previous flow on UP button press instead of using the fallbackRoute. + // if ((lastRoute?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || lastRoute?.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR) && (lastRoute.state?.index ?? 0) > 0) { + // navigationRef.current.goBack(); + // return; + // } + // } + + // if (shouldEnforceFallback || (isFirstRouteInNavigator && fallbackRoute)) { + // navigate(fallbackRoute, 'REPLACE'); + // return; + // } + + // const isCentralPaneFocused = isCentralPaneName(findFocusedRoute(navigationRef.current.getState())?.name); + // const distanceFromPathInRootNavigator = getDistanceFromPathInRootNavigator(navigationRef.getRootState(), fallbackRoute ?? ''); + + // if (isCentralPaneFocused && fallbackRoute) { + // // Allow CentralPane to use UP with fallback route if the path is not found in root navigator. + // if (distanceFromPathInRootNavigator === -1) { + // navigate(fallbackRoute, 'REPLACE'); + // return; + // } + + // // Add possibility to go back more than one screen in root navigator if that screen is on the stack. + // if (distanceFromPathInRootNavigator > 0) { + // navigationRef.current.dispatch(StackActions.pop(distanceFromPathInRootNavigator)); + // return; + // } + // } + + // // If the central pane is focused, it's possible that we navigated from other central pane with different matching bottom tab. + // if (isCentralPaneFocused) { + // const rootState = navigationRef.getRootState(); + // const stateAfterPop = {routes: rootState.routes.slice(0, -1)} as State; + // const topmostCentralPaneRouteAfterPop = getTopmostCentralPaneRoute(stateAfterPop); + + // const topmostBottomTabRoute = getTopmostBottomTabRoute(rootState as State); + // const matchingBottomTabRoute = getMatchingBottomTabRouteForState(stateAfterPop); + + // // If the central pane is defined after the pop action, we need to check if it's synced with the bottom tab screen. + // // If not, we need to pop to the bottom tab screen/screens to sync it with the new central pane. + // if (topmostCentralPaneRouteAfterPop && topmostBottomTabRoute?.name !== matchingBottomTabRoute.name) { + // const bottomTabNavigator = rootState.routes.find((item: NavigationStateRoute) => item.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR)?.state; + + // if (bottomTabNavigator && bottomTabNavigator.index) { + // const matchingIndex = bottomTabNavigator.routes.findLastIndex((item) => item.name === matchingBottomTabRoute.name); + // const indexToPop = matchingIndex !== -1 ? bottomTabNavigator.index - matchingIndex : undefined; + // navigationRef.current.dispatch({...StackActions.pop(indexToPop), target: bottomTabNavigator?.key}); + // } + // } + // } navigationRef.current.goBack(); } @@ -502,6 +547,7 @@ export default { setNavigationActionToMicrotaskQueue, getTopMostCentralPaneRouteFromRootState, navigateToReportWithPolicyCheck, + goUp, }; export {navigationRef}; diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index d34fd052434d..137cd0ffe876 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -45,20 +45,12 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT } if (route.name === SCREENS.SETTINGS.WORKSPACES && shouldUseNarrowLayout) { - Navigation.goBack(ROUTES.SETTINGS); + Navigation.goUp(ROUTES.SETTINGS); return; } if (route.name === SCREENS.WORKSPACE.INITIAL) { - const previousRoute = navigationRef.getRootState().routes.at(-2); - - // If there is the settings split navigator we can dismiss safely - if (previousRoute?.name === NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR) { - Navigation.dismissModal(); - } else { - // If not, we are going to replace this route with the settings route - Navigation.navigate(ROUTES.SETTINGS_WORKSPACES, CONST.NAVIGATION.ACTION_TYPE.REPLACE); - } + Navigation.goUp(ROUTES.SETTINGS_WORKSPACES); return; } diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 1644fdac1abc..d7bad8bc1f80 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -379,16 +379,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac Navigation.resetToHome(); Navigation.isNavigationReady().then(() => Navigation.navigate(route.params?.backTo as Route)); } else { - // @TODO This part could be done with the new goBack method when it will be implemented. - const previousRoute = navigationRef.getRootState().routes.at(-2); - - // If there is the settings split navigator we can dismiss safely - if (previousRoute?.name === NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR) { - Navigation.dismissModal(); - } else { - // If not, we are going to replace this route with the settings route - Navigation.navigate(ROUTES.SETTINGS_WORKSPACES, CONST.NAVIGATION.ACTION_TYPE.REPLACE); - } + Navigation.goUp(ROUTES.SETTINGS_WORKSPACES); } }} policyAvatar={policyAvatar} From cf2585519c37068956a6eef734fc29f2e019445b Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 30 Sep 2024 15:11:17 +0200 Subject: [PATCH 060/257] Handle navigating back to sidebar screen --- .../SplitStackRouter.ts | 2 +- src/libs/Navigation/Navigation.ts | 87 +++++++------------ src/libs/Navigation/types.ts | 3 + 3 files changed, 35 insertions(+), 57 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts index 7bdb1ba22a3d..bbe741fe25cd 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts @@ -20,7 +20,7 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc const workspaceCentralPane = state.routes.at(-1); // There should always be sidebarScreen screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings. - if (!isAtLeastOneInState(state, sidebarScreen)) { + if (!isAtLeastOneInState(state, sidebarScreen) && !isNarrowLayout) { // @ts-expect-error Updating read only property // noinspection JSConstantReassignment state.stale = true; // eslint-disable-line diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index c864985bcfd5..d46a74780e06 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -27,7 +27,21 @@ import linkTo from './linkTo'; import getMinimalAction from './linkTo/getMinimalAction'; import navigationRef from './navigationRef'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; -import type {NavigationStateRoute, RootStackParamList, StackNavigationAction, State, StateOrRoute} from './types'; +import type {NavigationStateRoute, RootStackParamList, SplitNavigatorLHNScreen, SplitNavigatorName, SplitNavigatorParamListType, StackNavigationAction, State, StateOrRoute} from './types'; + +const SPLIT_NAVIGATOR_TO_SIDEBAR_MAP: Record = { + [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: SCREENS.HOME, + [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: SCREENS.SETTINGS.ROOT, + [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: SCREENS.WORKSPACE.INITIAL, +}; + +function getSidebarScreenParams(splitNavigatorRoute: NavigationStateRoute) { + if (splitNavigatorRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { + return splitNavigatorRoute.state?.routes?.at(0)?.params; + } + + return undefined; +} let resolveNavigationIsReadyPromise: () => void; const navigationIsReadyPromise = new Promise((resolve) => { @@ -273,66 +287,27 @@ function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopT return; } + const rootState = navigationRef.current?.getRootState(); + const lastRoute = rootState?.routes.at(-1); + + if (lastRoute?.name.endsWith('SplitNavigator') && lastRoute?.state?.routes?.length === 1) { + const name = SPLIT_NAVIGATOR_TO_SIDEBAR_MAP[lastRoute?.name as SplitNavigatorName]; + const params = getSidebarScreenParams(lastRoute); + navigationRef.dispatch({ + type: 'REPLACE', + payload: { + name, + params, + }, + }); + return; + } + if (!navigationRef.current?.canGoBack()) { Log.hmmm('[Navigation] Unable to go back'); return; } - // const isFirstRouteInNavigator = !getActiveRouteIndex(navigationRef.current.getState()); - // if (isFirstRouteInNavigator) { - // const rootState = navigationRef.getRootState(); - // const lastRoute = rootState.routes.at(-1); - // // If the user comes from a different flow (there is more than one route in ModalNavigator) we should go back to the previous flow on UP button press instead of using the fallbackRoute. - // if ((lastRoute?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || lastRoute?.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR) && (lastRoute.state?.index ?? 0) > 0) { - // navigationRef.current.goBack(); - // return; - // } - // } - - // if (shouldEnforceFallback || (isFirstRouteInNavigator && fallbackRoute)) { - // navigate(fallbackRoute, 'REPLACE'); - // return; - // } - - // const isCentralPaneFocused = isCentralPaneName(findFocusedRoute(navigationRef.current.getState())?.name); - // const distanceFromPathInRootNavigator = getDistanceFromPathInRootNavigator(navigationRef.getRootState(), fallbackRoute ?? ''); - - // if (isCentralPaneFocused && fallbackRoute) { - // // Allow CentralPane to use UP with fallback route if the path is not found in root navigator. - // if (distanceFromPathInRootNavigator === -1) { - // navigate(fallbackRoute, 'REPLACE'); - // return; - // } - - // // Add possibility to go back more than one screen in root navigator if that screen is on the stack. - // if (distanceFromPathInRootNavigator > 0) { - // navigationRef.current.dispatch(StackActions.pop(distanceFromPathInRootNavigator)); - // return; - // } - // } - - // // If the central pane is focused, it's possible that we navigated from other central pane with different matching bottom tab. - // if (isCentralPaneFocused) { - // const rootState = navigationRef.getRootState(); - // const stateAfterPop = {routes: rootState.routes.slice(0, -1)} as State; - // const topmostCentralPaneRouteAfterPop = getTopmostCentralPaneRoute(stateAfterPop); - - // const topmostBottomTabRoute = getTopmostBottomTabRoute(rootState as State); - // const matchingBottomTabRoute = getMatchingBottomTabRouteForState(stateAfterPop); - - // // If the central pane is defined after the pop action, we need to check if it's synced with the bottom tab screen. - // // If not, we need to pop to the bottom tab screen/screens to sync it with the new central pane. - // if (topmostCentralPaneRouteAfterPop && topmostBottomTabRoute?.name !== matchingBottomTabRoute.name) { - // const bottomTabNavigator = rootState.routes.find((item: NavigationStateRoute) => item.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR)?.state; - - // if (bottomTabNavigator && bottomTabNavigator.index) { - // const matchingIndex = bottomTabNavigator.routes.findLastIndex((item) => item.name === matchingBottomTabRoute.name); - // const indexToPop = matchingIndex !== -1 ? bottomTabNavigator.index - matchingIndex : undefined; - // navigationRef.current.dispatch({...StackActions.pop(indexToPop), target: bottomTabNavigator?.key}); - // } - // } - // } - navigationRef.current.goBack(); } diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 6e2e2526e8de..ba9ca736a2f6 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -60,6 +60,8 @@ type SplitNavigatorParamListType = { [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: WorkspaceSplitNavigatorParamList; }; +type SplitNavigatorName = keyof SplitNavigatorParamListType; + type SplitNavigatorByLHN = (typeof LHN_TO_SPLIT_NAVIGATOR_NAME)[T]; type CentralPaneScreensParamList = { @@ -1650,4 +1652,5 @@ export type { SplitNavigatorLHNScreen, SplitNavigatorParamListType, SplitNavigatorByLHN, + SplitNavigatorName, }; From e2a304e15154c9de4e314d177c8650c250d15b97 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 18 Jun 2024 09:54:01 +0200 Subject: [PATCH 061/257] Replace FullScreenNavigator with SplitNavigator --- .../createSplitNavigator/index.tsx | 64 +++++++++++++++++++ .../createSplitNavigator/types.ts | 11 ++++ .../useNavigationReset/index.native.ts | 1 + .../useNavigationReset/index.ts | 14 ++++ .../usePrepareSplitNavigatorChildren.ts | 23 +++++++ 5 files changed, 113 insertions(+) create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx new file mode 100644 index 000000000000..17ab209cfae8 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx @@ -0,0 +1,64 @@ +import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native'; +import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; +import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; +import {StackView} from '@react-navigation/stack'; +import React from 'react'; +import {View} from 'react-native'; +import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useStyleUtils from '@hooks/useStyleUtils'; +import useThemeStyles from '@hooks/useThemeStyles'; +import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; +import SplitRouter from './SplitRouter'; +import type {SplitNavigatorProps, SplitNavigatorRouterOptions} from './types'; +import useNavigationReset from './useNavigationReset'; +import usePrepareSplitNavigatorChildren from './usePrepareSplitNavigatorChildren'; + +function SplitNavigator(props: SplitNavigatorProps) { + const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); + const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); + + const children = usePrepareSplitNavigatorChildren(props.children, props.sidebarScreen, screenOptions.homeScreen); + + const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< + StackNavigationState, + SplitNavigatorRouterOptions, + StackActionHelpers, + StackNavigationOptions, + StackNavigationEventMap + >(SplitRouter, { + children, + screenOptions: screenOptions.centralPaneNavigator, + initialRouteName: props.initialRouteName, + sidebarScreen: props.sidebarScreen, + initialCentralPaneScreen: props.initialCentralPaneScreen, + }); + + useNavigationReset(navigation, shouldUseNarrowLayout); + + return ( + + + + + + + + ); +} + +SplitNavigator.displayName = 'SplitNavigator'; + +export default function () { + return createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, React.ComponentType>>( + SplitNavigator, + )(); +} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts new file mode 100644 index 000000000000..3b41f6f7a96d --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts @@ -0,0 +1,11 @@ +import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; +import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; + +type SplitNavigatorRouterOptions = StackRouterOptions & {initialCentralPaneScreen: string; sidebarScreen: string}; + +type SplitNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> & { + initialCentralPaneScreen: Extract; + sidebarScreen: Extract; +}; + +export type {SplitNavigatorProps, SplitNavigatorRouterOptions}; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts new file mode 100644 index 000000000000..5d5d30356781 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts @@ -0,0 +1 @@ +export default function useNavigationReset() {} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts new file mode 100644 index 000000000000..238fc1ca2928 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts @@ -0,0 +1,14 @@ +import type {NavigationHelpers, ParamListBase} from '@react-navigation/native'; +import {useEffect} from 'react'; +import navigationRef from '@libs/Navigation/navigationRef'; + +export default function useNavigationReset(navigation: NavigationHelpers, isSmallScreenWidth: boolean) { + useEffect(() => { + if (!navigationRef.isReady()) { + return; + } + // We need to separately reset state of this navigator to trigger getRehydratedState. + navigation.reset(navigation.getState()); + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps + }, [isSmallScreenWidth]); +} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts new file mode 100644 index 000000000000..ad05d1079328 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts @@ -0,0 +1,23 @@ +import type {StackNavigationOptions} from '@react-navigation/stack'; +import {Children, isValidElement, useMemo} from 'react'; +import type {ReactNode} from 'react'; + +export default function usePrepareSplitNavigatorChildren(screensNode: ReactNode, sidebarScreenName: string, sidebarScreenOptions: StackNavigationOptions) { + return useMemo( + () => + Children.toArray(screensNode).map((screen: ReactNode) => { + if (isValidElement(screen) && screen?.props?.name === sidebarScreenName) { + // If we found the element we wanted, clone it with the provided prop changes. + return { + ...screen, + props: { + ...screen.props, + options: sidebarScreenOptions, + }, + }; + } + return screen; + }), + [screensNode, sidebarScreenName, sidebarScreenOptions], + ); +} From a3f95c8ac9fdb40792fc0b443d372f8e2a18f8e0 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 19 Jun 2024 11:49:28 +0200 Subject: [PATCH 062/257] Rename Split to SplitStack --- .../createSplitNavigator/index.tsx | 64 ------------------- .../createSplitNavigator/types.ts | 11 ---- .../usePrepareSplitNavigatorChildren.ts | 23 ------- .../createSplitStackNavigator/index.tsx | 23 +------ .../useNavigationReset/index.native.ts | 0 .../useNavigationReset/index.ts | 0 6 files changed, 3 insertions(+), 118 deletions(-) delete mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx delete mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts delete mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts rename src/libs/Navigation/AppNavigator/{createSplitNavigator => createSplitStackNavigator}/useNavigationReset/index.native.ts (100%) rename src/libs/Navigation/AppNavigator/{createSplitNavigator => createSplitStackNavigator}/useNavigationReset/index.ts (100%) diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx deleted file mode 100644 index 17ab209cfae8..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native'; -import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; -import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; -import {StackView} from '@react-navigation/stack'; -import React from 'react'; -import {View} from 'react-native'; -import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import useStyleUtils from '@hooks/useStyleUtils'; -import useThemeStyles from '@hooks/useThemeStyles'; -import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; -import SplitRouter from './SplitRouter'; -import type {SplitNavigatorProps, SplitNavigatorRouterOptions} from './types'; -import useNavigationReset from './useNavigationReset'; -import usePrepareSplitNavigatorChildren from './usePrepareSplitNavigatorChildren'; - -function SplitNavigator(props: SplitNavigatorProps) { - const styles = useThemeStyles(); - const StyleUtils = useStyleUtils(); - const {shouldUseNarrowLayout} = useResponsiveLayout(); - const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); - - const children = usePrepareSplitNavigatorChildren(props.children, props.sidebarScreen, screenOptions.homeScreen); - - const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< - StackNavigationState, - SplitNavigatorRouterOptions, - StackActionHelpers, - StackNavigationOptions, - StackNavigationEventMap - >(SplitRouter, { - children, - screenOptions: screenOptions.centralPaneNavigator, - initialRouteName: props.initialRouteName, - sidebarScreen: props.sidebarScreen, - initialCentralPaneScreen: props.initialCentralPaneScreen, - }); - - useNavigationReset(navigation, shouldUseNarrowLayout); - - return ( - - - - - - - - ); -} - -SplitNavigator.displayName = 'SplitNavigator'; - -export default function () { - return createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, React.ComponentType>>( - SplitNavigator, - )(); -} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts deleted file mode 100644 index 3b41f6f7a96d..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; -import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; - -type SplitNavigatorRouterOptions = StackRouterOptions & {initialCentralPaneScreen: string; sidebarScreen: string}; - -type SplitNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> & { - initialCentralPaneScreen: Extract; - sidebarScreen: Extract; -}; - -export type {SplitNavigatorProps, SplitNavigatorRouterOptions}; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts deleted file mode 100644 index ad05d1079328..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitNavigatorChildren.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type {StackNavigationOptions} from '@react-navigation/stack'; -import {Children, isValidElement, useMemo} from 'react'; -import type {ReactNode} from 'react'; - -export default function usePrepareSplitNavigatorChildren(screensNode: ReactNode, sidebarScreenName: string, sidebarScreenOptions: StackNavigationOptions) { - return useMemo( - () => - Children.toArray(screensNode).map((screen: ReactNode) => { - if (isValidElement(screen) && screen?.props?.name === sidebarScreenName) { - // If we found the element we wanted, clone it with the provided prop changes. - return { - ...screen, - props: { - ...screen.props, - options: sidebarScreenOptions, - }, - }; - } - return screen; - }), - [screensNode, sidebarScreenName, sidebarScreenOptions], - ); -} diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index 80cf27eb1fe6..d90b60d2ac4d 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -2,7 +2,7 @@ import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@rea import {createNavigatorFactory, useNavigationBuilder, useRoute} from '@react-navigation/native'; import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; import {StackView} from '@react-navigation/stack'; -import React, {useMemo} from 'react'; +import React from 'react'; import {View} from 'react-native'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -14,25 +14,10 @@ import type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions} from '. import useHandleScreenResize from './useHandleScreenResize'; import usePrepareSplitStackNavigatorChildren from './usePrepareSplitStackNavigatorChildren'; -function getStateToRender(state: StackNavigationState, isSmallScreenWidth: boolean): StackNavigationState { - const sidebarScreenRoute = state.routes.at(0); - const centralScreenRoutes = state.routes.slice(1); - const routes = isSmallScreenWidth ? state.routes.slice(-2) : [sidebarScreenRoute, ...centralScreenRoutes.slice(-2)]; - - // Routes passed to the state have to be defined - const definedRoutes = routes.filter((route) => route !== undefined); - - return { - ...state, - routes: definedRoutes, - index: routes.length - 1, - }; -} - function SplitStackNavigator(props: SplitStackNavigatorProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const {isSmallScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); const children = usePrepareSplitStackNavigatorChildren(props.children, props.sidebarScreen, screenOptions.homeScreen); @@ -58,8 +43,6 @@ function SplitStackNavigator(props: SplitStackN useHandleScreenResize(navigation); - const stateToRender = useMemo(() => getStateToRender(state, isSmallScreenWidth), [state, isSmallScreenWidth]); - return ( @@ -67,7 +50,7 @@ function SplitStackNavigator(props: SplitStackN diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.native.ts rename to src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createSplitNavigator/useNavigationReset/index.ts rename to src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts From 665f795779bcc44e2a1ba8c46cd8451455396b9a Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 19 Jun 2024 13:45:01 +0200 Subject: [PATCH 063/257] Rename FullScreenNavigator to WorkspaceNavigator --- .../Navigation/AppNavigator/AuthScreens.tsx | 1 + .../Navigators/WorkspaceSplitNavigator.tsx | 2 +- .../WORKSPACE_SCREEN_TO_RHP_MAPPING.ts | 218 ++++++++++++++++++ src/pages/workspace/WorkspaceInitialPage.tsx | 3 +- 4 files changed, 221 insertions(+), 3 deletions(-) create mode 100755 src/libs/Navigation/linkingConfig/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 9eba945176a5..82bfd43ca9aa 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -66,6 +66,7 @@ import LeftModalNavigator from './Navigators/LeftModalNavigator'; import OnboardingModalNavigator from './Navigators/OnboardingModalNavigator'; import RightModalNavigator from './Navigators/RightModalNavigator'; import WelcomeVideoModalNavigator from './Navigators/WelcomeVideoModalNavigator'; +import WorkspaceNavigator from './Navigators/WorkspaceNavigator'; const loadReportAttachments = () => require('../../../pages/home/report/ReportAttachments').default; const loadValidateLoginPage = () => require('../../../pages/ValidateLoginPage').default; diff --git a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx index 31a3c89a3fe1..2471cffe7c61 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx @@ -54,4 +54,4 @@ function WorkspaceNavigator() { WorkspaceNavigator.displayName = 'WorkspaceNavigator'; export {CENTRAL_PANE_WORKSPACE_SCREENS}; -export default WorkspaceNavigator; +export default WorkspaceNavigator; \ No newline at end of file diff --git a/src/libs/Navigation/linkingConfig/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts new file mode 100755 index 000000000000..30e7d8d81e08 --- /dev/null +++ b/src/libs/Navigation/linkingConfig/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts @@ -0,0 +1,218 @@ +import type {WorkspaceScreenName} from '@libs/Navigation/types'; +import SCREENS from '@src/SCREENS'; + +const WORKSPACE_SCREEN_TO_RHP_MAPPING: Partial> = { + [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.ADDRESS, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE], + [SCREENS.WORKSPACE.MEMBERS]: [ + SCREENS.WORKSPACE.INVITE, + SCREENS.WORKSPACE.INVITE_MESSAGE, + SCREENS.WORKSPACE.MEMBER_DETAILS, + SCREENS.WORKSPACE.MEMBER_NEW_CARD, + SCREENS.WORKSPACE.OWNER_CHANGE_CHECK, + SCREENS.WORKSPACE.OWNER_CHANGE_SUCCESS, + SCREENS.WORKSPACE.OWNER_CHANGE_ERROR, + SCREENS.WORKSPACE.OWNER_CHANGE_ERROR, + SCREENS.WORKSPACE.MEMBERS_IMPORT, + SCREENS.WORKSPACE.MEMBERS_IMPORTED, + ], + [SCREENS.WORKSPACE.WORKFLOWS]: [ + SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_NEW, + SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EDIT, + SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EXPENSES_FROM, + SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_APPROVER, + SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY, + SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET, + SCREENS.WORKSPACE.WORKFLOWS_PAYER, + ], + [SCREENS.WORKSPACE.ACCOUNTING.ROOT]: [ + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CLASSES, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_TAXES, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_LOCATIONS, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CUSTOMERS, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_INVOICE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_COMPANY_CARD_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_NON_REIMBURSABLE_DEFAULT_VENDOR_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_CHART_OF_ACCOUNTS, + SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION, + SCREENS.WORKSPACE.ACCOUNTING.XERO_CUSTOMER, + SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES, + SCREENS.WORKSPACE.ACCOUNTING.XERO_TRACKING_CATEGORIES, + SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_TRACKING_CATEGORY, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_PURCHASE_BILL_DATE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_STATUS_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_PREFERRED_EXPORTER_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_BANK_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_SUBSIDIARY_SELECTOR, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_REUSE_EXISTING_CONNECTIONS, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_TOKEN_INPUT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_MAPPING, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_VIEW, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_EDIT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_LIST_ADD, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_SEGMENT_ADD, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_PREFERRED_EXPORTER_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_DATE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_DESTINATION_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_VENDOR_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_PAYABLE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_JOURNAL_POSTING_PREFERENCE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_RECEIVABLE_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_INVOICE_ITEM_PREFERENCE_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_INVOICE_ITEM_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_TAX_POSTING_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_PROVINCIAL_TAX_POSTING_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_REIMBURSEMENT_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_COLLECTION_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPENSE_REPORT_APPROVAL_LEVEL_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_VENDOR_BILL_APPROVAL_LEVEL_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_JOURNAL_ENTRY_APPROVAL_LEVEL_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_APPROVAL_ACCOUNT_SELECT, + SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_CUSTOM_FORM_ID, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PREREQUISITES, + SCREENS.WORKSPACE.ACCOUNTING.ENTER_SAGE_INTACCT_CREDENTIALS, + SCREENS.WORKSPACE.ACCOUNTING.EXISTING_SAGE_INTACCT_CONNECTIONS, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ENTITY, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_IMPORT, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_MAPPING_TYPE, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_TOGGLE_MAPPING, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_USER_DIMENSIONS, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ADD_USER_DIMENSION, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EDIT_USER_DIMENSION, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EXPORT, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PREFERRED_EXPORTER, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EXPORT_DATE, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_REIMBURSABLE_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_EXPENSES, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_REIMBURSABLE_DESTINATION, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_DESTINATION, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_DEFAULT_VENDOR, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_CREDIT_CARD_ACCOUNT, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ADVANCED, + SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PAYMENT_ACCOUNT, + SCREENS.WORKSPACE.ACCOUNTING.CARD_RECONCILIATION, + SCREENS.WORKSPACE.ACCOUNTING.RECONCILIATION_ACCOUNT_SETTINGS, + ], + [SCREENS.WORKSPACE.TAXES]: [ + SCREENS.WORKSPACE.TAXES_SETTINGS, + SCREENS.WORKSPACE.TAX_CREATE, + SCREENS.WORKSPACE.TAXES_SETTINGS_CUSTOM_TAX_NAME, + SCREENS.WORKSPACE.TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT, + SCREENS.WORKSPACE.TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT, + SCREENS.WORKSPACE.TAX_CREATE, + SCREENS.WORKSPACE.TAX_EDIT, + SCREENS.WORKSPACE.TAX_NAME, + SCREENS.WORKSPACE.TAX_VALUE, + SCREENS.WORKSPACE.TAX_CODE, + ], + [SCREENS.WORKSPACE.TAGS]: [ + SCREENS.WORKSPACE.TAGS_SETTINGS, + SCREENS.WORKSPACE.TAGS_EDIT, + SCREENS.WORKSPACE.TAG_CREATE, + SCREENS.WORKSPACE.TAG_SETTINGS, + SCREENS.WORKSPACE.TAG_EDIT, + SCREENS.WORKSPACE.TAG_LIST_VIEW, + SCREENS.WORKSPACE.TAG_GL_CODE, + SCREENS.WORKSPACE.TAG_APPROVER, + SCREENS.WORKSPACE.TAGS_IMPORT, + SCREENS.WORKSPACE.TAGS_IMPORTED, + ], + [SCREENS.WORKSPACE.CATEGORIES]: [ + SCREENS.WORKSPACE.CATEGORY_CREATE, + SCREENS.WORKSPACE.CATEGORY_SETTINGS, + SCREENS.WORKSPACE.CATEGORIES_IMPORT, + SCREENS.WORKSPACE.CATEGORIES_IMPORTED, + SCREENS.WORKSPACE.CATEGORIES_SETTINGS, + SCREENS.WORKSPACE.CATEGORY_EDIT, + SCREENS.WORKSPACE.CATEGORY_GL_CODE, + SCREENS.WORKSPACE.CATEGORY_PAYROLL_CODE, + SCREENS.WORKSPACE.CATEGORY_DEFAULT_TAX_RATE, + SCREENS.WORKSPACE.CATEGORY_FLAG_AMOUNTS_OVER, + SCREENS.WORKSPACE.CATEGORY_DESCRIPTION_HINT, + SCREENS.WORKSPACE.CATEGORY_APPROVER, + SCREENS.WORKSPACE.CATEGORY_REQUIRE_RECEIPTS_OVER, + ], + [SCREENS.WORKSPACE.DISTANCE_RATES]: [ + SCREENS.WORKSPACE.CREATE_DISTANCE_RATE, + SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS, + SCREENS.WORKSPACE.DISTANCE_RATE_EDIT, + SCREENS.WORKSPACE.DISTANCE_RATE_TAX_RECLAIMABLE_ON_EDIT, + SCREENS.WORKSPACE.DISTANCE_RATE_TAX_RATE_EDIT, + SCREENS.WORKSPACE.DISTANCE_RATE_DETAILS, + ], + [SCREENS.WORKSPACE.REPORT_FIELDS]: [ + SCREENS.WORKSPACE.REPORT_FIELDS_CREATE, + SCREENS.WORKSPACE.REPORT_FIELDS_SETTINGS, + SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES, + SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE, + SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS, + SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE, + SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE, + ], + [SCREENS.WORKSPACE.INVOICES]: [SCREENS.WORKSPACE.INVOICES_COMPANY_NAME, SCREENS.WORKSPACE.INVOICES_COMPANY_WEBSITE], + [SCREENS.WORKSPACE.COMPANY_CARDS]: [ + SCREENS.WORKSPACE.COMPANY_CARDS_SELECT_FEED, + SCREENS.WORKSPACE.COMPANY_CARDS_ADD_NEW, + SCREENS.WORKSPACE.COMPANY_CARDS_TYPE, + SCREENS.WORKSPACE.COMPANY_CARDS_INSTRUCTIONS, + SCREENS.WORKSPACE.COMPANY_CARDS_NAME, + SCREENS.WORKSPACE.COMPANY_CARDS_DETAILS, + SCREENS.WORKSPACE.COMPANY_CARDS_SELECT_FEED, + SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS, + SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS_FEED_NAME, + SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS, + SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS_FEED_NAME, + SCREENS.WORKSPACE.COMPANY_CARDS_ASSIGN_CARD, + SCREENS.WORKSPACE.COMPANY_CARD_DETAILS, + SCREENS.WORKSPACE.COMPANY_CARD_NAME, + SCREENS.WORKSPACE.COMPANY_CARD_EXPORT, + ], + [SCREENS.WORKSPACE.EXPENSIFY_CARD]: [ + SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW, + SCREENS.WORKSPACE.EXPENSIFY_CARD_BANK_ACCOUNT, + SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS, + SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_ACCOUNT, + SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_FREQUENCY, + SCREENS.WORKSPACE.EXPENSIFY_CARD_DETAILS, + SCREENS.WORKSPACE.EXPENSIFY_CARD_NAME, + SCREENS.WORKSPACE.EXPENSIFY_CARD_LIMIT, + SCREENS.WORKSPACE.EXPENSIFY_CARD_LIMIT_TYPE, + ], + [SCREENS.WORKSPACE.RULES]: [ + SCREENS.WORKSPACE.RULES_CUSTOM_NAME, + SCREENS.WORKSPACE.RULES_AUTO_APPROVE_REPORTS_UNDER, + SCREENS.WORKSPACE.RULES_RANDOM_REPORT_AUDIT, + SCREENS.WORKSPACE.RULES_AUTO_PAY_REPORTS_UNDER, + SCREENS.WORKSPACE.RULES_RECEIPT_REQUIRED_AMOUNT, + SCREENS.WORKSPACE.RULES_MAX_EXPENSE_AMOUNT, + SCREENS.WORKSPACE.RULES_MAX_EXPENSE_AGE, + SCREENS.WORKSPACE.RULES_BILLABLE_DEFAULT, + ], +}; + +export default WORKSPACE_SCREEN_TO_RHP_MAPPING; diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index d7bad8bc1f80..379801d16be7 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -24,7 +24,7 @@ import {isConnectionInProgress} from '@libs/actions/connections'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import getTopmostRouteName from '@libs/Navigation/getTopmostRouteName'; -import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; +import Navigation from '@libs/Navigation/Navigation'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; @@ -32,7 +32,6 @@ import * as Policy from '@userActions/Policy/Policy'; import * as ReimbursementAccount from '@userActions/ReimbursementAccount'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; -import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; From ab72ccc1109e37c2d5e23bee7ef10db4ff8f4a74 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 25 Jul 2024 12:02:04 +0200 Subject: [PATCH 064/257] Add BottomTabBar to WorkspaceInitialPage and SettingsWorkspaces --- .../AppNavigator/Navigators/WorkspaceSplitNavigator.tsx | 2 +- src/pages/workspace/WorkspacesListPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx index 2471cffe7c61..31a3c89a3fe1 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx @@ -54,4 +54,4 @@ function WorkspaceNavigator() { WorkspaceNavigator.displayName = 'WorkspaceNavigator'; export {CENTRAL_PANE_WORKSPACE_SCREENS}; -export default WorkspaceNavigator; \ No newline at end of file +export default WorkspaceNavigator; diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 95d1459062d0..a29e17ef61d2 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -108,7 +108,7 @@ function WorkspacesListPage() { const styles = useThemeStyles(); const {translate} = useLocalize(); const {isOffline} = useNetwork(); - const {shouldUseNarrowLayout, isSmallScreenWidth, isMediumScreenWidth} = useResponsiveLayout(); + const {shouldUseNarrowLayout, isMediumScreenWidth} = useResponsiveLayout(); const [allConnectionSyncProgresses] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS); const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); From a9d0bf83767cf95fe8d24f1ece55849caf0beaa8 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 3 Sep 2024 12:33:23 +0200 Subject: [PATCH 065/257] Add todo comments for new navigation logic, adjust split navigators, adjust getAdaptedState --- .../Navigation/AppNavigator/AuthScreens.tsx | 5 +- .../linkingConfig/getAdaptedStateFromPath.ts | 3 + src/libs/Navigation/linkingConfig/index.ts | 2 +- .../getActionForBottomTabNavigator.ts | 50 ++++ .../Navigation/newLinkTo/getMinimalAction.ts | 42 +++ src/libs/Navigation/newLinkTo/index.ts | 239 ++++++++++++++++++ src/libs/Navigation/newLinkTo/types.ts | 11 + 7 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts create mode 100644 src/libs/Navigation/newLinkTo/getMinimalAction.ts create mode 100644 src/libs/Navigation/newLinkTo/index.ts create mode 100644 src/libs/Navigation/newLinkTo/types.ts diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 82bfd43ca9aa..4a741df8d6e1 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -35,6 +35,7 @@ import {buildSearchQueryString} from '@libs/SearchUtils'; import * as SessionUtils from '@libs/SessionUtils'; import ConnectionCompletePage from '@pages/ConnectionCompletePage'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; +import SearchPage from '@pages/Search/SearchPage'; import DesktopSignInRedirectPage from '@pages/signin/DesktopSignInRedirectPage'; import * as App from '@userActions/App'; import * as Download from '@userActions/Download'; @@ -64,9 +65,11 @@ import ExplanationModalNavigator from './Navigators/ExplanationModalNavigator'; import FeatureTrainingModalNavigator from './Navigators/FeatureTrainingModalNavigator'; import LeftModalNavigator from './Navigators/LeftModalNavigator'; import OnboardingModalNavigator from './Navigators/OnboardingModalNavigator'; +import ReportsSplitNavigator from './Navigators/ReportsSplitNavigator'; import RightModalNavigator from './Navigators/RightModalNavigator'; +import SettingsSplitNavigator from './Navigators/SettingsSplitNavigator'; import WelcomeVideoModalNavigator from './Navigators/WelcomeVideoModalNavigator'; -import WorkspaceNavigator from './Navigators/WorkspaceNavigator'; +import WorkspaceSplitNavigator from './Navigators/WorkspaceSplitNavigator'; const loadReportAttachments = () => require('../../../pages/home/report/ReportAttachments').default; const loadValidateLoginPage = () => require('../../../pages/ValidateLoginPage').default; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 07dc2863c3ca..07352a7b6d85 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -21,6 +21,9 @@ type GetAdaptedStateReturnType = { type GetAdaptedStateFromPath = (...args: [...Parameters, shouldReplacePathInNestedState?: boolean]) => GetAdaptedStateReturnType; +type SplitNavigatorLHNScreen = keyof typeof mapLhnToSplitNavigatorName; +type SplitNavigator = (typeof mapLhnToSplitNavigatorName)[SplitNavigatorLHNScreen]; + // The function getPathFromState that we are using in some places isn't working correctly without defined index. const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState => ({routes, index: routes.length - 1}); diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index 1f556aa67809..7bb5e8ae5b5a 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -15,7 +15,7 @@ const linkingConfig: LinkingOptions = { return adaptedState; }, subscribe, - getPathFromState: customGetPathFromState, + // getPathFromState: customGetPathFromState, prefixes, config, }; diff --git a/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts b/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts new file mode 100644 index 000000000000..85580d068ad7 --- /dev/null +++ b/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts @@ -0,0 +1,50 @@ +import type {NavigationAction, NavigationState} from '@react-navigation/native'; +import type {Writable} from 'type-fest'; +import type {RootStackParamList, StackNavigationAction} from '@libs/Navigation/types'; +import getTopmostBottomTabRoute from '@navigation/getTopmostBottomTabRoute'; +import CONST from '@src/CONST'; +import type {ActionPayloadParams} from './types'; + +// Because we need to change the type to push, we also need to set target for this action to the bottom tab navigator. +function getActionForBottomTabNavigator( + action: StackNavigationAction, + state: NavigationState, + policyID?: string, + shouldNavigate?: boolean, +): Writable | undefined { + const bottomTabNavigatorRoute = state.routes.at(0); + if (!bottomTabNavigatorRoute || bottomTabNavigatorRoute.state === undefined || !action || action.type !== CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { + return; + } + + const params = action.payload.params as ActionPayloadParams; + let payloadParams = params.params as Record; + const screen = params.screen; + + if (policyID && !payloadParams?.policyID) { + payloadParams = {...payloadParams, policyID}; + } else if (!policyID) { + delete payloadParams?.policyID; + } + + // Check if the current bottom tab is the same as the one we want to navigate to. If it is, we don't need to do anything. + const bottomTabCurrentTab = getTopmostBottomTabRoute(state); + const bottomTabParams = bottomTabCurrentTab?.params as Record; + + // Verify if the policyID is different than the one we are currently on. If it is, we need to navigate to the new policyID. + const isNewPolicy = bottomTabParams?.policyID !== payloadParams?.policyID; + if (bottomTabCurrentTab?.name === screen && !shouldNavigate && !isNewPolicy) { + return; + } + + return { + type: CONST.NAVIGATION.ACTION_TYPE.PUSH, + payload: { + name: screen, + params: payloadParams, + }, + target: bottomTabNavigatorRoute.state.key, + }; +} + +export default getActionForBottomTabNavigator; diff --git a/src/libs/Navigation/newLinkTo/getMinimalAction.ts b/src/libs/Navigation/newLinkTo/getMinimalAction.ts new file mode 100644 index 000000000000..ff01b3b8333b --- /dev/null +++ b/src/libs/Navigation/newLinkTo/getMinimalAction.ts @@ -0,0 +1,42 @@ +import type {NavigationAction, NavigationState} from '@react-navigation/native'; +import type {Writable} from 'type-fest'; +import type {State} from '@navigation/types'; +import type {ActionPayload} from './types'; + +/** + * Motivation for this function is described in NAVIGATION.md + * + * @param action action generated by getActionFromState + * @param state The root state + * @returns minimalAction minimal action is the action that we should dispatch + */ +function getMinimalAction(action: NavigationAction, state: NavigationState): Writable { + let currentAction: NavigationAction = action; + let currentState: State | undefined = state; + let currentTargetKey: string | undefined; + + while (currentAction.payload && 'name' in currentAction.payload && currentState?.routes[currentState.index ?? -1].name === currentAction.payload.name) { + if (!currentState?.routes[currentState.index ?? -1].state) { + break; + } + + currentState = currentState?.routes[currentState.index ?? -1].state; + currentTargetKey = currentState?.key; + + const payload = currentAction.payload as ActionPayload; + + // Creating new smaller action + currentAction = { + type: currentAction.type, + payload: { + name: payload?.params?.screen, + params: payload?.params?.params, + path: payload?.params?.path, + }, + target: currentTargetKey, + }; + } + return currentAction; +} + +export default getMinimalAction; diff --git a/src/libs/Navigation/newLinkTo/index.ts b/src/libs/Navigation/newLinkTo/index.ts new file mode 100644 index 000000000000..0f278a9dfc24 --- /dev/null +++ b/src/libs/Navigation/newLinkTo/index.ts @@ -0,0 +1,239 @@ +import {getActionFromState} from '@react-navigation/core'; +import type {NavigationContainerRef, NavigationState, PartialState} from '@react-navigation/native'; +import {findFocusedRoute} from '@react-navigation/native'; +import {shallowCompare} from '@libs/ObjectUtils'; +import {getPathWithoutPolicyID} from '@libs/PolicyUtils'; +import getStateFromPath from '@navigation/getStateFromPath'; +import linkingConfig from '@navigation/linkingConfig'; +import type {RootStackParamList, StackNavigationAction} from '@navigation/types'; +import CONST from '@src/CONST'; +import type {Route} from '@src/ROUTES'; +import getMinimalAction from './getMinimalAction'; + +function shouldDispatchAction(currentState: NavigationState, stateFromPath: PartialState>) { + const currentFocusedRoute = findFocusedRoute(currentState); + const targetFocusedRoute = findFocusedRoute(stateFromPath); + + const areNamesEqual = currentFocusedRoute?.name === targetFocusedRoute?.name; + const areParamsEqual = shallowCompare(currentFocusedRoute?.params as Record | undefined, targetFocusedRoute?.params as Record | undefined); + + if (areNamesEqual && areParamsEqual) { + return false; + } + + return true; +} + +export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string, isActiveRoute?: boolean) { + if (!navigation) { + throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); + } + + const pathWithoutPolicyID = getPathWithoutPolicyID(`/${path}`) as Route; + + // This is the state generated with the default getStateFromPath function. + // It won't include the whole state that will be generated for this path but the focused route will be correct. + // It is necessary because getActionFromState will generate RESET action for whole state generated with our custom getStateFromPath function. + const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; + const currentState = navigation.getRootState() as NavigationState; + const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); + + // We don't want to dispatch action to push/replace with exactly the same route that is already focused. + if (!shouldDispatchAction(currentState, stateFromPath)) { + return; + } + + // If there is no action, just reset the whole state. + if (!action) { + navigation.resetRoot(stateFromPath); + return; + } + + if (action.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { + // We want to PUSH by default to add entries to the browser history. + action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; + } + + if (!shouldDispatchAction(currentState, stateFromPath)) { + return; + } + + const minimalAction = getMinimalAction(action, navigation.getRootState()); + navigation.dispatch(minimalAction); + + // const pathWithoutPolicyID = getPathWithoutPolicyID(`/${path}`) as Route; + // const rootState = navigation.getRootState() as NavigationState; + // const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; + // // Creating path with /w/ included if necessary. + // const topmostCentralPaneRoute = getTopmostCentralPaneRoute(rootState); + // const policyIDs = !!topmostCentralPaneRoute?.params && 'policyIDs' in topmostCentralPaneRoute.params ? (topmostCentralPaneRoute?.params?.policyIDs as string) : ''; + // const extractedPolicyID = extractPolicyIDFromPath(`/${path}`); + // const policyIDFromState = getPolicyIDFromState(rootState); + // const policyID = extractedPolicyID ?? policyIDFromState ?? policyIDs; + // const lastRoute = rootState?.routes?.at(-1); + + // const isNarrowLayout = getIsNarrowLayout(); + + // const isWorkspaceScreenOnTop = lastRoute?.name === NAVIGATORS.WORKSPACE_NAVIGATOR; + + // // policyIDs is present only on SCREENS.SEARCH.CENTRAL_PANE and it's displayed in the url as a query param, on the other pages this parameter is called policyID and it's shown in the url in the format: /w/:policyID + // if (policyID && !isWorkspaceScreenOnTop && !policyIDs) { + // // The stateFromPath doesn't include proper path if there is a policy passed with /w/id. + // // We need to replace the path in the state with the proper one. + // // To avoid this hacky solution we may want to create custom getActionFromState function in the future. + // replacePathInNestedState(stateFromPath, `/w/${policyID}${pathWithoutPolicyID}`); + // } + + // const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); + + // const isReportInRhpOpened = isReportOpenInRHP(rootState); + + // // If action type is different than NAVIGATE we can't change it to the PUSH safely + // if (action?.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { + // const actionPayloadParams = action.payload.params as ActionPayloadParams; + + // const topRouteName = lastRoute?.name; + + // // CentralPane screens aren't nested in any navigator, if actionPayloadParams?.screen is undefined, it means the screen name and parameters have to be read directly from action.payload + // const targetName = actionPayloadParams?.screen ?? action.payload.name; + // const targetParams = actionPayloadParams?.params ?? actionPayloadParams; + // const isTargetNavigatorOnTop = topRouteName === action.payload.name; + + // const isTargetScreenDifferentThanCurrent = !!(!topmostCentralPaneRoute || topmostCentralPaneRoute.name !== targetName); + // const areParamsDifferent = + // targetName === SCREENS.REPORT + // ? getTopmostReportId(rootState) !== getTopmostReportId(stateFromPath) + // : !shallowCompare( + // omitBy(topmostCentralPaneRoute?.params as Record | undefined, (value) => value === undefined), + // omitBy(targetParams as Record | undefined, (value) => value === undefined), + // ); + + // // If this action is navigating to the report screen and the top most navigator is different from the one we want to navigate - PUSH the new screen to the top of the stack by default + // if (isCentralPaneName(action.payload.name) && (isTargetScreenDifferentThanCurrent || areParamsDifferent)) { + // // We need to push a tab if the tab doesn't match the central pane route that we are going to push. + // const topmostBottomTabRoute = getTopmostBottomTabRoute(rootState); + // const policyIDsFromState = extractPolicyIDsFromState(stateFromPath); + // const matchingBottomTabRoute = getMatchingBottomTabRouteForState(stateFromPath, policyID || policyIDsFromState); + // const isOpeningSearch = matchingBottomTabRoute.name === SCREENS.SEARCH.BOTTOM_TAB; + // const isNewPolicyID = + // ((topmostBottomTabRoute?.params as Record)?.policyID ?? '') !== + // ((matchingBottomTabRoute?.params as Record)?.policyID ?? ''); + + // if (topmostBottomTabRoute && (topmostBottomTabRoute.name !== matchingBottomTabRoute.name || isNewPolicyID || isOpeningSearch)) { + // root.dispatch({ + // type: CONST.NAVIGATION.ACTION_TYPE.PUSH, + // payload: matchingBottomTabRoute, + // }); + // } + + // if (type === CONST.NAVIGATION.TYPE.UP) { + // action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; + // } else { + // action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; + // } + + // // If we navigate to SCREENS.SEARCH.CENTRAL_PANE, it's necessary to pass the current policyID, but we have to remember that this param is called policyIDs on this page + // if (targetName === SCREENS.SEARCH.CENTRAL_PANE && targetParams && policyID) { + // (targetParams as Record).policyIDs = policyID; + // } + + // // If the type is UP, we deeplinked into one of the RHP flows and we want to replace the current screen with the previous one in the flow + // // and at the same time we want the back button to go to the page we were before the deeplink + // } else if (type === CONST.NAVIGATION.TYPE.UP) { + // action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; + + // // If this action is navigating to ModalNavigator or WorkspaceNavigator and the last route on the root navigator is not already opened Navigator then push + // } else if ((action.payload.name === NAVIGATORS.WORKSPACE_NAVIGATOR || isSideModalNavigator(action.payload.name)) && !isTargetNavigatorOnTop) { + // if (isSideModalNavigator(topRouteName)) { + // dismissModal(navigation); + // } + + // // If this RHP has mandatory central pane and bottom tab screens defined we need to push them. + // const {adaptedState, metainfo} = getAdaptedStateFromPath(path, linkingConfig.config); + // if (adaptedState && (metainfo.isCentralPaneAndBottomTabMandatory || metainfo.isWorkspaceNavigatorMandatory)) { + // const diff = getPartialStateDiff(rootState, adaptedState as State, metainfo); + // const diffActions = getActionsFromPartialDiff(diff); + // for (const diffAction of diffActions) { + // root.dispatch(diffAction); + // } + // } + // // All actions related to FullScreenNavigator on wide screen are pushed when comparing differences between rootState and adaptedState. + // if (action.payload.name === NAVIGATORS.WORKSPACE_NAVIGATOR) { + // return; + // } + // action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; + + // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + // } else if (action.payload.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR) { + // // If path contains a policyID, we should invoke the navigate function + // const shouldNavigate = !!extractedPolicyID; + // const actionForBottomTabNavigator = getActionForBottomTabNavigator(action, rootState, policyID, shouldNavigate); + + // if (!actionForBottomTabNavigator) { + // return; + // } + + // root.dispatch(actionForBottomTabNavigator); + + // // If the layout is wide we need to push matching central pane route to the stack. + // if (!isNarrowLayout) { + // // stateFromPath should always include bottom tab navigator state, so getMatchingCentralPaneRouteForState will be always defined. + // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + // const matchingCentralPaneRoute = getMatchingCentralPaneRouteForState(stateFromPath, rootState)!; + // if (matchingCentralPaneRoute && 'name' in matchingCentralPaneRoute) { + // root.dispatch({ + // type: CONST.NAVIGATION.ACTION_TYPE.PUSH, + // payload: { + // name: matchingCentralPaneRoute.name, + // params: matchingCentralPaneRoute.params, + // }, + // }); + // } + // } else { + // // If the layout is small we need to pop everything from the central pane so the bottom tab navigator is visible. + // root.dispatch({ + // type: 'POP_TO_TOP', + // target: rootState.key, + // }); + // } + // return; + // } + // } + + // if (action && 'payload' in action && action.payload && 'name' in action.payload && isSideModalNavigator(action.payload.name)) { + // // Information about the state may be in the params. + // const currentFocusedRoute = findFocusedRoute(extrapolateStateFromParams(rootState)); + // const targetFocusedRoute = findFocusedRoute(stateFromPath); + + // // If the current focused route is the same as the target focused route, we don't want to navigate. + // if ( + // currentFocusedRoute?.name === targetFocusedRoute?.name && + // shallowCompare(currentFocusedRoute?.params as Record, targetFocusedRoute?.params as Record) + // ) { + // return; + // } + + // const minimalAction = getMinimalAction(action, navigation.getRootState()); + // if (minimalAction) { + // // There are situations where a route already exists on the current navigation stack + // // But we want to push the same route instead of going back in the stack + // // Which would break the user navigation history + // if (!isActiveRoute && type === CONST.NAVIGATION.ACTION_TYPE.PUSH) { + // minimalAction.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; + // } + // root.dispatch(minimalAction); + // return; + // } + // } + + // // When we navigate from the ReportScreen opened in RHP, this page shouldn't be removed from the navigation state to allow users to go back to it. + // if (isReportInRhpOpened && action) { + // action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; + // } + + // if (action !== undefined) { + // root.dispatch(action); + // } else { + // root.reset(stateFromPath); + // } +} diff --git a/src/libs/Navigation/newLinkTo/types.ts b/src/libs/Navigation/newLinkTo/types.ts new file mode 100644 index 000000000000..254a4cdef2a5 --- /dev/null +++ b/src/libs/Navigation/newLinkTo/types.ts @@ -0,0 +1,11 @@ +type ActionPayloadParams = { + screen?: string; + params?: unknown; + path?: string; +}; + +type ActionPayload = { + params?: ActionPayloadParams; +}; + +export type {ActionPayload, ActionPayloadParams}; From 9c7967ac0d4d96646603e270b2f8beabdd6b028a Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Sat, 7 Sep 2024 11:29:20 +0200 Subject: [PATCH 066/257] Refactor useActiveWorkspace --- src/hooks/useReportIDs.tsx | 2 +- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 2 +- .../AppNavigator/Navigators/ReportsSplitNavigator.tsx | 2 +- src/libs/Navigation/linkingConfig/index.ts | 2 +- src/pages/workspace/WorkspaceNewRoomPage.tsx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hooks/useReportIDs.tsx b/src/hooks/useReportIDs.tsx index b7d84cb25196..d51d9e53c48c 100644 --- a/src/hooks/useReportIDs.tsx +++ b/src/hooks/useReportIDs.tsx @@ -91,7 +91,7 @@ function ReportIDsContextProvider({ const {accountID} = useCurrentUserPersonalDetails(); const currentReportIDValue = useCurrentReportID(); const derivedCurrentReportID = currentReportIDForTests ?? currentReportIDValue?.currentReportID; - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); const policyMemberAccountIDs = useMemo(() => getPolicyEmployeeListByIdWithoutCurrentUser(policies, activeWorkspaceID, accountID), [policies, activeWorkspaceID, accountID]); diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 4a741df8d6e1..82f05eef4f88 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -235,7 +235,7 @@ function AuthScreens() { const {shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout(); const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); const {canUseDefaultRooms} = usePermissions(); - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(onboardingIsMediumOrLargerScreenWidth), [screenOptions, onboardingIsMediumOrLargerScreenWidth]); const onboardingScreenOptions = useMemo( () => getOnboardingModalScreenOptions(shouldUseNarrowLayout, styles, StyleUtils, onboardingIsMediumOrLargerScreenWidth), diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index 2ad1d7a480c9..c52c97fef17a 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -23,7 +23,7 @@ function shouldOpenOnAdminRoom() { function ReportsSplitNavigator() { const {canUseDefaultRooms} = usePermissions(); - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); let initialReportID: string | undefined; const isInitialRender = useRef(true); diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index 7bb5e8ae5b5a..1f556aa67809 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -15,7 +15,7 @@ const linkingConfig: LinkingOptions = { return adaptedState; }, subscribe, - // getPathFromState: customGetPathFromState, + getPathFromState: customGetPathFromState, prefixes, config, }; diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 481fc6c41402..28a1e9ad4a7a 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -55,7 +55,7 @@ function WorkspaceNewRoomPage() { const wasLoading = usePrevious(!!formState?.isLoading); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); const {isLoading = false, errorFields = {}} = formState ?? {}; - const {activeWorkspaceID} = useActiveWorkspace(); + const activeWorkspaceID = useActiveWorkspace(); const activeWorkspaceOrDefaultID = activeWorkspaceID ?? activePolicyID; From af90fafa478e9c288f0621d5de539e1fcc8a2c6f Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 11 Sep 2024 11:53:37 +0200 Subject: [PATCH 067/257] Add createSplitNavigator --- .../LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts | 10 ++++++++ .../linkingConfig/SEARCH_RHP_SCREENS.ts | 24 +++++++++++++++++++ src/libs/Navigation/newLinkTo/index.ts | 6 ++--- 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts create mode 100644 src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts diff --git a/src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts b/src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts new file mode 100644 index 000000000000..963f8e1a1712 --- /dev/null +++ b/src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts @@ -0,0 +1,10 @@ +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; + +const LHN_TO_SPLIT_NAVIGATOR_NAME = { + [SCREENS.SETTINGS.ROOT]: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, + [SCREENS.HOME]: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, + [SCREENS.WORKSPACE.INITIAL]: NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, +}; + +export default LHN_TO_SPLIT_NAVIGATOR_NAME; diff --git a/src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts b/src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts new file mode 100644 index 000000000000..e61622f808bc --- /dev/null +++ b/src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts @@ -0,0 +1,24 @@ +import SCREENS from '@src/SCREENS'; + +const SEARCH_RHP_SCREENS: string[] = [ + SCREENS.SEARCH.REPORT_RHP, + SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_CURRENCY_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_DATE_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_DESCRIPTION_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_MERCHANT_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_REPORT_ID_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_AMOUNT_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_CATEGORY_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_KEYWORD_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_TAX_RATE_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_EXPENSE_TYPE_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_TAG_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_FROM_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_TO_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_IN_RHP, + SCREENS.SEARCH.ADVANCED_FILTERS_CARD_RHP, +]; + +export default SEARCH_RHP_SCREENS; diff --git a/src/libs/Navigation/newLinkTo/index.ts b/src/libs/Navigation/newLinkTo/index.ts index 0f278a9dfc24..100491b04bd3 100644 --- a/src/libs/Navigation/newLinkTo/index.ts +++ b/src/libs/Navigation/newLinkTo/index.ts @@ -74,7 +74,7 @@ export default function linkTo(navigation: NavigationContainerRef Date: Wed, 18 Sep 2024 16:09:37 +0200 Subject: [PATCH 068/257] improve routers --- .../CustomRouter.ts | 2 - src/libs/Navigation/newLinkTo/index.ts | 182 +----------------- 2 files changed, 1 insertion(+), 183 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 829d173659a3..0652a5305e55 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -90,13 +90,11 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { if (!queryJSON) { return null; } - if (action.payload.policyID) { queryJSON.policyID = action.payload.policyID; } else { delete queryJSON.policyID; } - const newAction = StackActions.push(SCREENS.SEARCH.CENTRAL_PANE, { ...currentParams, q: SearchUtils.buildSearchQueryString(queryJSON), diff --git a/src/libs/Navigation/newLinkTo/index.ts b/src/libs/Navigation/newLinkTo/index.ts index 100491b04bd3..e19f02687f1c 100644 --- a/src/libs/Navigation/newLinkTo/index.ts +++ b/src/libs/Navigation/newLinkTo/index.ts @@ -24,7 +24,7 @@ function shouldDispatchAction(currentState: NavigationState, return true; } -export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string, isActiveRoute?: boolean) { +export default function linkTo(navigation: NavigationContainerRef | null, path: Route) { if (!navigation) { throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); } @@ -54,186 +54,6 @@ export default function linkTo(navigation: NavigationContainerRef; - // const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; - // // Creating path with /w/ included if necessary. - // const topmostCentralPaneRoute = getTopmostCentralPaneRoute(rootState); - // const policyIDs = !!topmostCentralPaneRoute?.params && 'policyIDs' in topmostCentralPaneRoute.params ? (topmostCentralPaneRoute?.params?.policyIDs as string) : ''; - // const extractedPolicyID = extractPolicyIDFromPath(`/${path}`); - // const policyIDFromState = getPolicyIDFromState(rootState); - // const policyID = extractedPolicyID ?? policyIDFromState ?? policyIDs; - // const lastRoute = rootState?.routes?.at(-1); - - // const isNarrowLayout = getIsNarrowLayout(); - - // const isWorkspaceScreenOnTop = lastRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR; - - // // policyIDs is present only on SCREENS.SEARCH.CENTRAL_PANE and it's displayed in the url as a query param, on the other pages this parameter is called policyID and it's shown in the url in the format: /w/:policyID - // if (policyID && !isWorkspaceScreenOnTop && !policyIDs) { - // // The stateFromPath doesn't include proper path if there is a policy passed with /w/id. - // // We need to replace the path in the state with the proper one. - // // To avoid this hacky solution we may want to create custom getActionFromState function in the future. - // replacePathInNestedState(stateFromPath, `/w/${policyID}${pathWithoutPolicyID}`); - // } - - // const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); - - // const isReportInRhpOpened = isReportOpenInRHP(rootState); - - // // If action type is different than NAVIGATE we can't change it to the PUSH safely - // if (action?.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { - // const actionPayloadParams = action.payload.params as ActionPayloadParams; - - // const topRouteName = lastRoute?.name; - - // // CentralPane screens aren't nested in any navigator, if actionPayloadParams?.screen is undefined, it means the screen name and parameters have to be read directly from action.payload - // const targetName = actionPayloadParams?.screen ?? action.payload.name; - // const targetParams = actionPayloadParams?.params ?? actionPayloadParams; - // const isTargetNavigatorOnTop = topRouteName === action.payload.name; - - // const isTargetScreenDifferentThanCurrent = !!(!topmostCentralPaneRoute || topmostCentralPaneRoute.name !== targetName); - // const areParamsDifferent = - // targetName === SCREENS.REPORT - // ? getTopmostReportId(rootState) !== getTopmostReportId(stateFromPath) - // : !shallowCompare( - // omitBy(topmostCentralPaneRoute?.params as Record | undefined, (value) => value === undefined), - // omitBy(targetParams as Record | undefined, (value) => value === undefined), - // ); - - // // If this action is navigating to the report screen and the top most navigator is different from the one we want to navigate - PUSH the new screen to the top of the stack by default - // if (isCentralPaneName(action.payload.name) && (isTargetScreenDifferentThanCurrent || areParamsDifferent)) { - // // We need to push a tab if the tab doesn't match the central pane route that we are going to push. - // const topmostBottomTabRoute = getTopmostBottomTabRoute(rootState); - // const policyIDsFromState = extractPolicyIDsFromState(stateFromPath); - // const matchingBottomTabRoute = getMatchingBottomTabRouteForState(stateFromPath, policyID || policyIDsFromState); - // const isOpeningSearch = matchingBottomTabRoute.name === SCREENS.SEARCH.BOTTOM_TAB; - // const isNewPolicyID = - // ((topmostBottomTabRoute?.params as Record)?.policyID ?? '') !== - // ((matchingBottomTabRoute?.params as Record)?.policyID ?? ''); - - // if (topmostBottomTabRoute && (topmostBottomTabRoute.name !== matchingBottomTabRoute.name || isNewPolicyID || isOpeningSearch)) { - // root.dispatch({ - // type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - // payload: matchingBottomTabRoute, - // }); - // } - - // if (type === CONST.NAVIGATION.TYPE.UP) { - // action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; - // } else { - // action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - // } - - // // If we navigate to SCREENS.SEARCH.CENTRAL_PANE, it's necessary to pass the current policyID, but we have to remember that this param is called policyIDs on this page - // if (targetName === SCREENS.SEARCH.CENTRAL_PANE && targetParams && policyID) { - // (targetParams as Record).policyIDs = policyID; - // } - - // // If the type is UP, we deeplinked into one of the RHP flows and we want to replace the current screen with the previous one in the flow - // // and at the same time we want the back button to go to the page we were before the deeplink - // } else if (type === CONST.NAVIGATION.TYPE.UP) { - // action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; - - // // If this action is navigating to ModalNavigator or WorkspaceNavigator and the last route on the root navigator is not already opened Navigator then push - // } else if ((action.payload.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR || isSideModalNavigator(action.payload.name)) && !isTargetNavigatorOnTop) { - // if (isSideModalNavigator(topRouteName)) { - // dismissModal(navigation); - // } - - // // If this RHP has mandatory central pane and bottom tab screens defined we need to push them. - // const {adaptedState, metainfo} = getAdaptedStateFromPath(path, linkingConfig.config); - // if (adaptedState && (metainfo.isCentralPaneAndBottomTabMandatory || metainfo.isWorkspaceNavigatorMandatory)) { - // const diff = getPartialStateDiff(rootState, adaptedState as State, metainfo); - // const diffActions = getActionsFromPartialDiff(diff); - // for (const diffAction of diffActions) { - // root.dispatch(diffAction); - // } - // } - // // All actions related to FullScreenNavigator on wide screen are pushed when comparing differences between rootState and adaptedState. - // if (action.payload.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - // return; - // } - // action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - - // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - // } else if (action.payload.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR) { - // // If path contains a policyID, we should invoke the navigate function - // const shouldNavigate = !!extractedPolicyID; - // const actionForBottomTabNavigator = getActionForBottomTabNavigator(action, rootState, policyID, shouldNavigate); - - // if (!actionForBottomTabNavigator) { - // return; - // } - - // root.dispatch(actionForBottomTabNavigator); - - // // If the layout is wide we need to push matching central pane route to the stack. - // if (!isNarrowLayout) { - // // stateFromPath should always include bottom tab navigator state, so getMatchingCentralPaneRouteForState will be always defined. - // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - // const matchingCentralPaneRoute = getMatchingCentralPaneRouteForState(stateFromPath, rootState)!; - // if (matchingCentralPaneRoute && 'name' in matchingCentralPaneRoute) { - // root.dispatch({ - // type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - // payload: { - // name: matchingCentralPaneRoute.name, - // params: matchingCentralPaneRoute.params, - // }, - // }); - // } - // } else { - // // If the layout is small we need to pop everything from the central pane so the bottom tab navigator is visible. - // root.dispatch({ - // type: 'POP_TO_TOP', - // target: rootState.key, - // }); - // } - // return; - // } - // } - - // if (action && 'payload' in action && action.payload && 'name' in action.payload && isSideModalNavigator(action.payload.name)) { - // // Information about the state may be in the params. - // const currentFocusedRoute = findFocusedRoute(extrapolateStateFromParams(rootState)); - // const targetFocusedRoute = findFocusedRoute(stateFromPath); - - // // If the current focused route is the same as the target focused route, we don't want to navigate. - // if ( - // currentFocusedRoute?.name === targetFocusedRoute?.name && - // shallowCompare(currentFocusedRoute?.params as Record, targetFocusedRoute?.params as Record) - // ) { - // return; - // } - - // const minimalAction = getMinimalAction(action, navigation.getRootState()); - // if (minimalAction) { - // // There are situations where a route already exists on the current navigation stack - // // But we want to push the same route instead of going back in the stack - // // Which would break the user navigation history - // if (!isActiveRoute && type === CONST.NAVIGATION.ACTION_TYPE.PUSH) { - // minimalAction.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - // } - // root.dispatch(minimalAction); - // return; - // } - // } - - // // When we navigate from the ReportScreen opened in RHP, this page shouldn't be removed from the navigation state to allow users to go back to it. - // if (isReportInRhpOpened && action) { - // action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - // } - - // if (action !== undefined) { - // root.dispatch(action); - // } else { - // root.reset(stateFromPath); - // } } From f3986530c9f78ff4d0601bd3ae5f37b7f4072a2c Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 18 Sep 2024 17:46:43 +0200 Subject: [PATCH 069/257] add setter to activeWorkspaceID context --- src/hooks/useReportIDs.tsx | 2 +- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 2 +- .../AppNavigator/Navigators/ReportsSplitNavigator.tsx | 2 +- .../AppNavigator/createCustomStackNavigator/CustomRouter.ts | 2 ++ src/pages/workspace/WorkspaceNewRoomPage.tsx | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/hooks/useReportIDs.tsx b/src/hooks/useReportIDs.tsx index d51d9e53c48c..b7d84cb25196 100644 --- a/src/hooks/useReportIDs.tsx +++ b/src/hooks/useReportIDs.tsx @@ -91,7 +91,7 @@ function ReportIDsContextProvider({ const {accountID} = useCurrentUserPersonalDetails(); const currentReportIDValue = useCurrentReportID(); const derivedCurrentReportID = currentReportIDForTests ?? currentReportIDValue?.currentReportID; - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const policyMemberAccountIDs = useMemo(() => getPolicyEmployeeListByIdWithoutCurrentUser(policies, activeWorkspaceID, accountID), [policies, activeWorkspaceID, accountID]); diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 82f05eef4f88..4a741df8d6e1 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -235,7 +235,7 @@ function AuthScreens() { const {shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout(); const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils); const {canUseDefaultRooms} = usePermissions(); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(onboardingIsMediumOrLargerScreenWidth), [screenOptions, onboardingIsMediumOrLargerScreenWidth]); const onboardingScreenOptions = useMemo( () => getOnboardingModalScreenOptions(shouldUseNarrowLayout, styles, StyleUtils, onboardingIsMediumOrLargerScreenWidth), diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index c52c97fef17a..2ad1d7a480c9 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -23,7 +23,7 @@ function shouldOpenOnAdminRoom() { function ReportsSplitNavigator() { const {canUseDefaultRooms} = usePermissions(); - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); let initialReportID: string | undefined; const isInitialRender = useRef(true); diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 0652a5305e55..829d173659a3 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -90,11 +90,13 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { if (!queryJSON) { return null; } + if (action.payload.policyID) { queryJSON.policyID = action.payload.policyID; } else { delete queryJSON.policyID; } + const newAction = StackActions.push(SCREENS.SEARCH.CENTRAL_PANE, { ...currentParams, q: SearchUtils.buildSearchQueryString(queryJSON), diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 28a1e9ad4a7a..481fc6c41402 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -55,7 +55,7 @@ function WorkspaceNewRoomPage() { const wasLoading = usePrevious(!!formState?.isLoading); const visibilityDescription = useMemo(() => translate(`newRoomPage.${visibility}Description`), [translate, visibility]); const {isLoading = false, errorFields = {}} = formState ?? {}; - const activeWorkspaceID = useActiveWorkspace(); + const {activeWorkspaceID} = useActiveWorkspace(); const activeWorkspaceOrDefaultID = activeWorkspaceID ?? activePolicyID; From 58be5b5a416ababf5162b08b8739ca929671b7aa Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 19 Sep 2024 12:53:06 +0200 Subject: [PATCH 070/257] Fix LHN paddings --- src/pages/settings/InitialSettingsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 32ca20741d07..4a014fdcfb25 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -413,7 +413,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr scrollEventThrottle={16} contentContainerStyle={[styles.w100]} showsVerticalScrollIndicator={false} - > + > {accountMenuItems} {workspaceMenuItems} {generalMenuItems} From 0f9efb91bd883a6822f15c204ae379a9b4a32910 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 20 Sep 2024 15:20:52 +0200 Subject: [PATCH 071/257] remember state between tabs --- src/libs/Navigation/newLinkTo/index.ts | 6 ++++-- src/pages/workspace/WorkspaceInitialPage.tsx | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/newLinkTo/index.ts b/src/libs/Navigation/newLinkTo/index.ts index e19f02687f1c..f8ac74d6e61f 100644 --- a/src/libs/Navigation/newLinkTo/index.ts +++ b/src/libs/Navigation/newLinkTo/index.ts @@ -24,7 +24,7 @@ function shouldDispatchAction(currentState: NavigationState, return true; } -export default function linkTo(navigation: NavigationContainerRef | null, path: Route) { +export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: typeof CONST.NAVIGATION.ACTION_TYPE.REPLACE) { if (!navigation) { throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); } @@ -49,7 +49,9 @@ export default function linkTo(navigation: NavigationContainerRef Date: Tue, 24 Sep 2024 07:12:01 +0200 Subject: [PATCH 072/257] Test freezing split navigators --- src/libs/Navigation/NavigationRoot.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 124e0ed541d6..99a38d8d0bf2 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -165,6 +165,8 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh // We want to clean saved scroll offsets for screens that aren't anymore in the state. cleanStaleScrollOffsets(state); + + console.log('state', state); }; return ( From d74d1ebaff1e38a3f81cb73d2844d0ea7b402e68 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 27 Sep 2024 17:19:40 +0200 Subject: [PATCH 073/257] Fix flickering in frozen split navigators --- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 4 ---- src/libs/Navigation/NavigationRoot.tsx | 2 -- 2 files changed, 6 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 4a741df8d6e1..9eba945176a5 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -35,7 +35,6 @@ import {buildSearchQueryString} from '@libs/SearchUtils'; import * as SessionUtils from '@libs/SessionUtils'; import ConnectionCompletePage from '@pages/ConnectionCompletePage'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; -import SearchPage from '@pages/Search/SearchPage'; import DesktopSignInRedirectPage from '@pages/signin/DesktopSignInRedirectPage'; import * as App from '@userActions/App'; import * as Download from '@userActions/Download'; @@ -65,11 +64,8 @@ import ExplanationModalNavigator from './Navigators/ExplanationModalNavigator'; import FeatureTrainingModalNavigator from './Navigators/FeatureTrainingModalNavigator'; import LeftModalNavigator from './Navigators/LeftModalNavigator'; import OnboardingModalNavigator from './Navigators/OnboardingModalNavigator'; -import ReportsSplitNavigator from './Navigators/ReportsSplitNavigator'; import RightModalNavigator from './Navigators/RightModalNavigator'; -import SettingsSplitNavigator from './Navigators/SettingsSplitNavigator'; import WelcomeVideoModalNavigator from './Navigators/WelcomeVideoModalNavigator'; -import WorkspaceSplitNavigator from './Navigators/WorkspaceSplitNavigator'; const loadReportAttachments = () => require('../../../pages/home/report/ReportAttachments').default; const loadValidateLoginPage = () => require('../../../pages/ValidateLoginPage').default; diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 99a38d8d0bf2..124e0ed541d6 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -165,8 +165,6 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh // We want to clean saved scroll offsets for screens that aren't anymore in the state. cleanStaleScrollOffsets(state); - - console.log('state', state); }; return ( From 3d73e89aed3ed204498919b49fb16ce559c463a3 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 2 Oct 2024 12:26:05 +0200 Subject: [PATCH 074/257] Fix types in getMinimalAction and goUp functions --- src/libs/Navigation/Navigation.ts | 85 +++++++++---------- .../Navigation/newLinkTo/getMinimalAction.ts | 9 +- src/libs/Navigation/newLinkTo/index.ts | 2 +- 3 files changed, 50 insertions(+), 46 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index d46a74780e06..ce0404d63945 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -1,9 +1,11 @@ -import {findFocusedRoute, getActionFromState} from '@react-navigation/core'; -import type {EventArg, NavigationContainerEventMap} from '@react-navigation/native'; +import {getActionFromState} from '@react-navigation/core'; +import type {EventArg, NavigationAction, NavigationContainerEventMap} from '@react-navigation/native'; import {CommonActions, getPathFromState, StackActions} from '@react-navigation/native'; import type {OnyxEntry} from 'react-native-onyx'; +import type {Writable} from 'type-fest'; import Log from '@libs/Log'; import {removePolicyIDParamFromState} from '@libs/NavigationUtils'; +import {shallowCompare} from '@libs/ObjectUtils'; import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils'; import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; @@ -27,9 +29,9 @@ import linkTo from './linkTo'; import getMinimalAction from './linkTo/getMinimalAction'; import navigationRef from './navigationRef'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; -import type {NavigationStateRoute, RootStackParamList, SplitNavigatorLHNScreen, SplitNavigatorName, SplitNavigatorParamListType, StackNavigationAction, State, StateOrRoute} from './types'; +import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, SplitNavigatorLHNScreen, SplitNavigatorParamListType, State, StateOrRoute} from './types'; -const SPLIT_NAVIGATOR_TO_SIDEBAR_MAP: Record = { +const SPLIT_NAVIGATOR_TO_SIDEBAR_MAP: Record = { [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: SCREENS.HOME, [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: SCREENS.SETTINGS.ROOT, [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: SCREENS.WORKSPACE.INITIAL, @@ -202,6 +204,28 @@ function navigate(route: Route = ROUTES.HOME, type?: string) { linkTo(navigationRef.current, route, type, isActiveRoute(route)); } +function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | NavigationPartialRoute, minimalAction: Writable) { + if (!minimalAction.payload) { + return false; + } + + if (!('name' in minimalAction.payload)) { + return false; + } + + const areRouteNamesEqual = route.name === minimalAction.payload.name; + + if (!areRouteNamesEqual) { + return false; + } + + if (!('params' in minimalAction.payload)) { + return false; + } + + return shallowCompare(route.params as Record, minimalAction.payload.params as Record); +} + function goUp(fallbackRoute: Route) { if (!canNavigate('goBack')) { return; @@ -212,56 +236,30 @@ function goUp(fallbackRoute: Route) { return; } - const rootState = navigationRef.current?.getRootState(); - const lastRoute = rootState?.routes.at(-1); - - const route = findFocusedRoute(getStateFromPath(fallbackRoute)); - const routeName = route?.name; + const rootState = navigationRef.current.getRootState(); + const stateFromPath = getStateFromPath(fallbackRoute); + const action = getActionFromState(stateFromPath, linkingConfig.config); - if (!routeName) { + if (!action) { return; } - if (rootState?.routeNames?.includes(route?.name)) { - if (rootState?.routes.at(-2)?.name === routeName) { - navigationRef.current.dispatch(StackActions.pop()); - return; - } - navigate(fallbackRoute, 'REPLACE'); - return; - } + const {action: minimalAction, targetState} = getMinimalAction(action, rootState); - if (lastRoute?.state?.routeNames?.includes(route?.name)) { - const distanceFromPathInRootNavigator = getDistanceFromPathInRootNavigator(lastRoute?.state, fallbackRoute ?? ''); - if (distanceFromPathInRootNavigator > 0) { - navigationRef.current.dispatch({...StackActions.pop(distanceFromPathInRootNavigator), target: lastRoute?.key}); - return; - } - navigate(fallbackRoute, 'REPLACE'); + if (minimalAction.type !== CONST.NAVIGATION.ACTION_TYPE.NAVIGATE || !targetState) { return; } - const secondToLastRoute = rootState?.routes.at(-2); + const indexOfFallbackRoute = targetState.routes.findLastIndex((route) => doesRouteMatchToMinimalActionPayload(route, minimalAction)); - if (secondToLastRoute?.state?.routeNames?.includes(route?.name)) { - navigationRef.current.dispatch(StackActions.pop()); - const distanceFromPathInRootNavigator = getDistanceFromPathInRootNavigator(secondToLastRoute?.state, fallbackRoute ?? ''); - if (distanceFromPathInRootNavigator > 0) { - navigationRef.current.dispatch({...StackActions.pop(distanceFromPathInRootNavigator), target: secondToLastRoute?.key}); - return; - } - const routes = navigationRef.current.getRootState().routes; - const stateFromPath = getStateFromPath(fallbackRoute); - const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); - if (!action) { - return; - } - const minimalAction = getMinimalAction(action, {...rootState, routes: routes.slice(0, -1), index: rootState.index - 1}); - navigationRef.dispatch(minimalAction); + if (indexOfFallbackRoute === -1) { + const replaceAction = {...minimalAction, type: 'REPLACE'} as NavigationAction; + navigationRef.current.dispatch(replaceAction); return; } - navigate(fallbackRoute, 'REPLACE'); + const distanceToPop = targetState.routes.length - indexOfFallbackRoute - 1; + navigationRef.current.dispatch({...StackActions.pop(distanceToPop), target: targetState.key}); } /** @@ -291,7 +289,8 @@ function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopT const lastRoute = rootState?.routes.at(-1); if (lastRoute?.name.endsWith('SplitNavigator') && lastRoute?.state?.routes?.length === 1) { - const name = SPLIT_NAVIGATOR_TO_SIDEBAR_MAP[lastRoute?.name as SplitNavigatorName]; + const splitNavigatorName = lastRoute?.name as keyof SplitNavigatorParamListType; + const name = SPLIT_NAVIGATOR_TO_SIDEBAR_MAP[splitNavigatorName]; const params = getSidebarScreenParams(lastRoute); navigationRef.dispatch({ type: 'REPLACE', diff --git a/src/libs/Navigation/newLinkTo/getMinimalAction.ts b/src/libs/Navigation/newLinkTo/getMinimalAction.ts index ff01b3b8333b..9eab2f6f8717 100644 --- a/src/libs/Navigation/newLinkTo/getMinimalAction.ts +++ b/src/libs/Navigation/newLinkTo/getMinimalAction.ts @@ -3,6 +3,11 @@ import type {Writable} from 'type-fest'; import type {State} from '@navigation/types'; import type {ActionPayload} from './types'; +type MinimalAction = { + action: Writable; + targetState: State | undefined; +}; + /** * Motivation for this function is described in NAVIGATION.md * @@ -10,7 +15,7 @@ import type {ActionPayload} from './types'; * @param state The root state * @returns minimalAction minimal action is the action that we should dispatch */ -function getMinimalAction(action: NavigationAction, state: NavigationState): Writable { +function getMinimalAction(action: NavigationAction, state: NavigationState): MinimalAction { let currentAction: NavigationAction = action; let currentState: State | undefined = state; let currentTargetKey: string | undefined; @@ -36,7 +41,7 @@ function getMinimalAction(action: NavigationAction, state: NavigationState): Wri target: currentTargetKey, }; } - return currentAction; + return {action: currentAction, targetState: currentState}; } export default getMinimalAction; diff --git a/src/libs/Navigation/newLinkTo/index.ts b/src/libs/Navigation/newLinkTo/index.ts index f8ac74d6e61f..40d51cd6ec9f 100644 --- a/src/libs/Navigation/newLinkTo/index.ts +++ b/src/libs/Navigation/newLinkTo/index.ts @@ -56,6 +56,6 @@ export default function linkTo(navigation: NavigationContainerRef Date: Wed, 2 Oct 2024 14:49:13 +0200 Subject: [PATCH 075/257] Fix replacing a sidebar screen in split navigators --- src/libs/Navigation/Navigation.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index ce0404d63945..79456dbfacab 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -288,7 +288,9 @@ function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopT const rootState = navigationRef.current?.getRootState(); const lastRoute = rootState?.routes.at(-1); - if (lastRoute?.name.endsWith('SplitNavigator') && lastRoute?.state?.routes?.length === 1) { + const canGoBack = navigationRef.current?.canGoBack(); + + if (!canGoBack && lastRoute?.name.endsWith('SplitNavigator') && lastRoute?.state?.routes?.length === 1) { const splitNavigatorName = lastRoute?.name as keyof SplitNavigatorParamListType; const name = SPLIT_NAVIGATOR_TO_SIDEBAR_MAP[splitNavigatorName]; const params = getSidebarScreenParams(lastRoute); @@ -302,12 +304,12 @@ function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopT return; } - if (!navigationRef.current?.canGoBack()) { + if (!canGoBack) { Log.hmmm('[Navigation] Unable to go back'); return; } - navigationRef.current.goBack(); + navigationRef.current?.goBack(); } /** From 38d466f000ee0572fc0c0d70d16dd9d250bf3e59 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 4 Oct 2024 15:43:50 +0200 Subject: [PATCH 076/257] Adjust Navigation.resetToHome to work with SplitNavigators --- src/libs/Navigation/Navigation.ts | 33 +++++++++---------------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 79456dbfacab..6031dcbc5f16 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -3,6 +3,7 @@ import type {EventArg, NavigationAction, NavigationContainerEventMap} from '@rea import {CommonActions, getPathFromState, StackActions} from '@react-navigation/native'; import type {OnyxEntry} from 'react-native-onyx'; import type {Writable} from 'type-fest'; +import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import Log from '@libs/Log'; import {removePolicyIDParamFromState} from '@libs/NavigationUtils'; import {shallowCompare} from '@libs/ObjectUtils'; @@ -312,35 +313,20 @@ function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopT navigationRef.current?.goBack(); } -/** - * Close the current screen and navigate to the route. - * If the current screen is the first screen in the navigator, we force using the fallback route to replace the current screen. - * It's useful in a case where we want to close an RHP and navigate to another RHP to prevent any blink effect. - */ -function closeAndNavigate(route: Route) { - if (!navigationRef.current) { - return; - } - - const isFirstRouteInNavigator = !getActiveRouteIndex(navigationRef.current.getState()); - if (isFirstRouteInNavigator) { - goBack(route, true); - return; - } - goBack(); - navigate(route); -} - /** * Reset the navigation state to Home page */ function resetToHome() { + const isNarrowLayout = getIsNarrowLayout(); const rootState = navigationRef.getRootState(); - const bottomTabKey = rootState.routes.find((item: NavigationStateRoute) => item.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR)?.state?.key; - if (bottomTabKey) { - navigationRef.dispatch({...StackActions.popToTop(), target: bottomTabKey}); - } navigationRef.dispatch({...StackActions.popToTop(), target: rootState.key}); + const splitNavigatorMainScreen = !isNarrowLayout + ? { + name: SCREENS.REPORT, + } + : undefined; + const payload = createSplitNavigator({name: SCREENS.HOME}, splitNavigatorMainScreen); + navigationRef.dispatch({payload, type: 'REPLACE', target: rootState.key}); } /** @@ -508,7 +494,6 @@ export default { getActiveRoute, getActiveRouteWithoutParams, getReportRHPActiveRoute, - closeAndNavigate, goBack, isNavigationReady, setIsNavigationReady, From e2ad7440a77de681525aee6b9b881c16105d8266 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 7 Oct 2024 15:59:45 +0200 Subject: [PATCH 077/257] Replace some usages of resetToHome with goUp(ROUTES.HOME) --- src/libs/Navigation/Navigation.ts | 5 +++-- src/pages/settings/Subscription/CardSection/CardSection.tsx | 2 +- src/pages/workspace/AccessOrNotFoundWrapper.tsx | 2 +- src/pages/workspace/WorkspaceInitialPage.tsx | 4 ++-- src/pages/workspace/WorkspacePageWithSections.tsx | 5 +++-- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 6031dcbc5f16..c250f467a697 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -224,6 +224,7 @@ function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | Navi return false; } + // @TODO: Fix params comparison. When comparing split navigators params, it may happen that first one has parameters with the initial settings and the second one does not. return shallowCompare(route.params as Record, minimalAction.payload.params as Record); } @@ -232,8 +233,8 @@ function goUp(fallbackRoute: Route) { return; } - if (!navigationRef.current?.canGoBack()) { - Log.hmmm('[Navigation] Unable to go back'); + if (!navigationRef.current) { + Log.hmmm('[Navigation] Unable to go up'); return; } diff --git a/src/pages/settings/Subscription/CardSection/CardSection.tsx b/src/pages/settings/Subscription/CardSection/CardSection.tsx index 7346e34bb14e..d1b4286474a5 100644 --- a/src/pages/settings/Subscription/CardSection/CardSection.tsx +++ b/src/pages/settings/Subscription/CardSection/CardSection.tsx @@ -57,7 +57,7 @@ function CardSection() { const requestRefund = useCallback(() => { User.requestRefund(); setIsRequestRefundModalVisible(false); - Navigation.resetToHome(); + Navigation.goUp(ROUTES.HOME); }, []); const viewPurchases = useCallback(() => { diff --git a/src/pages/workspace/AccessOrNotFoundWrapper.tsx b/src/pages/workspace/AccessOrNotFoundWrapper.tsx index 5deae769531d..be748a50bb5d 100644 --- a/src/pages/workspace/AccessOrNotFoundWrapper.tsx +++ b/src/pages/workspace/AccessOrNotFoundWrapper.tsx @@ -91,7 +91,7 @@ function PageNotFoundFallback({policyID, shouldShowFullScreenFallback, fullPageN shouldForceFullScreen={shouldShowFullScreenFallback} onBackButtonPress={() => { if (shouldShowFullScreenFallback) { - Navigation.dismissModal(); + Navigation.goUp(ROUTES.SETTINGS_WORKSPACES); return; } Navigation.goBack(policyID && !isMoneyRequest ? ROUTES.WORKSPACE_PROFILE.getRoute(policyID) : undefined); diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index bb2e53129b68..fed578c4c1f9 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -368,7 +368,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac > Navigation.goUp(ROUTES.HOME)} shouldShow={shouldShowNotFoundPage} subtitleKey={isEmptyObject(policy) ? undefined : 'workspace.common.notAuthorized'} > @@ -376,7 +376,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac title={policyName} onBackButtonPress={() => { if (route.params?.backTo) { - Navigation.resetToHome(); + Navigation.goUp(ROUTES.HOME); Navigation.isNavigationReady().then(() => Navigation.navigate(route.params?.backTo as Route)); } else { Navigation.goUp(ROUTES.SETTINGS_WORKSPACES); diff --git a/src/pages/workspace/WorkspacePageWithSections.tsx b/src/pages/workspace/WorkspacePageWithSections.tsx index 4f0a84cffd9c..d7999971cca7 100644 --- a/src/pages/workspace/WorkspacePageWithSections.tsx +++ b/src/pages/workspace/WorkspacePageWithSections.tsx @@ -21,6 +21,7 @@ import * as BankAccounts from '@userActions/BankAccounts'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; +import ROUTES from '@src/ROUTES'; import type {Policy} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; @@ -173,8 +174,8 @@ function WorkspacePageWithSections({ shouldShowOfflineIndicatorInWideScreen={shouldShowOfflineIndicatorInWideScreen && !shouldShow} > Navigation.goUp(ROUTES.SETTINGS_WORKSPACES)} + onLinkPress={() => Navigation.goUp(ROUTES.HOME)} shouldShow={shouldShow} subtitleKey={isEmptyObject(policy) ? undefined : 'workspace.common.notAuthorized'} shouldForceFullScreen From 53fe13e23824b860da3c6c6975e4e4e93bcb0f33 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 8 Oct 2024 12:17:37 +0200 Subject: [PATCH 078/257] Cleanup linkTo and getMinimalAction --- src/libs/Navigation/Navigation.ts | 1 + .../Navigation/linkTo/getMinimalAction.ts | 9 +++- src/libs/Navigation/linkTo/index.ts | 2 +- .../Navigation/newLinkTo/getMinimalAction.ts | 47 ------------------- 4 files changed, 9 insertions(+), 50 deletions(-) delete mode 100644 src/libs/Navigation/newLinkTo/getMinimalAction.ts diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index c250f467a697..92b739ff8879 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -31,6 +31,7 @@ import getMinimalAction from './linkTo/getMinimalAction'; import navigationRef from './navigationRef'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, SplitNavigatorLHNScreen, SplitNavigatorParamListType, State, StateOrRoute} from './types'; +import createSplitNavigator from './linkingConfig/createSplitNavigator'; const SPLIT_NAVIGATOR_TO_SIDEBAR_MAP: Record = { [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: SCREENS.HOME, diff --git a/src/libs/Navigation/linkTo/getMinimalAction.ts b/src/libs/Navigation/linkTo/getMinimalAction.ts index ff01b3b8333b..9eab2f6f8717 100644 --- a/src/libs/Navigation/linkTo/getMinimalAction.ts +++ b/src/libs/Navigation/linkTo/getMinimalAction.ts @@ -3,6 +3,11 @@ import type {Writable} from 'type-fest'; import type {State} from '@navigation/types'; import type {ActionPayload} from './types'; +type MinimalAction = { + action: Writable; + targetState: State | undefined; +}; + /** * Motivation for this function is described in NAVIGATION.md * @@ -10,7 +15,7 @@ import type {ActionPayload} from './types'; * @param state The root state * @returns minimalAction minimal action is the action that we should dispatch */ -function getMinimalAction(action: NavigationAction, state: NavigationState): Writable { +function getMinimalAction(action: NavigationAction, state: NavigationState): MinimalAction { let currentAction: NavigationAction = action; let currentState: State | undefined = state; let currentTargetKey: string | undefined; @@ -36,7 +41,7 @@ function getMinimalAction(action: NavigationAction, state: NavigationState): Wri target: currentTargetKey, }; } - return currentAction; + return {action: currentAction, targetState: currentState}; } export default getMinimalAction; diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index f8ac74d6e61f..40d51cd6ec9f 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -56,6 +56,6 @@ export default function linkTo(navigation: NavigationContainerRef; - targetState: State | undefined; -}; - -/** - * Motivation for this function is described in NAVIGATION.md - * - * @param action action generated by getActionFromState - * @param state The root state - * @returns minimalAction minimal action is the action that we should dispatch - */ -function getMinimalAction(action: NavigationAction, state: NavigationState): MinimalAction { - let currentAction: NavigationAction = action; - let currentState: State | undefined = state; - let currentTargetKey: string | undefined; - - while (currentAction.payload && 'name' in currentAction.payload && currentState?.routes[currentState.index ?? -1].name === currentAction.payload.name) { - if (!currentState?.routes[currentState.index ?? -1].state) { - break; - } - - currentState = currentState?.routes[currentState.index ?? -1].state; - currentTargetKey = currentState?.key; - - const payload = currentAction.payload as ActionPayload; - - // Creating new smaller action - currentAction = { - type: currentAction.type, - payload: { - name: payload?.params?.screen, - params: payload?.params?.params, - path: payload?.params?.path, - }, - target: currentTargetKey, - }; - } - return {action: currentAction, targetState: currentState}; -} - -export default getMinimalAction; From 05d529afd75959bcb192c02758cb6cb8ec7def23 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 8 Oct 2024 12:48:57 +0200 Subject: [PATCH 079/257] Cleanup navigation changes --- .../useNavigationReset/index.native.ts | 1 - .../useNavigationReset/index.ts | 14 ----- src/libs/Navigation/Navigation.ts | 2 +- .../linkingConfig/SEARCH_RHP_SCREENS.ts | 24 -------- .../linkingConfig/getAdaptedStateFromPath.ts | 3 - .../getActionForBottomTabNavigator.ts | 50 --------------- src/libs/Navigation/newLinkTo/index.ts | 61 ------------------- src/libs/Navigation/newLinkTo/types.ts | 11 ---- src/libs/Navigation/types.ts | 3 - src/pages/settings/InitialSettingsPage.tsx | 2 +- 10 files changed, 2 insertions(+), 169 deletions(-) delete mode 100644 src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts delete mode 100644 src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts delete mode 100644 src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts delete mode 100644 src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts delete mode 100644 src/libs/Navigation/newLinkTo/index.ts delete mode 100644 src/libs/Navigation/newLinkTo/types.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts deleted file mode 100644 index 5d5d30356781..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.native.ts +++ /dev/null @@ -1 +0,0 @@ -export default function useNavigationReset() {} diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts deleted file mode 100644 index 238fc1ca2928..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useNavigationReset/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type {NavigationHelpers, ParamListBase} from '@react-navigation/native'; -import {useEffect} from 'react'; -import navigationRef from '@libs/Navigation/navigationRef'; - -export default function useNavigationReset(navigation: NavigationHelpers, isSmallScreenWidth: boolean) { - useEffect(() => { - if (!navigationRef.isReady()) { - return; - } - // We need to separately reset state of this navigator to trigger getRehydratedState. - navigation.reset(navigation.getState()); - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, [isSmallScreenWidth]); -} diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 92b739ff8879..ed13a2076537 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -26,12 +26,12 @@ import originalGetTopmostReportActionId from './getTopmostReportActionID'; import originalGetTopmostReportId from './getTopmostReportId'; import isReportOpenInRHP from './isReportOpenInRHP'; import linkingConfig from './linkingConfig'; +import createSplitNavigator from './linkingConfig/createSplitNavigator'; import linkTo from './linkTo'; import getMinimalAction from './linkTo/getMinimalAction'; import navigationRef from './navigationRef'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, SplitNavigatorLHNScreen, SplitNavigatorParamListType, State, StateOrRoute} from './types'; -import createSplitNavigator from './linkingConfig/createSplitNavigator'; const SPLIT_NAVIGATOR_TO_SIDEBAR_MAP: Record = { [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: SCREENS.HOME, diff --git a/src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts b/src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts deleted file mode 100644 index e61622f808bc..000000000000 --- a/src/libs/Navigation/linkingConfig/SEARCH_RHP_SCREENS.ts +++ /dev/null @@ -1,24 +0,0 @@ -import SCREENS from '@src/SCREENS'; - -const SEARCH_RHP_SCREENS: string[] = [ - SCREENS.SEARCH.REPORT_RHP, - SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_CURRENCY_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_DATE_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_DESCRIPTION_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_MERCHANT_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_REPORT_ID_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_AMOUNT_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_CATEGORY_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_KEYWORD_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_TAX_RATE_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_EXPENSE_TYPE_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_TAG_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_FROM_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_TO_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_IN_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_CARD_RHP, -]; - -export default SEARCH_RHP_SCREENS; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 07352a7b6d85..07dc2863c3ca 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -21,9 +21,6 @@ type GetAdaptedStateReturnType = { type GetAdaptedStateFromPath = (...args: [...Parameters, shouldReplacePathInNestedState?: boolean]) => GetAdaptedStateReturnType; -type SplitNavigatorLHNScreen = keyof typeof mapLhnToSplitNavigatorName; -type SplitNavigator = (typeof mapLhnToSplitNavigatorName)[SplitNavigatorLHNScreen]; - // The function getPathFromState that we are using in some places isn't working correctly without defined index. const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState => ({routes, index: routes.length - 1}); diff --git a/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts b/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts deleted file mode 100644 index 85580d068ad7..000000000000 --- a/src/libs/Navigation/newLinkTo/getActionForBottomTabNavigator.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type {NavigationAction, NavigationState} from '@react-navigation/native'; -import type {Writable} from 'type-fest'; -import type {RootStackParamList, StackNavigationAction} from '@libs/Navigation/types'; -import getTopmostBottomTabRoute from '@navigation/getTopmostBottomTabRoute'; -import CONST from '@src/CONST'; -import type {ActionPayloadParams} from './types'; - -// Because we need to change the type to push, we also need to set target for this action to the bottom tab navigator. -function getActionForBottomTabNavigator( - action: StackNavigationAction, - state: NavigationState, - policyID?: string, - shouldNavigate?: boolean, -): Writable | undefined { - const bottomTabNavigatorRoute = state.routes.at(0); - if (!bottomTabNavigatorRoute || bottomTabNavigatorRoute.state === undefined || !action || action.type !== CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { - return; - } - - const params = action.payload.params as ActionPayloadParams; - let payloadParams = params.params as Record; - const screen = params.screen; - - if (policyID && !payloadParams?.policyID) { - payloadParams = {...payloadParams, policyID}; - } else if (!policyID) { - delete payloadParams?.policyID; - } - - // Check if the current bottom tab is the same as the one we want to navigate to. If it is, we don't need to do anything. - const bottomTabCurrentTab = getTopmostBottomTabRoute(state); - const bottomTabParams = bottomTabCurrentTab?.params as Record; - - // Verify if the policyID is different than the one we are currently on. If it is, we need to navigate to the new policyID. - const isNewPolicy = bottomTabParams?.policyID !== payloadParams?.policyID; - if (bottomTabCurrentTab?.name === screen && !shouldNavigate && !isNewPolicy) { - return; - } - - return { - type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - payload: { - name: screen, - params: payloadParams, - }, - target: bottomTabNavigatorRoute.state.key, - }; -} - -export default getActionForBottomTabNavigator; diff --git a/src/libs/Navigation/newLinkTo/index.ts b/src/libs/Navigation/newLinkTo/index.ts deleted file mode 100644 index 40d51cd6ec9f..000000000000 --- a/src/libs/Navigation/newLinkTo/index.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {getActionFromState} from '@react-navigation/core'; -import type {NavigationContainerRef, NavigationState, PartialState} from '@react-navigation/native'; -import {findFocusedRoute} from '@react-navigation/native'; -import {shallowCompare} from '@libs/ObjectUtils'; -import {getPathWithoutPolicyID} from '@libs/PolicyUtils'; -import getStateFromPath from '@navigation/getStateFromPath'; -import linkingConfig from '@navigation/linkingConfig'; -import type {RootStackParamList, StackNavigationAction} from '@navigation/types'; -import CONST from '@src/CONST'; -import type {Route} from '@src/ROUTES'; -import getMinimalAction from './getMinimalAction'; - -function shouldDispatchAction(currentState: NavigationState, stateFromPath: PartialState>) { - const currentFocusedRoute = findFocusedRoute(currentState); - const targetFocusedRoute = findFocusedRoute(stateFromPath); - - const areNamesEqual = currentFocusedRoute?.name === targetFocusedRoute?.name; - const areParamsEqual = shallowCompare(currentFocusedRoute?.params as Record | undefined, targetFocusedRoute?.params as Record | undefined); - - if (areNamesEqual && areParamsEqual) { - return false; - } - - return true; -} - -export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: typeof CONST.NAVIGATION.ACTION_TYPE.REPLACE) { - if (!navigation) { - throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); - } - - const pathWithoutPolicyID = getPathWithoutPolicyID(`/${path}`) as Route; - - // This is the state generated with the default getStateFromPath function. - // It won't include the whole state that will be generated for this path but the focused route will be correct. - // It is necessary because getActionFromState will generate RESET action for whole state generated with our custom getStateFromPath function. - const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; - const currentState = navigation.getRootState() as NavigationState; - const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); - - // We don't want to dispatch action to push/replace with exactly the same route that is already focused. - if (!shouldDispatchAction(currentState, stateFromPath)) { - return; - } - - // If there is no action, just reset the whole state. - if (!action) { - navigation.resetRoot(stateFromPath); - return; - } - - if (type === CONST.NAVIGATION.ACTION_TYPE.REPLACE) { - action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; - } else if (action.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { - // We want to PUSH by default to add entries to the browser history. - action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; - } - - const {action: minimalAction} = getMinimalAction(action, navigation.getRootState()); - navigation.dispatch(minimalAction); -} diff --git a/src/libs/Navigation/newLinkTo/types.ts b/src/libs/Navigation/newLinkTo/types.ts deleted file mode 100644 index 254a4cdef2a5..000000000000 --- a/src/libs/Navigation/newLinkTo/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -type ActionPayloadParams = { - screen?: string; - params?: unknown; - path?: string; -}; - -type ActionPayload = { - params?: ActionPayloadParams; -}; - -export type {ActionPayload, ActionPayloadParams}; diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index ba9ca736a2f6..6e2e2526e8de 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -60,8 +60,6 @@ type SplitNavigatorParamListType = { [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: WorkspaceSplitNavigatorParamList; }; -type SplitNavigatorName = keyof SplitNavigatorParamListType; - type SplitNavigatorByLHN = (typeof LHN_TO_SPLIT_NAVIGATOR_NAME)[T]; type CentralPaneScreensParamList = { @@ -1652,5 +1650,4 @@ export type { SplitNavigatorLHNScreen, SplitNavigatorParamListType, SplitNavigatorByLHN, - SplitNavigatorName, }; diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 4a014fdcfb25..32ca20741d07 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -413,7 +413,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr scrollEventThrottle={16} contentContainerStyle={[styles.w100]} showsVerticalScrollIndicator={false} - > + > {accountMenuItems} {workspaceMenuItems} {generalMenuItems} From ece8857d4a5cbc22d7f318665daefc5c37114477 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 8 Oct 2024 12:51:31 +0200 Subject: [PATCH 080/257] Remove mappings from linkingConfig --- .../LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts | 10 - .../WORKSPACE_SCREEN_TO_RHP_MAPPING.ts | 218 ------------------ 2 files changed, 228 deletions(-) delete mode 100644 src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts delete mode 100755 src/libs/Navigation/linkingConfig/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts diff --git a/src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts b/src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts deleted file mode 100644 index 963f8e1a1712..000000000000 --- a/src/libs/Navigation/linkingConfig/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts +++ /dev/null @@ -1,10 +0,0 @@ -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; - -const LHN_TO_SPLIT_NAVIGATOR_NAME = { - [SCREENS.SETTINGS.ROOT]: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, - [SCREENS.HOME]: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, - [SCREENS.WORKSPACE.INITIAL]: NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, -}; - -export default LHN_TO_SPLIT_NAVIGATOR_NAME; diff --git a/src/libs/Navigation/linkingConfig/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts deleted file mode 100755 index 30e7d8d81e08..000000000000 --- a/src/libs/Navigation/linkingConfig/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts +++ /dev/null @@ -1,218 +0,0 @@ -import type {WorkspaceScreenName} from '@libs/Navigation/types'; -import SCREENS from '@src/SCREENS'; - -const WORKSPACE_SCREEN_TO_RHP_MAPPING: Partial> = { - [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.ADDRESS, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE], - [SCREENS.WORKSPACE.MEMBERS]: [ - SCREENS.WORKSPACE.INVITE, - SCREENS.WORKSPACE.INVITE_MESSAGE, - SCREENS.WORKSPACE.MEMBER_DETAILS, - SCREENS.WORKSPACE.MEMBER_NEW_CARD, - SCREENS.WORKSPACE.OWNER_CHANGE_CHECK, - SCREENS.WORKSPACE.OWNER_CHANGE_SUCCESS, - SCREENS.WORKSPACE.OWNER_CHANGE_ERROR, - SCREENS.WORKSPACE.OWNER_CHANGE_ERROR, - SCREENS.WORKSPACE.MEMBERS_IMPORT, - SCREENS.WORKSPACE.MEMBERS_IMPORTED, - ], - [SCREENS.WORKSPACE.WORKFLOWS]: [ - SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_NEW, - SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EDIT, - SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EXPENSES_FROM, - SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_APPROVER, - SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY, - SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET, - SCREENS.WORKSPACE.WORKFLOWS_PAYER, - ], - [SCREENS.WORKSPACE.ACCOUNTING.ROOT]: [ - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_IMPORT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CLASSES, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_TAXES, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_LOCATIONS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CUSTOMERS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_INVOICE_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_COMPANY_CARD_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_NON_REIMBURSABLE_DEFAULT_VENDOR_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ADVANCED, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_EXPORT, - SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT, - SCREENS.WORKSPACE.ACCOUNTING.XERO_CHART_OF_ACCOUNTS, - SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION, - SCREENS.WORKSPACE.ACCOUNTING.XERO_CUSTOMER, - SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES, - SCREENS.WORKSPACE.ACCOUNTING.XERO_TRACKING_CATEGORIES, - SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_TRACKING_CATEGORY, - SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT, - SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_PURCHASE_BILL_DATE_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED, - SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_STATUS_SELECTOR, - SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR, - SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_PREFERRED_EXPORTER_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR, - SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_BANK_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_SUBSIDIARY_SELECTOR, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_REUSE_EXISTING_CONNECTIONS, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_TOKEN_INPUT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_MAPPING, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_VIEW, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_EDIT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_LIST_ADD, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_SEGMENT_ADD, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_PREFERRED_EXPORTER_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_DATE_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_DESTINATION_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_VENDOR_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_PAYABLE_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_JOURNAL_POSTING_PREFERENCE_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_RECEIVABLE_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_INVOICE_ITEM_PREFERENCE_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_INVOICE_ITEM_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_TAX_POSTING_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_PROVINCIAL_TAX_POSTING_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_ADVANCED, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_REIMBURSEMENT_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_COLLECTION_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPENSE_REPORT_APPROVAL_LEVEL_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_VENDOR_BILL_APPROVAL_LEVEL_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_JOURNAL_ENTRY_APPROVAL_LEVEL_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_APPROVAL_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_CUSTOM_FORM_ID, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PREREQUISITES, - SCREENS.WORKSPACE.ACCOUNTING.ENTER_SAGE_INTACCT_CREDENTIALS, - SCREENS.WORKSPACE.ACCOUNTING.EXISTING_SAGE_INTACCT_CONNECTIONS, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ENTITY, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_IMPORT, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_MAPPING_TYPE, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_TOGGLE_MAPPING, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_USER_DIMENSIONS, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ADD_USER_DIMENSION, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EDIT_USER_DIMENSION, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EXPORT, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PREFERRED_EXPORTER, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EXPORT_DATE, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_REIMBURSABLE_EXPENSES, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_EXPENSES, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_REIMBURSABLE_DESTINATION, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_DESTINATION, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_DEFAULT_VENDOR, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_CREDIT_CARD_ACCOUNT, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ADVANCED, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PAYMENT_ACCOUNT, - SCREENS.WORKSPACE.ACCOUNTING.CARD_RECONCILIATION, - SCREENS.WORKSPACE.ACCOUNTING.RECONCILIATION_ACCOUNT_SETTINGS, - ], - [SCREENS.WORKSPACE.TAXES]: [ - SCREENS.WORKSPACE.TAXES_SETTINGS, - SCREENS.WORKSPACE.TAX_CREATE, - SCREENS.WORKSPACE.TAXES_SETTINGS_CUSTOM_TAX_NAME, - SCREENS.WORKSPACE.TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT, - SCREENS.WORKSPACE.TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT, - SCREENS.WORKSPACE.TAX_CREATE, - SCREENS.WORKSPACE.TAX_EDIT, - SCREENS.WORKSPACE.TAX_NAME, - SCREENS.WORKSPACE.TAX_VALUE, - SCREENS.WORKSPACE.TAX_CODE, - ], - [SCREENS.WORKSPACE.TAGS]: [ - SCREENS.WORKSPACE.TAGS_SETTINGS, - SCREENS.WORKSPACE.TAGS_EDIT, - SCREENS.WORKSPACE.TAG_CREATE, - SCREENS.WORKSPACE.TAG_SETTINGS, - SCREENS.WORKSPACE.TAG_EDIT, - SCREENS.WORKSPACE.TAG_LIST_VIEW, - SCREENS.WORKSPACE.TAG_GL_CODE, - SCREENS.WORKSPACE.TAG_APPROVER, - SCREENS.WORKSPACE.TAGS_IMPORT, - SCREENS.WORKSPACE.TAGS_IMPORTED, - ], - [SCREENS.WORKSPACE.CATEGORIES]: [ - SCREENS.WORKSPACE.CATEGORY_CREATE, - SCREENS.WORKSPACE.CATEGORY_SETTINGS, - SCREENS.WORKSPACE.CATEGORIES_IMPORT, - SCREENS.WORKSPACE.CATEGORIES_IMPORTED, - SCREENS.WORKSPACE.CATEGORIES_SETTINGS, - SCREENS.WORKSPACE.CATEGORY_EDIT, - SCREENS.WORKSPACE.CATEGORY_GL_CODE, - SCREENS.WORKSPACE.CATEGORY_PAYROLL_CODE, - SCREENS.WORKSPACE.CATEGORY_DEFAULT_TAX_RATE, - SCREENS.WORKSPACE.CATEGORY_FLAG_AMOUNTS_OVER, - SCREENS.WORKSPACE.CATEGORY_DESCRIPTION_HINT, - SCREENS.WORKSPACE.CATEGORY_APPROVER, - SCREENS.WORKSPACE.CATEGORY_REQUIRE_RECEIPTS_OVER, - ], - [SCREENS.WORKSPACE.DISTANCE_RATES]: [ - SCREENS.WORKSPACE.CREATE_DISTANCE_RATE, - SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS, - SCREENS.WORKSPACE.DISTANCE_RATE_EDIT, - SCREENS.WORKSPACE.DISTANCE_RATE_TAX_RECLAIMABLE_ON_EDIT, - SCREENS.WORKSPACE.DISTANCE_RATE_TAX_RATE_EDIT, - SCREENS.WORKSPACE.DISTANCE_RATE_DETAILS, - ], - [SCREENS.WORKSPACE.REPORT_FIELDS]: [ - SCREENS.WORKSPACE.REPORT_FIELDS_CREATE, - SCREENS.WORKSPACE.REPORT_FIELDS_SETTINGS, - SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES, - SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE, - SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS, - SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE, - SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE, - ], - [SCREENS.WORKSPACE.INVOICES]: [SCREENS.WORKSPACE.INVOICES_COMPANY_NAME, SCREENS.WORKSPACE.INVOICES_COMPANY_WEBSITE], - [SCREENS.WORKSPACE.COMPANY_CARDS]: [ - SCREENS.WORKSPACE.COMPANY_CARDS_SELECT_FEED, - SCREENS.WORKSPACE.COMPANY_CARDS_ADD_NEW, - SCREENS.WORKSPACE.COMPANY_CARDS_TYPE, - SCREENS.WORKSPACE.COMPANY_CARDS_INSTRUCTIONS, - SCREENS.WORKSPACE.COMPANY_CARDS_NAME, - SCREENS.WORKSPACE.COMPANY_CARDS_DETAILS, - SCREENS.WORKSPACE.COMPANY_CARDS_SELECT_FEED, - SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS, - SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS_FEED_NAME, - SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS, - SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS_FEED_NAME, - SCREENS.WORKSPACE.COMPANY_CARDS_ASSIGN_CARD, - SCREENS.WORKSPACE.COMPANY_CARD_DETAILS, - SCREENS.WORKSPACE.COMPANY_CARD_NAME, - SCREENS.WORKSPACE.COMPANY_CARD_EXPORT, - ], - [SCREENS.WORKSPACE.EXPENSIFY_CARD]: [ - SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW, - SCREENS.WORKSPACE.EXPENSIFY_CARD_BANK_ACCOUNT, - SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS, - SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_ACCOUNT, - SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_FREQUENCY, - SCREENS.WORKSPACE.EXPENSIFY_CARD_DETAILS, - SCREENS.WORKSPACE.EXPENSIFY_CARD_NAME, - SCREENS.WORKSPACE.EXPENSIFY_CARD_LIMIT, - SCREENS.WORKSPACE.EXPENSIFY_CARD_LIMIT_TYPE, - ], - [SCREENS.WORKSPACE.RULES]: [ - SCREENS.WORKSPACE.RULES_CUSTOM_NAME, - SCREENS.WORKSPACE.RULES_AUTO_APPROVE_REPORTS_UNDER, - SCREENS.WORKSPACE.RULES_RANDOM_REPORT_AUDIT, - SCREENS.WORKSPACE.RULES_AUTO_PAY_REPORTS_UNDER, - SCREENS.WORKSPACE.RULES_RECEIPT_REQUIRED_AMOUNT, - SCREENS.WORKSPACE.RULES_MAX_EXPENSE_AMOUNT, - SCREENS.WORKSPACE.RULES_MAX_EXPENSE_AGE, - SCREENS.WORKSPACE.RULES_BILLABLE_DEFAULT, - ], -}; - -export default WORKSPACE_SCREEN_TO_RHP_MAPPING; From 741c10d83c5e02b48fffee5d3b69417982a99d77 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 8 Oct 2024 15:09:32 +0200 Subject: [PATCH 081/257] fix mapping and SplitStackRouter --- .../createSplitStackNavigator/SplitStackRouter.ts | 15 ++++++++++----- .../linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts | 6 ++---- .../linkingConfig/getAdaptedStateFromPath.ts | 13 ++----------- .../linkingConfig/getParamsFromRoute.ts | 12 ++++++++++++ 4 files changed, 26 insertions(+), 20 deletions(-) create mode 100644 src/libs/Navigation/linkingConfig/getParamsFromRoute.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts index bbe741fe25cd..2dbff910c956 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts @@ -1,6 +1,8 @@ import type {CommonActions, ParamListBase, PartialState, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; import {StackActions, StackRouter} from '@react-navigation/native'; +import pick from 'lodash/pick'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; +import getParamsFromRoute from '@libs/Navigation/linkingConfig/getParamsFromRoute'; import navigationRef from '@libs/Navigation/navigationRef'; import type {SplitStackNavigatorRouterOptions} from './types'; @@ -16,11 +18,14 @@ type AdaptStateIfNecessaryArgs = { function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralScreen, parentRoute}}: AdaptStateIfNecessaryArgs) { const isNarrowLayout = getIsNarrowLayout(); - // @TODO leftover from times when there was fullscreen navigator only for the workspaces. - const workspaceCentralPane = state.routes.at(-1); + const lastRoute = state.routes.at(-1); - // There should always be sidebarScreen screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings. + // If the screen is wide, there should be at least two screens inside: + // - sidebarScreen to cover left pane. + // - defaultCentralScreen to cover central pane. if (!isAtLeastOneInState(state, sidebarScreen) && !isNarrowLayout) { + const paramsFromRoute = getParamsFromRoute(sidebarScreen); + // @ts-expect-error Updating read only property // noinspection JSConstantReassignment state.stale = true; // eslint-disable-line @@ -30,8 +35,8 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc // Unshift the root screen to fill left pane. state.routes.unshift({ name: sidebarScreen, - // @TODO why we need to pass params here? - params: workspaceCentralPane?.params, + // This handles the case where the sidebar should have params included in the central screen e.g. policyID for workspace initial. + params: pick(lastRoute?.params, paramsFromRoute), }); } } diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts index ba006376940e..f6878c687f7d 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts @@ -1,16 +1,14 @@ import SCREENS from '@src/SCREENS'; const SIDEBAR_TO_RHP: Record = { - // @TODO are those really all to home? - [SCREENS.HOME]: [ + [SCREENS.HOME]: [SCREENS.MONEY_REQUEST.CREATE], + [SCREENS.SETTINGS.ROOT]: [ SCREENS.SETTINGS.SHARE_CODE, SCREENS.SETTINGS.PROFILE.STATUS, SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, - SCREENS.MONEY_REQUEST.CREATE, SCREENS.SETTINGS.EXIT_SURVEY.REASON, SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE, SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM, - SCREENS.HOME, ], }; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 07dc2863c3ca..2685cc5fa1b3 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -8,10 +8,10 @@ import * as ReportConnection from '@libs/ReportConnection'; import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Screen} from '@src/SCREENS'; import SCREENS from '@src/SCREENS'; -import config, {normalizedConfigs} from './config'; +import config from './config'; import createSplitNavigator from './createSplitNavigator'; +import getParamsFromRoute from './getParamsFromRoute'; import RELATIONS from './RELATIONS'; import replacePathInNestedState from './replacePathInNestedState'; @@ -24,14 +24,6 @@ type GetAdaptedStateFromPath = (...args: [...Parameters // The function getPathFromState that we are using in some places isn't working correctly without defined index. const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState => ({routes, index: routes.length - 1}); -function getParamsFromRoute(screenName: string): string[] { - const routeConfig = normalizedConfigs[screenName as Screen]; - - const route = routeConfig.pattern; - - return route.match(/(?<=[:?&])(\w+)(?=[/=?&]|$)/g) ?? []; -} - function isRouteWithBackToParam(route: NavigationPartialRoute): route is Route { return route.params !== undefined && 'backTo' in route.params && typeof route.params.backTo === 'string'; } @@ -118,7 +110,6 @@ function getMatchingFullScreenRouteForState(state: PartialState Date: Tue, 8 Oct 2024 15:09:53 +0200 Subject: [PATCH 082/257] remove dismissModalWithReport --- src/libs/Navigation/dismissModalWithReport.ts | 81 ------------------- 1 file changed, 81 deletions(-) delete mode 100644 src/libs/Navigation/dismissModalWithReport.ts diff --git a/src/libs/Navigation/dismissModalWithReport.ts b/src/libs/Navigation/dismissModalWithReport.ts deleted file mode 100644 index 9d0cb05251fc..000000000000 --- a/src/libs/Navigation/dismissModalWithReport.ts +++ /dev/null @@ -1,81 +0,0 @@ -import {getActionFromState} from '@react-navigation/core'; -import type {NavigationContainerRef} from '@react-navigation/native'; -import {StackActions} from '@react-navigation/native'; -import findLastIndex from 'lodash/findLastIndex'; -import type {OnyxEntry} from 'react-native-onyx'; -import Log from '@libs/Log'; -import {isCentralPaneName} from '@libs/NavigationUtils'; -import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils'; -import {doesReportBelongToWorkspace} from '@libs/ReportUtils'; -import NAVIGATORS from '@src/NAVIGATORS'; -import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; -import type {Report} from '@src/types/onyx'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import getPolicyIDFromState from './getPolicyIDFromState'; -import getStateFromPath from './getStateFromPath'; -import getTopmostReportId from './getTopmostReportId'; -import linkingConfig from './linkingConfig'; -import type {RootStackParamList, StackNavigationAction, State} from './types'; - -// This function is in a separate file than Navigation.ts to avoid cyclic dependency. - -/** - * Dismisses the last modal stack if there is any - * - * @param targetReportID - The reportID to navigate to after dismissing the modal - */ -function dismissModalWithReport(targetReport: OnyxEntry, navigationRef: NavigationContainerRef) { - if (!navigationRef.isReady()) { - return; - } - - const state = navigationRef.getState(); - const lastRoute = state.routes.at(-1); - switch (lastRoute?.name) { - case NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR: - case NAVIGATORS.LEFT_MODAL_NAVIGATOR: - case NAVIGATORS.RIGHT_MODAL_NAVIGATOR: - case SCREENS.NOT_FOUND: - case SCREENS.ATTACHMENTS: - case SCREENS.TRANSACTION_RECEIPT: - case SCREENS.PROFILE_AVATAR: - case SCREENS.WORKSPACE_AVATAR: - case SCREENS.REPORT_AVATAR: - case SCREENS.CONCIERGE: - // If we are not in the target report, we need to navigate to it after dismissing the modal - if (targetReport?.reportID !== getTopmostReportId(state)) { - const reportState = getStateFromPath(ROUTES.REPORT_WITH_ID.getRoute(targetReport?.reportID ?? '-1')); - const policyID = getPolicyIDFromState(state as State); - const policyMemberAccountIDs = getPolicyEmployeeAccountIDs(policyID); - const shouldOpenAllWorkspace = isEmptyObject(targetReport) ? true : !doesReportBelongToWorkspace(targetReport, policyMemberAccountIDs, policyID); - - // @TODO Handle dismissing modal with switching a policyID - - // if (shouldOpenAllWorkspace) { - // switchPolicyID(navigationRef, {route: ROUTES.HOME}); - // } else { - // switchPolicyID(navigationRef, {policyID, route: ROUTES.HOME}); - // } - - const action: StackNavigationAction = getActionFromState(reportState, linkingConfig.config); - if (action) { - action.type = 'REPLACE'; - navigationRef.dispatch(action); - } - // If not-found page is in the route stack, we need to close it - } else if (state.routes.some((route) => route.name === SCREENS.NOT_FOUND)) { - const lastRouteIndex = state.routes.length - 1; - const centralRouteIndex = findLastIndex(state.routes, (route) => isCentralPaneName(route.name)); - navigationRef.dispatch({...StackActions.pop(lastRouteIndex - centralRouteIndex), target: state.key}); - } else { - navigationRef.dispatch({...StackActions.pop(), target: state.key}); - } - break; - default: { - Log.hmmm('[Navigation] dismissModalWithReport failed because there is no modal stack to dismiss'); - } - } -} - -export default dismissModalWithReport; From 47c8e0b7882ca1f7c53e83cfa89c30d122a92296 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 8 Oct 2024 15:10:49 +0200 Subject: [PATCH 083/257] resolve some todos --- .../Navigation/AppNavigator/AuthScreens.tsx | 19 +------------------ .../createCustomBottomTabNavigator/TopBar.tsx | 1 - .../CustomRouter.ts | 4 +++- src/libs/Navigation/Navigation.ts | 3 +++ 4 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 9eba945176a5..fa202e31da75 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -89,24 +89,7 @@ function shouldOpenOnAdminRoom() { return url ? new URL(url).searchParams.get('openOnAdminRoom') === 'true' : false; } -// @TODO: Add these params to SearchPage and ReportScreen -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function getCentralPaneScreenInitialParams(screenName: CentralPaneName, initialReportID?: string): Partial> { - if (screenName === SCREENS.SEARCH.CENTRAL_PANE) { - // Generate default query string with buildSearchQueryString without argument. - return {q: buildSearchQueryString()}; - } - - if (screenName === SCREENS.REPORT) { - return { - openOnAdminRoom: shouldOpenOnAdminRoom() ? true : undefined, - reportID: initialReportID, - }; - } - - return undefined; -} - +// @TODO Adapt to the new structure. function getCentralPaneScreenListeners(screenName: CentralPaneName) { if (screenName === SCREENS.REPORT) { return {beforeRemove: beforeRemoveReportOpenedFromSearchRHP}; diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx index 0ce95aab0265..c7831a682dbe 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx @@ -30,7 +30,6 @@ function TopBar({breadcrumbLabel, activeWorkspaceID, shouldDisplaySearch = true, const theme = useTheme(); const {translate} = useLocalize(); - // @TODO use policyID from state instead of activeWorkspaceID. It will help with glitching. const policy = usePolicy(activeWorkspaceID); const [session] = useOnyx(ONYXKEYS.SESSION, {selector: (sessionValue) => sessionValue && {authTokenType: sessionValue.authTokenType}}); const isAnonymousUser = Session.isAnonymousUser(session); diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 829d173659a3..6f68b7a8e373 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -41,6 +41,7 @@ function shouldPreventReset(state: StackNavigationState, action: // We want to prevent the user from navigating back to a non-onboarding screen if they are currently on an onboarding screen if (isOnboardingFlowName(currentFocusedRoute?.name) && !isOnboardingFlowName(targetFocusedRoute?.name)) { Welcome.setOnboardingErrorMessage(Localize.translateLocal('onboarding.purpose.errorBackButton')); + // We reset the URL as the browser sets it in a way that doesn't match the navigation state // @TODO is it working? Maybe we should split it for platforms. // eslint-disable-next-line no-restricted-globals @@ -78,7 +79,7 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { const stackRouter = StackRouter(options); const {setActiveWorkspaceID} = useActiveWorkspace(); - // @TODO: Make sure that everything works fine without compareAndAdaptState function + // @TODO: Make sure that everything works fine without compareAndAdaptState function. Probably with getMatchingFullScreenRoute. return { ...stackRouter, getStateForAction(state: StackNavigationState, action: CommonActions.Action | StackActionType | CustomRootStackActionType, configOptions: RouterConfigOptions) { @@ -111,6 +112,7 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { setActiveWorkspaceID(action.payload.policyID); return stackRouter.getStateForAction(state, newAction, configOptions); } + // We don't have other navigators that should handle switch policy action. return null; } diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index ed13a2076537..4f2a40c5ecb5 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -226,6 +226,7 @@ function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | Navi } // @TODO: Fix params comparison. When comparing split navigators params, it may happen that first one has parameters with the initial settings and the second one does not. + // We can filter out params that shouldn't be compared. For example params that react-navigation uses for the initial state. return shallowCompare(route.params as Record, minimalAction.payload.params as Record); } @@ -474,6 +475,8 @@ function navigateToReportWithPolicyCheck({report, reportID, reportActionID, refe ); } +// @TODO In places where we use dismissModal with report arg we should do dismiss modal and then navigate to the report. +// We left it here to limit the number of changed files. const dismissModal = (reportID?: string, ref = navigationRef) => { ref.dispatch({type: 'DISMISS_MODAL'}); if (!reportID) { From 4b1cedd9e3b0c491e12446ea5a9ae78d9ec2506f Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 8 Oct 2024 15:37:04 +0200 Subject: [PATCH 084/257] bring back stateToRender --- .../createSplitStackNavigator/index.tsx | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index d90b60d2ac4d..bcec6474ea50 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -2,7 +2,7 @@ import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@rea import {createNavigatorFactory, useNavigationBuilder, useRoute} from '@react-navigation/native'; import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; import {StackView} from '@react-navigation/stack'; -import React from 'react'; +import React, {useMemo} from 'react'; import {View} from 'react-native'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -14,6 +14,21 @@ import type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions} from '. import useHandleScreenResize from './useHandleScreenResize'; import usePrepareSplitStackNavigatorChildren from './usePrepareSplitStackNavigatorChildren'; +function getStateToRender(state: StackNavigationState, isSmallScreenWidth: boolean): StackNavigationState { + const sidebarScreenRoute = state.routes.at(0); + const centralScreenRoutes = state.routes.slice(1); + const routes = isSmallScreenWidth ? state.routes.slice(-2) : [sidebarScreenRoute, ...centralScreenRoutes.slice(-2)]; + + // Routes passed to the state have to be defined + const definedRoutes = routes.filter((route) => route !== undefined); + + return { + ...state, + routes: definedRoutes, + index: routes.length - 1, + }; +} + function SplitStackNavigator(props: SplitStackNavigatorProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -43,6 +58,8 @@ function SplitStackNavigator(props: SplitStackN useHandleScreenResize(navigation); + const stateToRender = useMemo(() => getStateToRender(state, shouldUseNarrowLayout), [state, shouldUseNarrowLayout]); + return ( @@ -50,7 +67,7 @@ function SplitStackNavigator(props: SplitStackN From 8b7e4a0a87aaeebf3111d7c567d10a05afc9e731 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 8 Oct 2024 15:48:51 +0200 Subject: [PATCH 085/257] Add PARAMS_TO_OMIT_WHEN_COMPARING_ROUTES --- src/libs/Navigation/Navigation.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 4f2a40c5ecb5..684480abd16f 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -1,6 +1,7 @@ import {getActionFromState} from '@react-navigation/core'; import type {EventArg, NavigationAction, NavigationContainerEventMap} from '@react-navigation/native'; import {CommonActions, getPathFromState, StackActions} from '@react-navigation/native'; +import lodashOmit from 'lodash/omit'; import type {OnyxEntry} from 'react-native-onyx'; import type {Writable} from 'type-fest'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; @@ -33,6 +34,8 @@ import navigationRef from './navigationRef'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, SplitNavigatorLHNScreen, SplitNavigatorParamListType, State, StateOrRoute} from './types'; +const PARAMS_TO_OMIT_WHEN_COMPARING_ROUTES = ['path', 'initial', 'params', 'state', 'screen', 'policyID'] as const; + const SPLIT_NAVIGATOR_TO_SIDEBAR_MAP: Record = { [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: SCREENS.HOME, [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: SCREENS.SETTINGS.ROOT, @@ -225,9 +228,10 @@ function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | Navi return false; } - // @TODO: Fix params comparison. When comparing split navigators params, it may happen that first one has parameters with the initial settings and the second one does not. - // We can filter out params that shouldn't be compared. For example params that react-navigation uses for the initial state. - return shallowCompare(route.params as Record, minimalAction.payload.params as Record); + const routeParams = lodashOmit(route.params ?? {}, PARAMS_TO_OMIT_WHEN_COMPARING_ROUTES) as Record; + const minimalActionParams = lodashOmit(minimalAction.payload.params ?? {}, PARAMS_TO_OMIT_WHEN_COMPARING_ROUTES) as Record; + + return shallowCompare(routeParams, minimalActionParams); } function goUp(fallbackRoute: Route) { From 222e8adce9f1dc847c8545635db4070c3b552baf Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 9 Oct 2024 13:23:53 +0200 Subject: [PATCH 086/257] Remove unused files, fix lint and typescript errors --- .../Navigation/AppNavigator/AuthScreens.tsx | 13 +-- .../index.native.ts | 41 -------- .../index.ts | 4 - .../createCustomFullScreenNavigator/index.tsx | 50 ---------- .../AppNavigator/getActionsFromPartialDiff.ts | 38 -------- .../AppNavigator/getPartialStateDiff.ts | 89 ----------------- src/libs/Navigation/Navigation.ts | 97 ++++++++++--------- .../RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts | 1 - .../RELATIONS/WORKSPACE_TO_RHP.ts | 3 +- .../getMatchingBottomTabRouteForState.ts | 33 ------- .../getMatchingCentralPaneRouteForState.ts | 74 -------------- src/pages/home/sidebar/SidebarLinksData.tsx | 1 + src/pages/workspace/WorkspaceInitialPage.tsx | 1 - src/pages/workspace/WorkspaceMembersPage.tsx | 6 +- .../workspace/WorkspaceMoreFeaturesPage.tsx | 4 +- src/pages/workspace/WorkspaceProfilePage.tsx | 4 +- .../categories/WorkspaceCategoriesPage.tsx | 4 +- .../WorkspaceCompanyCardsPage.tsx | 4 +- .../distanceRates/PolicyDistanceRatesPage.tsx | 4 +- .../expensifyCard/WorkspaceCardsListLabel.tsx | 4 +- .../WorkspaceExpensifyCardListPage.tsx | 4 +- .../WorkspaceExpensifyCardPage.tsx | 4 +- .../WorkspaceExpensifyCardPageEmptyState.tsx | 4 +- .../invoices/WorkspaceInvoicesPage.tsx | 4 +- .../WorkspaceReportFieldsPage.tsx | 4 +- src/pages/workspace/rules/PolicyRulesPage.tsx | 4 +- .../workspace/tags/WorkspaceTagsPage.tsx | 4 +- .../workspace/taxes/WorkspaceTaxesPage.tsx | 4 +- src/pages/workspace/withPolicy.tsx | 10 +- .../WorkspaceAutoReportingFrequencyPage.tsx | 4 +- ...orkspaceAutoReportingMonthlyOffsetPage.tsx | 4 +- .../workflows/WorkspaceWorkflowsPage.tsx | 4 +- ...orkspaceWorkflowsApprovalsApproverPage.tsx | 4 +- .../WorkspaceWorkflowsApprovalsCreatePage.tsx | 4 +- .../WorkspaceWorkflowsApprovalsEditPage.tsx | 4 +- ...paceWorkflowsApprovalsExpensesFromPage.tsx | 4 +- 36 files changed, 106 insertions(+), 439 deletions(-) delete mode 100644 src/libs/Navigation/AppNavigator/beforeRemoveReportOpenedFromSearchRHP/index.native.ts delete mode 100644 src/libs/Navigation/AppNavigator/beforeRemoveReportOpenedFromSearchRHP/index.ts delete mode 100644 src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx delete mode 100644 src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts delete mode 100644 src/libs/Navigation/AppNavigator/getPartialStateDiff.ts delete mode 100644 src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts delete mode 100644 src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index fa202e31da75..9961eeff6955 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -2,7 +2,6 @@ import React, {memo, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import Onyx, {useOnyx} from 'react-native-onyx'; -import type {ValueOf} from 'type-fest'; import ActiveGuidesEventListener from '@components/ActiveGuidesEventListener'; import ActiveWorkspaceContextProvider from '@components/ActiveWorkspaceProvider'; import ComposeProviders from '@components/ComposeProviders'; @@ -25,7 +24,7 @@ import Log from '@libs/Log'; import getCurrentUrl from '@libs/Navigation/currentUrl'; import getOnboardingModalScreenOptions from '@libs/Navigation/getOnboardingModalScreenOptions'; import Navigation from '@libs/Navigation/Navigation'; -import type {AuthScreensParamList, CentralPaneName, CentralPaneScreensParamList} from '@libs/Navigation/types'; +import type {AuthScreensParamList} from '@libs/Navigation/types'; import NetworkConnection from '@libs/NetworkConnection'; import onyxSubscribe from '@libs/onyxSubscribe'; import * as Pusher from '@libs/Pusher/pusher'; @@ -56,7 +55,6 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; -import beforeRemoveReportOpenedFromSearchRHP from './beforeRemoveReportOpenedFromSearchRHP'; import createCustomStackNavigator from './createCustomStackNavigator'; import defaultScreenOptions from './defaultScreenOptions'; import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions'; @@ -89,15 +87,6 @@ function shouldOpenOnAdminRoom() { return url ? new URL(url).searchParams.get('openOnAdminRoom') === 'true' : false; } -// @TODO Adapt to the new structure. -function getCentralPaneScreenListeners(screenName: CentralPaneName) { - if (screenName === SCREENS.REPORT) { - return {beforeRemove: beforeRemoveReportOpenedFromSearchRHP}; - } - - return {}; -} - function initializePusher() { return Pusher.init({ appKey: CONFIG.PUSHER.APP_KEY, diff --git a/src/libs/Navigation/AppNavigator/beforeRemoveReportOpenedFromSearchRHP/index.native.ts b/src/libs/Navigation/AppNavigator/beforeRemoveReportOpenedFromSearchRHP/index.native.ts deleted file mode 100644 index fd31b6e6022f..000000000000 --- a/src/libs/Navigation/AppNavigator/beforeRemoveReportOpenedFromSearchRHP/index.native.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {StackActions} from '@react-navigation/native'; -import type {EventArg} from '@react-navigation/native'; -import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; -import Navigation from '@libs/Navigation/Navigation'; -import navigationRef from '@libs/Navigation/navigationRef'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; - -/** - * When we go back from the chat opened in the Chats section to the chat opened in the Search RHP we have to pop the Home screen from the Bottom tab navigator to display correctly Search page under RHP on native platform. - * It fixes this issue: https://github.com/Expensify/App/issues/48882 - */ -function beforeRemoveReportOpenedFromSearchRHP(event: EventArg<'beforeRemove', true>) { - if (!navigationRef.current) { - return; - } - - const state = navigationRef.current?.getRootState() as State; - - if (!state) { - return; - } - - const shouldPopHome = - state.routes?.length >= 3 && - state.routes.at(-1)?.name === SCREENS.REPORT && - state.routes.at(-2)?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR && - getTopmostBottomTabRoute(state)?.name === SCREENS.HOME; - - if (!shouldPopHome) { - return; - } - - event.preventDefault(); - const bottomTabState = state?.routes?.at(0)?.state; - navigationRef.dispatch({...StackActions.pop(), target: bottomTabState?.key}); - Navigation.goBack(); -} - -export default beforeRemoveReportOpenedFromSearchRHP; diff --git a/src/libs/Navigation/AppNavigator/beforeRemoveReportOpenedFromSearchRHP/index.ts b/src/libs/Navigation/AppNavigator/beforeRemoveReportOpenedFromSearchRHP/index.ts deleted file mode 100644 index b5d8f835ab43..000000000000 --- a/src/libs/Navigation/AppNavigator/beforeRemoveReportOpenedFromSearchRHP/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** The issue fixed by this handler is related to navigating back on native platforms. For more information, see the index.native.ts file in this folder */ -function beforeRemoveReportOpenedFromSearchRHP() {} - -export default beforeRemoveReportOpenedFromSearchRHP; diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx deleted file mode 100644 index ee8dd54c920d..000000000000 --- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native'; -import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; -import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; -import {StackView} from '@react-navigation/stack'; -import React, {useEffect} from 'react'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import navigationRef from '@libs/Navigation/navigationRef'; -import CustomFullScreenRouter from './CustomFullScreenRouter'; -import type {FullScreenNavigatorProps, FullScreenNavigatorRouterOptions} from './types'; - -function CustomFullScreenNavigator(props: FullScreenNavigatorProps) { - const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< - StackNavigationState, - FullScreenNavigatorRouterOptions, - StackActionHelpers, - StackNavigationOptions, - StackNavigationEventMap - >(CustomFullScreenRouter, { - children: props.children, - screenOptions: props.screenOptions, - initialRouteName: props.initialRouteName, - }); - - const {shouldUseNarrowLayout} = useResponsiveLayout(); - - useEffect(() => { - if (!navigationRef.isReady()) { - return; - } - // We need to separately reset state of this navigator to trigger getRehydratedState. - navigation.reset(navigation.getState()); - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, [shouldUseNarrowLayout]); - - return ( - - - - ); -} - -CustomFullScreenNavigator.displayName = 'CustomFullScreenNavigator'; - -export default createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, typeof CustomFullScreenNavigator>(CustomFullScreenNavigator); diff --git a/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts b/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts deleted file mode 100644 index 1cbb5ec3d718..000000000000 --- a/src/libs/Navigation/AppNavigator/getActionsFromPartialDiff.ts +++ /dev/null @@ -1,38 +0,0 @@ -import {getActionFromState, StackActions} from '@react-navigation/native'; -import type {NavigationAction} from '@react-navigation/native'; -import linkingConfig from '@libs/Navigation/linkingConfig'; -import NAVIGATORS from '@src/NAVIGATORS'; -import type {GetPartialStateDiffReturnType} from './getPartialStateDiff'; - -/** - * @param diff - Diff generated by getPartialDiff. - * @returns Array of actions to dispatch to apply diff. - */ -function getActionsFromPartialDiff(diff: GetPartialStateDiffReturnType): NavigationAction[] { - const actions: NavigationAction[] = []; - - const bottomTabDiff = diff[NAVIGATORS.BOTTOM_TAB_NAVIGATOR]; - const centralPaneDiff = diff[NAVIGATORS.CENTRAL_PANE_NAVIGATOR]; - const fullScreenDiff = diff[NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]; - - // There is only one bottom tab navigator so we can just push this route. - if (bottomTabDiff) { - actions.push(StackActions.push(bottomTabDiff.name, bottomTabDiff.params)); - } - - if (centralPaneDiff) { - // In this case we have to wrap the inner central pane route with central pane navigator. - actions.push(StackActions.push(centralPaneDiff.name, centralPaneDiff.params)); - } - - if (fullScreenDiff) { - const action = getActionFromState({routes: [fullScreenDiff]}, linkingConfig.config); - if (action) { - actions.push(action); - } - } - - return actions; -} - -export default getActionsFromPartialDiff; diff --git a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts b/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts deleted file mode 100644 index 79def4ee9218..000000000000 --- a/src/libs/Navigation/AppNavigator/getPartialStateDiff.ts +++ /dev/null @@ -1,89 +0,0 @@ -import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; -import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; -import getTopmostWorkspaceRoute from '@libs/Navigation/getTopmostWorkspaceRoute'; -import type {Metainfo} from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; -import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; -import shallowCompare from '@libs/ObjectUtils'; -import NAVIGATORS from '@src/NAVIGATORS'; - -type GetPartialStateDiffReturnType = { - [NAVIGATORS.BOTTOM_TAB_NAVIGATOR]?: NavigationPartialRoute; - [NAVIGATORS.CENTRAL_PANE_NAVIGATOR]?: NavigationPartialRoute; - [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]?: NavigationPartialRoute; -}; - -/** - * This function returns partial additive diff between the two states. - * - * Example: Let's start with state A on route /r/123. If the screen is wide we will have a HOME opened on bottom tab and REPORT on central pane. - * Now let's say we want to navigate to /workspace/345/profile. We will generate state B from this path. - * State B will have WORKSPACE_INITIAL on the bottom tab and WORKSPACE_PROFILE on the central pane. - * Now we will generate partial diff between state A and state B. The diff will tell us that we need to push WORKSPACE_INITIAL on the bottom tab and WORKSPACE_PROFILE on the central pane. - * - * Then we can generate actions from this diff and dispatch them to the linkTo function. - * - * It's named partial diff because we don't cover RHP and LHP navigators yet. In the future we can improve this function to handle all navigators to help us clean and simplify the linkTo function. - * - * The partial diff has information which bottom tab, central pane and full screen screens we need to push to go from state to templateState. - * @param state - Current state. - * @param templateState - Desired state generated with getAdaptedStateFromPath. - * @param metainfo - Additional info from getAdaptedStateFromPath function. - * @returns The screen options object - */ -function getPartialStateDiff(state: State, templateState: State, metainfo: Metainfo): GetPartialStateDiffReturnType { - const diff: GetPartialStateDiffReturnType = {}; - - // If it is mandatory we need to compare both central pane and bottom tab of states. - if (metainfo.isCentralPaneAndBottomTabMandatory) { - const stateTopmostBottomTab = getTopmostBottomTabRoute(state); - const templateStateTopmostBottomTab = getTopmostBottomTabRoute(templateState); - - // Bottom tab navigator - if (stateTopmostBottomTab && templateStateTopmostBottomTab && stateTopmostBottomTab.name !== templateStateTopmostBottomTab.name) { - diff[NAVIGATORS.BOTTOM_TAB_NAVIGATOR] = templateStateTopmostBottomTab; - } - - const stateTopmostCentralPane = getTopmostCentralPaneRoute(state); - const templateStateTopmostCentralPane = getTopmostCentralPaneRoute(templateState); - - if ( - // If the central pane is only in the template state, it's diff. - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - (!stateTopmostCentralPane && templateStateTopmostCentralPane) || - (stateTopmostCentralPane && - templateStateTopmostCentralPane && - stateTopmostCentralPane.name !== templateStateTopmostCentralPane.name && - !shallowCompare(stateTopmostCentralPane.params as Record | undefined, templateStateTopmostCentralPane.params as Record | undefined)) - ) { - // We need to wrap central pane routes in the central pane navigator. - diff[NAVIGATORS.CENTRAL_PANE_NAVIGATOR] = templateStateTopmostCentralPane; - } - } - - // This one is heuristic and may need to be improved if we will be able to navigate from modal screen with full screen in background to another modal screen with full screen in background. - // For now this simple check is enough. - if (metainfo.isWorkspaceNavigatorMandatory) { - const stateTopmostWorkspaceRoute = getTopmostWorkspaceRoute(state); - const templateStateTopmostWorkspaceRoute = getTopmostWorkspaceRoute(templateState); - const workspaceNavDiff = templateState.routes.filter((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR).at(-1) as NavigationPartialRoute; - - if ( - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - (!stateTopmostWorkspaceRoute && templateStateTopmostWorkspaceRoute) || - (stateTopmostWorkspaceRoute && - templateStateTopmostWorkspaceRoute && - (stateTopmostWorkspaceRoute.name !== templateStateTopmostWorkspaceRoute.name || - !shallowCompare( - stateTopmostWorkspaceRoute.params as Record | undefined, - templateStateTopmostWorkspaceRoute.params as Record | undefined, - ))) - ) { - diff[NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR] = workspaceNavDiff; - } - } - - return diff; -} - -export default getPartialStateDiff; -export type {GetPartialStateDiffReturnType}; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 684480abd16f..b741f0d55151 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -6,7 +6,6 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {Writable} from 'type-fest'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import Log from '@libs/Log'; -import {removePolicyIDParamFromState} from '@libs/NavigationUtils'; import {shallowCompare} from '@libs/ObjectUtils'; import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils'; import * as ReportConnection from '@libs/ReportConnection'; @@ -87,27 +86,28 @@ const closeRHPFlow = (ref = navigationRef) => originalCloseRHPFlow(ref); // This method is needed because it allows to dismiss the modal and then open the report. Within this method is checked whether the report belongs to a specific workspace. Sometimes the report we want to check, hasn't been added to the Onyx yet. // Then we can pass the report as a param without getting it from the Onyx. +// @TODO: Check if it's still needed /** Method for finding on which index in stack we are. */ -function getActiveRouteIndex(stateOrRoute: StateOrRoute, index?: number): number | undefined { - if ('routes' in stateOrRoute && stateOrRoute.routes) { - const childActiveRoute = stateOrRoute.routes[stateOrRoute.index ?? 0]; - return getActiveRouteIndex(childActiveRoute, stateOrRoute.index ?? 0); - } - - if ('state' in stateOrRoute && stateOrRoute.state?.routes) { - const childActiveRoute = stateOrRoute.state.routes[stateOrRoute.state.index ?? 0]; - return getActiveRouteIndex(childActiveRoute, stateOrRoute.state.index ?? 0); - } - - if ( - 'name' in stateOrRoute && - (stateOrRoute.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) - ) { - return 0; - } - - return index; -} +// function getActiveRouteIndex(stateOrRoute: StateOrRoute, index?: number): number | undefined { +// if ('routes' in stateOrRoute && stateOrRoute.routes) { +// const childActiveRoute = stateOrRoute.routes[stateOrRoute.index ?? 0]; +// return getActiveRouteIndex(childActiveRoute, stateOrRoute.index ?? 0); +// } + +// if ('state' in stateOrRoute && stateOrRoute.state?.routes) { +// const childActiveRoute = stateOrRoute.state.routes[stateOrRoute.state.index ?? 0]; +// return getActiveRouteIndex(childActiveRoute, stateOrRoute.state.index ?? 0); +// } + +// if ( +// 'name' in stateOrRoute && +// (stateOrRoute.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) +// ) { +// return 0; +// } + +// return index; +// } /** * Function that generates dynamic urls from paths passed from OldDot @@ -126,32 +126,33 @@ function parseHybridAppUrl(url: HybridAppRoute | Route): Route { } } -/** - * Gets distance from the path in root navigator. In other words how much screen you have to pop to get to the route with this path. - * The search is limited to 5 screens from the top for performance reasons. - * @param path - Path that you are looking for. - * @return - Returns distance to path or -1 if the path is not found in root navigator. - */ -function getDistanceFromPathInRootNavigator(state: State, path?: string): number { - let currentState = {...state}; - - for (let index = 0; index < 5; index++) { - if (!currentState.routes.length) { - break; - } - - // When comparing path and pathFromState, the policyID parameter isn't included in the comparison - const currentStateWithoutPolicyID = removePolicyIDParamFromState(currentState as State); - const pathFromState = getPathFromState(currentStateWithoutPolicyID, linkingConfig.config); - if (path === pathFromState.substring(1)) { - return index; - } - - currentState = {...currentState, routes: currentState.routes.slice(0, -1), index: currentState.index - 1}; - } - - return -1; -} +// @TODO: Check if it's still needed +// /** +// * Gets distance from the path in root navigator. In other words how much screen you have to pop to get to the route with this path. +// * The search is limited to 5 screens from the top for performance reasons. +// * @param path - Path that you are looking for. +// * @return - Returns distance to path or -1 if the path is not found in root navigator. +// */ +// function getDistanceFromPathInRootNavigator(state: State, path?: string): number { +// let currentState = {...state}; + +// for (let index = 0; index < 5; index++) { +// if (!currentState.routes.length) { +// break; +// } + +// // When comparing path and pathFromState, the policyID parameter isn't included in the comparison +// const currentStateWithoutPolicyID = removePolicyIDParamFromState(currentState as State); +// const pathFromState = getPathFromState(currentStateWithoutPolicyID, linkingConfig.config); +// if (path === pathFromState.substring(1)) { +// return index; +// } + +// currentState = {...currentState, routes: currentState.routes.slice(0, -1), index: currentState.index - 1}; +// } + +// return -1; +// } /** Returns the current active route */ function getActiveRoute(): string { @@ -206,7 +207,7 @@ function navigate(route: Route = ROUTES.HOME, type?: string) { return; } // linkTo(navigationRef.current, route, type, isActiveRoute(route)); - linkTo(navigationRef.current, route, type, isActiveRoute(route)); + linkTo(navigationRef.current, route, type); } function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | NavigationPartialRoute, minimalAction: Writable) { diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts index 56777ef98075..c5f624bb5587 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts @@ -16,7 +16,6 @@ const TAB_TO_CENTRAL_PANE_MAPPING: Record> = { +const WORKSPACE_TO_RHP: Record = { [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.ADDRESS, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE], [SCREENS.WORKSPACE.MEMBERS]: [ SCREENS.WORKSPACE.INVITE, diff --git a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts deleted file mode 100644 index 7dc6093d7942..000000000000 --- a/src/libs/Navigation/linkingConfig/getMatchingBottomTabRouteForState.ts +++ /dev/null @@ -1,33 +0,0 @@ -import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; -import type {BottomTabName, NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; -import {CENTRAL_PANE_TO_TAB_MAPPING} from './RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING'; - -// Get the route that matches the topmost central pane route in the navigation stack. e.g REPORT -> HOME -function getMatchingBottomTabRouteForState(state: State, policyID?: string): NavigationPartialRoute { - const paramsWithPolicyID = policyID ? {policyID} : undefined; - const defaultRoute = {name: SCREENS.HOME, params: paramsWithPolicyID}; - const isWorkspaceNavigatorOpened = state.routes.some((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR); - - if (isWorkspaceNavigatorOpened) { - return {name: SCREENS.SETTINGS.ROOT, params: paramsWithPolicyID}; - } - - const topmostCentralPaneRoute = getTopmostCentralPaneRoute(state); - - if (topmostCentralPaneRoute === undefined) { - return defaultRoute; - } - - const tabName = CENTRAL_PANE_TO_TAB_MAPPING[topmostCentralPaneRoute.name]; - - if (tabName === SCREENS.SEARCH.BOTTOM_TAB) { - const topmostCentralPaneRouteParams = {...topmostCentralPaneRoute.params} as Record; - return {name: tabName, params: topmostCentralPaneRouteParams}; - } - - return {name: tabName, params: paramsWithPolicyID}; -} - -export default getMatchingBottomTabRouteForState; diff --git a/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts b/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts deleted file mode 100644 index 7ce8cd5daac8..000000000000 --- a/src/libs/Navigation/linkingConfig/getMatchingCentralPaneRouteForState.ts +++ /dev/null @@ -1,74 +0,0 @@ -import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; -import type {AuthScreensParamList, CentralPaneName, NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; -import TAB_TO_CENTRAL_PANE_MAPPING from './RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING'; - -/** - * @param state - react-navigation state - */ -const getTopMostReportIDFromRHP = (state: State): string => { - if (!state) { - return ''; - } - - const topmostRightPane = state.routes.filter((route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR).at(-1); - - if (topmostRightPane?.state) { - return getTopMostReportIDFromRHP(topmostRightPane.state); - } - - const topmostRoute = state.routes.at(-1); - - if (topmostRoute?.state) { - return getTopMostReportIDFromRHP(topmostRoute.state); - } - - if (topmostRoute?.params && 'reportID' in topmostRoute.params && typeof topmostRoute.params.reportID === 'string') { - return topmostRoute.params.reportID; - } - - return ''; -}; - -// Get already opened settings screen within the policy -function getAlreadyOpenedSettingsScreen(rootState?: State): keyof AuthScreensParamList | undefined { - if (!rootState) { - return undefined; - } - - // If one of the screen from TAB_TO_CENTRAL_PANE_MAPPING[SCREENS.SETTINGS.ROOT] is now in the navigation state, we can decide which screen we should display. - // A screen from the navigation state can be pushed to the navigation state again only if it has a matching policyID with the currently selected workspace. - // Otherwise, when we switch the workspace, we want to display the initial screen in the settings tab. - const alreadyOpenedSettingsScreen = rootState.routes.filter((item) => TAB_TO_CENTRAL_PANE_MAPPING[SCREENS.SETTINGS.ROOT].includes(item.name as CentralPaneName)).at(-1); - - return alreadyOpenedSettingsScreen?.name as keyof AuthScreensParamList; -} - -// Get matching central pane route for bottom tab navigator. e.g HOME -> REPORT -function getMatchingCentralPaneRouteForState(state: State, rootState?: State): NavigationPartialRoute | undefined { - const topmostBottomTabRoute = getTopmostBottomTabRoute(state); - - if (!topmostBottomTabRoute) { - return; - } - - const centralPaneName = TAB_TO_CENTRAL_PANE_MAPPING[topmostBottomTabRoute.name].at(0); - if (!centralPaneName) { - return; - } - - if (topmostBottomTabRoute.name === SCREENS.SETTINGS.ROOT) { - // When we go back to the settings tab without switching the workspace id, we want to return to the previously opened screen - const screen = getAlreadyOpenedSettingsScreen(rootState) ?? centralPaneName; - return {name: screen as CentralPaneName, params: topmostBottomTabRoute.params}; - } - - if (topmostBottomTabRoute.name === SCREENS.HOME) { - return {name: centralPaneName, params: {reportID: getTopMostReportIDFromRHP(state)}}; - } - - return {name: centralPaneName}; -} - -export default getMatchingCentralPaneRouteForState; diff --git a/src/pages/home/sidebar/SidebarLinksData.tsx b/src/pages/home/sidebar/SidebarLinksData.tsx index 5b7faa9a20b2..e2e82e94d025 100644 --- a/src/pages/home/sidebar/SidebarLinksData.tsx +++ b/src/pages/home/sidebar/SidebarLinksData.tsx @@ -67,6 +67,7 @@ function SidebarLinksData({insets, isLoadingApp = true, onLinkClick, priorityMod // Data props: isActiveReport={isActiveReport} isLoading={isLoading ?? false} + activeWorkspaceID={activeWorkspaceID} optionListItems={orderedReportIDs} /> diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index fed578c4c1f9..59fd5a4d92ee 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -32,7 +32,6 @@ import * as Policy from '@userActions/Policy/Policy'; import * as ReimbursementAccount from '@userActions/ReimbursementAccount'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; -import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 91820f221564..990b633385f0 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -34,7 +34,7 @@ import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; @@ -53,7 +53,9 @@ import type {WithPolicyAndFullscreenLoadingProps} from './withPolicyAndFullscree import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading'; import WorkspacePageWithSections from './WorkspacePageWithSections'; -type WorkspaceMembersPageProps = WithPolicyAndFullscreenLoadingProps & WithCurrentUserPersonalDetailsProps & StackScreenProps; +type WorkspaceMembersPageProps = WithPolicyAndFullscreenLoadingProps & + WithCurrentUserPersonalDetailsProps & + StackScreenProps; /** * Inverts an object, equivalent of _.invert diff --git a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx index 484a408289db..a24ce932f7ae 100644 --- a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx +++ b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx @@ -17,7 +17,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import {isControlPolicy} from '@libs/PolicyUtils'; import * as Category from '@userActions/Policy/Category'; import * as DistanceRate from '@userActions/Policy/DistanceRate'; @@ -37,7 +37,7 @@ import type {WithPolicyAndFullscreenLoadingProps} from './withPolicyAndFullscree import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading'; import ToggleSettingOptionRow from './workflows/ToggleSettingsOptionRow'; -type WorkspaceMoreFeaturesPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +type WorkspaceMoreFeaturesPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; type Item = { icon: IconAsset; diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index 985e5df0eeca..4893fbd13b72 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -22,7 +22,7 @@ import useThemeIllustrations from '@hooks/useThemeIllustrations'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import Parser from '@libs/Parser'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -44,7 +44,7 @@ type WorkspaceProfilePageOnyxProps = { currencyList: OnyxEntry; }; -type WorkspaceProfilePageProps = WithPolicyProps & WorkspaceProfilePageOnyxProps & StackScreenProps; +type WorkspaceProfilePageProps = WithPolicyProps & WorkspaceProfilePageOnyxProps & StackScreenProps; function WorkspaceProfilePage({policyDraft, policy: policyProp, currencyList = {}, route}: WorkspaceProfilePageProps) { const styles = useThemeStyles(); diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index d8f3e98a7cad..bfed22902916 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -36,7 +36,7 @@ import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import localeCompare from '@libs/LocaleCompare'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as Modal from '@userActions/Modal'; @@ -54,7 +54,7 @@ type PolicyOption = ListItem & { keyForList: string; }; -type WorkspaceCategoriesPageProps = StackScreenProps; +type WorkspaceCategoriesPageProps = StackScreenProps; function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout(); diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx index 7ad3d7fd47b1..8a6fe2aae66c 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx @@ -7,7 +7,7 @@ import * as Illustrations from '@components/Icon/Illustrations'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections'; @@ -112,7 +112,7 @@ const mockedCards = { }, } as unknown as WorkspaceCardsList; -type WorkspaceCompanyCardPageProps = StackScreenProps; +type WorkspaceCompanyCardPageProps = StackScreenProps; function WorkspaceCompanyCardPage({route}: WorkspaceCompanyCardPageProps) { const {translate} = useLocalize(); diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx index 3a5c09c0b621..f4b0bcfdd6d2 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx @@ -25,7 +25,7 @@ import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as DistanceRate from '@userActions/Policy/DistanceRate'; import ButtonWithDropdownMenu from '@src/components/ButtonWithDropdownMenu'; @@ -36,7 +36,7 @@ import type {CustomUnit, Rate} from '@src/types/onyx/Policy'; type RateForList = ListItem & {value: string}; -type PolicyDistanceRatesPageProps = StackScreenProps; +type PolicyDistanceRatesPageProps = StackScreenProps; function PolicyDistanceRatesPage({ route: { diff --git a/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx b/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx index 685fa91ce9d0..ddaec5c1e131 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx @@ -20,7 +20,7 @@ import useWindowDimensions from '@hooks/useWindowDimensions'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import getClickedTargetLocation from '@libs/getClickedTargetLocation'; import * as PolicyUtils from '@libs/PolicyUtils'; -import type {WorkspaceNavigatorParamList} from '@navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; import variables from '@styles/variables'; import * as Policy from '@userActions/Policy/Policy'; import * as Report from '@userActions/Report'; @@ -40,7 +40,7 @@ type WorkspaceCardsListLabelProps = { }; function WorkspaceCardsListLabel({type, value, style}: WorkspaceCardsListLabelProps) { - const route = useRoute>(); + const route = useRoute>(); const policy = usePolicy(route.params.policyID); const styles = useThemeStyles(); const {windowWidth} = useWindowDimensions(); diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx index f2574223df48..e87ede820776 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx @@ -17,7 +17,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import * as CardUtils from '@libs/CardUtils'; import Navigation from '@navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -30,7 +30,7 @@ import WorkspaceCardListRow from './WorkspaceCardListRow'; type WorkspaceExpensifyCardListPageProps = { /** Route from navigation */ - route: RouteProp; + route: RouteProp; /** List of Expensify cards */ cardsList: OnyxEntry; diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx index 5d173fa4310b..32dcc9ffbea5 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPage.tsx @@ -6,7 +6,7 @@ import {useOnyx} from 'react-native-onyx'; import useNetwork from '@hooks/useNetwork'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as Policy from '@userActions/Policy/Policy'; @@ -16,7 +16,7 @@ import type SCREENS from '@src/SCREENS'; import WorkspaceExpensifyCardListPage from './WorkspaceExpensifyCardListPage'; import WorkspaceExpensifyCardPageEmptyState from './WorkspaceExpensifyCardPageEmptyState'; -type WorkspaceExpensifyCardPageProps = StackScreenProps; +type WorkspaceExpensifyCardPageProps = StackScreenProps; function WorkspaceExpensifyCardPage({route}: WorkspaceExpensifyCardPageProps) { const policyID = route.params.policyID ?? '-1'; diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx index 732f9c047589..a2b6706f0c5b 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx @@ -12,7 +12,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as CardUtils from '@libs/CardUtils'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import Navigation from '@navigation/Navigation'; import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading'; import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading'; @@ -40,7 +40,7 @@ const expensifyCardFeatures: FeatureListItem[] = [ ]; type WorkspaceExpensifyCardPageEmptyStateProps = { - route: StackScreenProps['route']; + route: StackScreenProps['route']; } & WithPolicyAndFullscreenLoadingProps; function WorkspaceExpensifyCardPageEmptyState({route, policy}: WorkspaceExpensifyCardPageEmptyStateProps) { diff --git a/src/pages/workspace/invoices/WorkspaceInvoicesPage.tsx b/src/pages/workspace/invoices/WorkspaceInvoicesPage.tsx index 75d1ab46fe28..6d658bb0cffb 100644 --- a/src/pages/workspace/invoices/WorkspaceInvoicesPage.tsx +++ b/src/pages/workspace/invoices/WorkspaceInvoicesPage.tsx @@ -4,7 +4,7 @@ import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {WorkspaceNavigatorParamList} from '@navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections'; import CONST from '@src/CONST'; @@ -13,7 +13,7 @@ import WorkspaceInvoicesNoVBAView from './WorkspaceInvoicesNoVBAView'; import WorkspaceInvoicesVBAView from './WorkspaceInvoicesVBAView'; import WorkspaceInvoiceVBASection from './WorkspaceInvoiceVBASection'; -type WorkspaceInvoicesPageProps = StackScreenProps; +type WorkspaceInvoicesPageProps = StackScreenProps; function WorkspaceInvoicesPage({route}: WorkspaceInvoicesPageProps) { const {translate} = useLocalize(); diff --git a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx index 9b36e648c17d..eea32546976f 100644 --- a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx +++ b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx @@ -33,7 +33,7 @@ import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import localeCompare from '@libs/LocaleCompare'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as WorkspaceReportFieldUtils from '@libs/WorkspaceReportFieldUtils'; @@ -51,7 +51,7 @@ type ReportFieldForList = ListItem & { orderWeight?: number; }; -type WorkspaceReportFieldsPageProps = StackScreenProps; +type WorkspaceReportFieldsPageProps = StackScreenProps; function WorkspaceReportFieldsPage({ route: { diff --git a/src/pages/workspace/rules/PolicyRulesPage.tsx b/src/pages/workspace/rules/PolicyRulesPage.tsx index 1fce2fb7bfcf..93508060c94f 100644 --- a/src/pages/workspace/rules/PolicyRulesPage.tsx +++ b/src/pages/workspace/rules/PolicyRulesPage.tsx @@ -5,7 +5,7 @@ import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections'; import * as Illustrations from '@src/components/Icon/Illustrations'; @@ -14,7 +14,7 @@ import type SCREENS from '@src/SCREENS'; import ExpenseReportRulesSection from './ExpenseReportRulesSection'; import IndividualExpenseRulesSection from './IndividualExpenseRulesSection'; -type PolicyRulesPageProps = StackScreenProps; +type PolicyRulesPageProps = StackScreenProps; function PolicyRulesPage({route}: PolicyRulesPageProps) { const {translate} = useLocalize(); diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 2c19eb70cac8..30bdf23504a4 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -35,7 +35,7 @@ import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import localeCompare from '@libs/LocaleCompare'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as Modal from '@userActions/Modal'; @@ -48,7 +48,7 @@ import type {PendingAction} from '@src/types/onyx/OnyxCommon'; import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type {PolicyTag, PolicyTagList, TagListItem} from './types'; -type WorkspaceTagsPageProps = StackScreenProps; +type WorkspaceTagsPageProps = StackScreenProps; function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout(); diff --git a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx index ac0eb0294203..b84c0e33e5d6 100644 --- a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx +++ b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx @@ -29,7 +29,7 @@ import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; -import type {WorkspaceNavigatorParamList} from '@navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading'; import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading'; @@ -39,7 +39,7 @@ import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type {TaxRate} from '@src/types/onyx'; -type WorkspaceTaxesPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +type WorkspaceTaxesPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; function WorkspaceTaxesPage({ policy, diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index 6412486ddf9d..53fc65c6915d 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -3,14 +3,20 @@ import type {ComponentType, ForwardedRef, RefAttributes} from 'react'; import React, {forwardRef} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {useOnyx} from 'react-native-onyx'; -import type {AuthScreensParamList, BottomTabNavigatorParamList, ReimbursementAccountNavigatorParamList, SettingsNavigatorParamList, WorkspaceNavigatorParamList} from '@navigation/types'; +import type { + AuthScreensParamList, + BottomTabNavigatorParamList, + ReimbursementAccountNavigatorParamList, + SettingsNavigatorParamList, + WorkspaceSplitNavigatorParamList, +} from '@navigation/types'; import * as Policy from '@userActions/Policy/Policy'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; -type NavigatorsParamList = BottomTabNavigatorParamList & AuthScreensParamList & SettingsNavigatorParamList & ReimbursementAccountNavigatorParamList & WorkspaceNavigatorParamList; +type NavigatorsParamList = BottomTabNavigatorParamList & AuthScreensParamList & SettingsNavigatorParamList & ReimbursementAccountNavigatorParamList & WorkspaceSplitNavigatorParamList; type PolicyRoute = RouteProp< NavigatorsParamList, diff --git a/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx b/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx index 177e2f78467c..daaa14e81a70 100644 --- a/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceAutoReportingFrequencyPage.tsx @@ -13,7 +13,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as Localize from '@libs/Localize'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; @@ -27,7 +27,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; type AutoReportingFrequencyKey = Exclude, 'instant'>; type Locale = ValueOf; -type WorkspaceAutoReportingFrequencyPageProps = WithPolicyOnyxProps & StackScreenProps; +type WorkspaceAutoReportingFrequencyPageProps = WithPolicyOnyxProps & StackScreenProps; type WorkspaceAutoReportingFrequencyPageItem = { text: string; diff --git a/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx b/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx index 86b91088c030..119d9ba65ad8 100644 --- a/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceAutoReportingMonthlyOffsetPage.tsx @@ -8,7 +8,7 @@ import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import withPolicy from '@pages/workspace/withPolicy'; @@ -21,7 +21,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; const DAYS_OF_MONTH = 28; -type WorkspaceAutoReportingMonthlyOffsetProps = WithPolicyOnyxProps & StackScreenProps; +type WorkspaceAutoReportingMonthlyOffsetProps = WithPolicyOnyxProps & StackScreenProps; type AutoReportingOffsetKeys = ValueOf; diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx index df648d0b03e0..1c824d7816f3 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx @@ -25,7 +25,7 @@ import {getPaymentMethodDescription} from '@libs/PaymentUtils'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import {convertPolicyEmployeesToApprovalWorkflows, INITIAL_APPROVAL_WORKFLOW} from '@libs/WorkflowUtils'; -import type {WorkspaceNavigatorParamList} from '@navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; import withPolicy from '@pages/workspace/withPolicy'; @@ -42,7 +42,7 @@ import type {ToggleSettingOptionRowProps} from './ToggleSettingsOptionRow'; import {getAutoReportingFrequencyDisplayNames} from './WorkspaceAutoReportingFrequencyPage'; import type {AutoReportingFrequencyKey} from './WorkspaceAutoReportingFrequencyPage'; -type WorkspaceWorkflowsPageProps = WithPolicyProps & StackScreenProps; +type WorkspaceWorkflowsPageProps = WithPolicyProps & StackScreenProps; function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { const {translate, preferredLocale} = useLocalize(); diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx index e24975484260..35742bad9c2a 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx @@ -19,7 +19,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; @@ -35,7 +35,7 @@ import type {Icon} from '@src/types/onyx/OnyxCommon'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; type WorkspaceWorkflowsApprovalsApproverPageProps = WithPolicyAndFullscreenLoadingProps & - StackScreenProps; + StackScreenProps; type SelectionListApprover = { text: string; diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsCreatePage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsCreatePage.tsx index 90f10ce0cd63..1e3baac72a05 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsCreatePage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsCreatePage.tsx @@ -11,7 +11,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading'; @@ -23,7 +23,7 @@ import type SCREENS from '@src/SCREENS'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import ApprovalWorkflowEditor from './ApprovalWorkflowEditor'; -type WorkspaceWorkflowsApprovalsCreatePageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +type WorkspaceWorkflowsApprovalsCreatePageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; function WorkspaceWorkflowsApprovalsCreatePage({policy, isLoadingReportData = true, route}: WorkspaceWorkflowsApprovalsCreatePageProps) { const styles = useThemeStyles(); diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx index 0c7b7fd8465a..8dffdcde2f88 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx @@ -13,7 +13,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import {convertPolicyEmployeesToApprovalWorkflows} from '@libs/WorkflowUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; @@ -27,7 +27,7 @@ import type ApprovalWorkflow from '@src/types/onyx/ApprovalWorkflow'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import ApprovalWorkflowEditor from './ApprovalWorkflowEditor'; -type WorkspaceWorkflowsApprovalsEditPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +type WorkspaceWorkflowsApprovalsEditPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; function WorkspaceWorkflowsApprovalsEditPage({policy, isLoadingReportData = true, route}: WorkspaceWorkflowsApprovalsEditPageProps) { const styles = useThemeStyles(); diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx index 273a7cf64b9f..4b7805869497 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsExpensesFromPage.tsx @@ -19,7 +19,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; -import type {WorkspaceNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; @@ -48,7 +48,7 @@ type SelectionListMember = { type MembersSection = SectionListData>; type WorkspaceWorkflowsApprovalsExpensesFromPageProps = WithPolicyAndFullscreenLoadingProps & - StackScreenProps; + StackScreenProps; function WorkspaceWorkflowsApprovalsExpensesFromPage({policy, isLoadingReportData = true, route}: WorkspaceWorkflowsApprovalsExpensesFromPageProps) { const styles = useThemeStyles(); From b83d53dd9c13b0667eeca45f3480e64554cf8e23 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 9 Oct 2024 13:54:03 +0200 Subject: [PATCH 087/257] Remove remaining occurences of Navigation.closeAndNavigate --- src/components/Search/SearchRouter/SearchRouterList.tsx | 3 ++- src/pages/iou/request/step/IOURequestStepCategory.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/Search/SearchRouter/SearchRouterList.tsx b/src/components/Search/SearchRouter/SearchRouterList.tsx index 7d86ce1150d5..d891e3e6a9aa 100644 --- a/src/components/Search/SearchRouter/SearchRouterList.tsx +++ b/src/components/Search/SearchRouter/SearchRouterList.tsx @@ -159,7 +159,8 @@ function SearchRouterList( // Handle selection of "Recent chat" closeAndClearRouter(); if ('reportID' in item && item?.reportID) { - Navigation.closeAndNavigate(ROUTES.REPORT_WITH_ID.getRoute(item?.reportID)); + // @TODO: Previously Navigation.closeAndNavigate was used here, remember to verify if it works correctly + Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(item?.reportID)); } else if ('login' in item) { Report.navigateToAndOpenReport(item?.login ? [item.login] : []); } diff --git a/src/pages/iou/request/step/IOURequestStepCategory.tsx b/src/pages/iou/request/step/IOURequestStepCategory.tsx index f3388fcc7b0e..b384ec272282 100644 --- a/src/pages/iou/request/step/IOURequestStepCategory.tsx +++ b/src/pages/iou/request/step/IOURequestStepCategory.tsx @@ -146,7 +146,8 @@ function IOURequestStepCategory({ IOU.setMoneyRequestCategory(transactionID, updatedCategory); if (action === CONST.IOU.ACTION.CATEGORIZE) { - Navigation.closeAndNavigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(action, iouType, transactionID, report?.reportID ?? '-1')); + // @TODO: Previously Navigation.closeAndNavigate was used here, remember to verify if it works correctly + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(action, iouType, transactionID, report?.reportID ?? '-1')); return; } From a214ae09a6b38e329a037c1020b9cd4088a6b0a6 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 9 Oct 2024 15:09:54 +0200 Subject: [PATCH 088/257] Fix animation when navigating to central screen of split navigator --- .../Navigation/AppNavigator/AuthScreens.tsx | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 9961eeff6955..fee658c673cb 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -1,3 +1,4 @@ +import type {RouteProp} from '@react-navigation/native'; import React, {memo, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; @@ -55,6 +56,7 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; +import SIDEBAR_TO_SPLIT from '../linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT'; import createCustomStackNavigator from './createCustomStackNavigator'; import defaultScreenOptions from './defaultScreenOptions'; import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions'; @@ -230,6 +232,26 @@ function AuthScreens() { isInitialRender.current = false; } + // Animation is disabled when navigating to the sidebar screen + const getSplitNavigatorOptions = (route: RouteProp) => { + if (!isSmallScreenWidth || !route?.params) { + return screenOptions.fullScreen; + } + + const screenName = 'screen' in route.params ? route.params.screen : undefined; + + if (!screenName) { + return screenOptions.fullScreen; + } + + const animationEnabled = !Object.keys(SIDEBAR_TO_SPLIT).includes(screenName); + + return { + ...screenOptions.fullScreen, + animationEnabled, + }; + }; + useEffect(() => { const shortcutsOverviewShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SHORTCUTS; const searchShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SEARCH; @@ -394,12 +416,12 @@ function AuthScreens() { {/* This have to be the first navigator in auth screens. */} getSplitNavigatorOptions(route)} getComponent={loadReportSplitNavigator} /> getSplitNavigatorOptions(route)} getComponent={loadSettingsSplitNavigator} /> getSplitNavigatorOptions(route)} getComponent={loadWorkspaceSplitNavigator} /> Date: Wed, 9 Oct 2024 16:20:05 +0200 Subject: [PATCH 089/257] Fix customGetPathFromState --- .../linkingConfig/customGetPathFromState.ts | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts index 199e6656dabd..74c38d130ad6 100644 --- a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts +++ b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts @@ -3,18 +3,21 @@ import type {RootStackParamList, State} from '@libs/Navigation/types'; import {removePolicyIDParamFromState} from '@libs/NavigationUtils'; import NAVIGATORS from '@src/NAVIGATORS'; -function getTopmostSplitNavigator(state: State | undefined) { - return state?.routes.findLast((route) => route.name.endsWith('SplitNavigator')); -} - const customGetPathFromState: typeof getPathFromState = (state, options) => { - // For the Home and Settings pages we should remove policyID from the params, because on small screens it's displayed twice in the URL + // For the Home page we should remove policyID from the params, because on small screens it's displayed twice in the URL const stateWithoutPolicyID = removePolicyIDParamFromState(state as State); const path = getPathFromState(stateWithoutPolicyID, options); - const topmostSplitNavigator = getTopmostSplitNavigator(state as State); - const policyIDFromState = topmostSplitNavigator?.params?.policyID; - const shouldAddPolicyID = !!topmostSplitNavigator && topmostSplitNavigator?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; - return `${policyIDFromState && shouldAddPolicyID ? `/w/${policyIDFromState}` : ''}${path}`; + const topmostRoute = state.routes.at(-1); + + const shouldAddPolicyID = !!topmostRoute && topmostRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; + + if (!shouldAddPolicyID) { + return path; + } + + const policyID = topmostRoute.params && `policyID` in topmostRoute.params ? (topmostRoute.params.policyID as string) : undefined; + + return `${policyID ? `/w/${policyID}` : ''}${path}`; }; export default customGetPathFromState; From 00001dd8fae10b48da5e2e48a0e91ad0391a2fc2 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 9 Oct 2024 17:21:55 +0200 Subject: [PATCH 090/257] add optimization for root navigator --- .../createCustomStackNavigator/index.tsx | 17 +++++++++--- .../SplitStackRouter.ts | 4 ++- .../createSplitStackNavigator/index.tsx | 3 +++ .../usePreserveSplitNavigatorState.ts | 26 +++++++++++++++++++ src/libs/Navigation/NavigationRoot.tsx | 2 ++ 5 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState.ts diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx index 8c98002e5c7b..1ba5b5bdcd25 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx @@ -2,12 +2,21 @@ import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@rea import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; import {StackView} from '@react-navigation/stack'; -import React from 'react'; +import React, {useMemo} from 'react'; import CustomRouter from './CustomRouter'; import type {ResponsiveStackNavigatorProps, ResponsiveStackNavigatorRouterOptions} from './types'; +function getStateToRender(state: StackNavigationState): StackNavigationState { + const routes = state.routes.slice(-2); + + return { + ...state, + routes, + index: routes.length - 1, + }; +} + function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { - // TODO: This part needs some TS magic to work. const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< StackNavigationState, ResponsiveStackNavigatorRouterOptions, @@ -20,12 +29,14 @@ function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { initialRouteName: props.initialRouteName, }); + const stateToRender = useMemo(() => getStateToRender(state), [state]); + return ( diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts index 2dbff910c956..6e97bb18cfaa 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts @@ -5,6 +5,7 @@ import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import getParamsFromRoute from '@libs/Navigation/linkingConfig/getParamsFromRoute'; import navigationRef from '@libs/Navigation/navigationRef'; import type {SplitStackNavigatorRouterOptions} from './types'; +import {getPreservedSplitNavigatorState} from './usePreserveSplitNavigatorState'; type StackState = StackNavigationState | PartialState>; @@ -94,7 +95,8 @@ function SplitStackRouter(options: SplitStackNavigatorRouterOptions) { return stackRouter.getStateForAction(state, action, configOptions); }, getInitialState({routeNames, routeParamList, routeGetIdList}: RouterConfigOptions) { - const initialState = stackRouter.getInitialState({routeNames, routeParamList, routeGetIdList}); + const preservedState = getPreservedSplitNavigatorState(options.parentRoute.key); + const initialState = preservedState ?? stackRouter.getInitialState({routeNames, routeParamList, routeGetIdList}); adaptStateIfNecessary({ state: initialState, diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index bcec6474ea50..c912a428dcce 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -13,6 +13,7 @@ import SplitStackRouter from './SplitStackRouter'; import type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions} from './types'; import useHandleScreenResize from './useHandleScreenResize'; import usePrepareSplitStackNavigatorChildren from './usePrepareSplitStackNavigatorChildren'; +import usePreserveSplitNavigatorState from './usePreserveSplitNavigatorState'; function getStateToRender(state: StackNavigationState, isSmallScreenWidth: boolean): StackNavigationState { const sidebarScreenRoute = state.routes.at(0); @@ -56,6 +57,8 @@ function SplitStackNavigator(props: SplitStackN parentRoute: route, }); + // We need to copy the state to the params so that the state is preserved when the root navigator unmount this route for performance reasons. + usePreserveSplitNavigatorState(route, state); useHandleScreenResize(navigation); const stateToRender = useMemo(() => getStateToRender(state, shouldUseNarrowLayout), [state, shouldUseNarrowLayout]); diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState.ts new file mode 100644 index 000000000000..215f03d94a8f --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState.ts @@ -0,0 +1,26 @@ +import type {NavigationState, ParamListBase, RouteProp, StackNavigationState} from '@react-navigation/native'; +import {useEffect} from 'react'; + +const preservedSplitNavigatorStates: Record> = {}; + +const cleanPreservedSplitNavigatorStates = (state: NavigationState) => { + const currentSplitNavigatorKeys = state.routes.map((route) => route.key); + + for (const key of Object.keys(preservedSplitNavigatorStates)) { + if (!currentSplitNavigatorKeys.includes(key)) { + delete preservedSplitNavigatorStates[key]; + } + } +}; + +const getPreservedSplitNavigatorState = (key: string) => preservedSplitNavigatorStates[key]; + +function usePreserveSplitNavigatorState(route: RouteProp, state: StackNavigationState) { + useEffect(() => { + preservedSplitNavigatorStates[route.key] = state; + }, [route, state]); +} + +export default usePreserveSplitNavigatorState; + +export {getPreservedSplitNavigatorState, cleanPreservedSplitNavigatorStates}; diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 124e0ed541d6..46b6e4a22457 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -20,6 +20,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import AppNavigator from './AppNavigator'; +import {cleanPreservedSplitNavigatorStates} from './AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState'; import linkingConfig from './linkingConfig'; import customGetPathFromState from './linkingConfig/customGetPathFromState'; import getAdaptedStateFromPath from './linkingConfig/getAdaptedStateFromPath'; @@ -165,6 +166,7 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh // We want to clean saved scroll offsets for screens that aren't anymore in the state. cleanStaleScrollOffsets(state); + cleanPreservedSplitNavigatorStates(state); }; return ( From 93eb244bf0651bab58854a16d661720085b53ae4 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 9 Oct 2024 17:28:15 +0200 Subject: [PATCH 091/257] remove FreezeWrapper --- .../withPrepareCentralPaneScreen/index.tsx | 10 ------- .../Navigation/AppNavigator/AuthScreens.tsx | 11 ++++--- .../Navigators/ReportsSplitNavigator.tsx | 3 +- src/libs/Navigation/FreezeWrapper.tsx | 30 ------------------- src/libs/freezeScreenWithLazyLoading.tsx | 24 --------------- .../home/sidebar/SidebarScreen/index.tsx | 8 +---- 6 files changed, 7 insertions(+), 79 deletions(-) delete mode 100644 src/components/withPrepareCentralPaneScreen/index.tsx delete mode 100644 src/libs/Navigation/FreezeWrapper.tsx delete mode 100644 src/libs/freezeScreenWithLazyLoading.tsx diff --git a/src/components/withPrepareCentralPaneScreen/index.tsx b/src/components/withPrepareCentralPaneScreen/index.tsx deleted file mode 100644 index 84ba31cd63fd..000000000000 --- a/src/components/withPrepareCentralPaneScreen/index.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import type React from 'react'; -import freezeScreenWithLazyLoading from '@libs/freezeScreenWithLazyLoading'; - -/** - * This higher-order function is dependent on the platform. On native platforms, screens that aren't already displayed in the navigation stack should be frozen to prevent unnecessary rendering. - * It's handled this way only on mobile platforms because on the web, more than one screen is displayed in a wide layout, so these screens shouldn't be frozen. - */ -export default function withPrepareCentralPaneScreen(lazyComponent: () => React.ComponentType) { - return freezeScreenWithLazyLoading(lazyComponent); -} diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index fee658c673cb..97983626d3e0 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -9,7 +9,6 @@ import ComposeProviders from '@components/ComposeProviders'; import OptionsListContextProvider from '@components/OptionListContextProvider'; import {SearchContextProvider} from '@components/Search/SearchContext'; import SearchRouterModal from '@components/Search/SearchRouter/SearchRouterModal'; -import withPrepareCentralPaneScreen from '@components/withPrepareCentralPaneScreen'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useOnboardingFlowRouter from '@hooks/useOnboardingFlow'; import usePermissions from '@hooks/usePermissions'; @@ -24,6 +23,7 @@ import KeyboardShortcut from '@libs/KeyboardShortcut'; import Log from '@libs/Log'; import getCurrentUrl from '@libs/Navigation/currentUrl'; import getOnboardingModalScreenOptions from '@libs/Navigation/getOnboardingModalScreenOptions'; +import SIDEBAR_TO_SPLIT from '@libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT'; import Navigation from '@libs/Navigation/Navigation'; import type {AuthScreensParamList} from '@libs/Navigation/types'; import NetworkConnection from '@libs/NetworkConnection'; @@ -56,7 +56,6 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; -import SIDEBAR_TO_SPLIT from '../linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT'; import createCustomStackNavigator from './createCustomStackNavigator'; import defaultScreenOptions from './defaultScreenOptions'; import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions'; @@ -79,10 +78,10 @@ const loadReportAvatar = () => require('../../../pages/Rep const loadReceiptView = () => require('../../../pages/TransactionReceiptPage').default; const loadWorkspaceJoinUser = () => require('@pages/workspace/WorkspaceJoinUserPage').default; -const loadReportSplitNavigator = withPrepareCentralPaneScreen(() => require('./Navigators/ReportsSplitNavigator').default); -const loadSettingsSplitNavigator = withPrepareCentralPaneScreen(() => require('./Navigators/SettingsSplitNavigator').default); -const loadWorkspaceSplitNavigator = withPrepareCentralPaneScreen(() => require('./Navigators/WorkspaceSplitNavigator').default); -const loadSearchPage = withPrepareCentralPaneScreen(() => require('@pages/Search/SearchPage').default); +const loadReportSplitNavigator = () => require('./Navigators/ReportsSplitNavigator').default; +const loadSettingsSplitNavigator = () => require('./Navigators/SettingsSplitNavigator').default; +const loadWorkspaceSplitNavigator = () => require('./Navigators/WorkspaceSplitNavigator').default; +const loadSearchPage = () => require('@pages/Search/SearchPage').default; function shouldOpenOnAdminRoom() { const url = getCurrentUrl(); diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index 2ad1d7a480c9..05b0b6c6d4f8 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -1,6 +1,5 @@ import React, {useRef} from 'react'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; -import withPrepareCentralPaneScreen from '@components/withPrepareCentralPaneScreen'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import usePermissions from '@hooks/usePermissions'; import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; @@ -12,7 +11,7 @@ import CONST from '@src/CONST'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; -const loadReportScreen = withPrepareCentralPaneScreen(() => require('../../../../pages/home/ReportScreen').default); +const loadReportScreen = () => require('../../../../pages/home/ReportScreen').default; const Stack = createSplitStackNavigator(); diff --git a/src/libs/Navigation/FreezeWrapper.tsx b/src/libs/Navigation/FreezeWrapper.tsx deleted file mode 100644 index aa6e302cdbd0..000000000000 --- a/src/libs/Navigation/FreezeWrapper.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import {useIsFocused, useNavigation, useRoute} from '@react-navigation/native'; -import React, {useEffect, useRef} from 'react'; -import {Freeze} from 'react-freeze'; -import type ChildrenProps from '@src/types/utils/ChildrenProps'; -import shouldSetScreenBlurred from './shouldSetScreenBlurred'; - -type FreezeWrapperProps = ChildrenProps & { - /** Prop to disable freeze */ - keepVisible?: boolean; -}; - -function FreezeWrapper({keepVisible = false, children}: FreezeWrapperProps) { - // we need to know the screen index to determine if the screen can be frozen - const screenIndexRef = useRef(null); - const isFocused = useIsFocused(); - const navigation = useNavigation(); - const currentRoute = useRoute(); - const isBlurred = shouldSetScreenBlurred((navigation.getState()?.index ?? 0) - (screenIndexRef.current ?? 0)); - useEffect(() => { - const index = navigation.getState()?.routes.findIndex((route) => route.key === currentRoute.key) ?? 0; - screenIndexRef.current = index; - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, []); - - return {children}; -} - -FreezeWrapper.displayName = 'FreezeWrapper'; - -export default FreezeWrapper; diff --git a/src/libs/freezeScreenWithLazyLoading.tsx b/src/libs/freezeScreenWithLazyLoading.tsx deleted file mode 100644 index eb3c8fa8bc63..000000000000 --- a/src/libs/freezeScreenWithLazyLoading.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import memoize from './memoize'; -import FreezeWrapper from './Navigation/FreezeWrapper'; - -function FrozenScreen(WrappedComponent: React.ComponentType) { - return (props: TProps) => ( - - - - ); -} - -export default function freezeScreenWithLazyLoading(lazyComponent: () => React.ComponentType) { - return memoize( - () => { - const Component = lazyComponent(); - return FrozenScreen(Component); - }, - {monitoringName: 'freezeScreenWithLazyLoading'}, - ); -} diff --git a/src/pages/home/sidebar/SidebarScreen/index.tsx b/src/pages/home/sidebar/SidebarScreen/index.tsx index 3190c7b7aa71..dc04c005b827 100755 --- a/src/pages/home/sidebar/SidebarScreen/index.tsx +++ b/src/pages/home/sidebar/SidebarScreen/index.tsx @@ -1,14 +1,8 @@ import React from 'react'; -// import FreezeWrapper from '@libs/Navigation/FreezeWrapper'; import BaseSidebarScreen from './BaseSidebarScreen'; -// TODO-SPLITS: Figure out how to handle the FreezeWrapper component. function SidebarScreen() { - return ( - // - - // - ); + return ; } SidebarScreen.displayName = 'SidebarScreen'; From 7b36a3b60d4729aee73538586f5ae6a5ee822139 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 9 Oct 2024 17:35:23 +0200 Subject: [PATCH 092/257] Add tests section to the NAVIGATION.md --- contributingGuides/NAVIGATION.md | 133 +++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index 6c0a5b460654..e91cb3e473ef 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -208,3 +208,136 @@ The action for the first step created with `getMinimalAction` looks like this: ### Deeplinking There is no minimal action for deeplinking directly to the `Profile` screen. But because the `Settings_root` is not on the stack, pressing UP will reset the params for navigators to the correct ones. + +### Tests + +#### There should be a proper report under attachment screen after reload +narrow layout: + +1. Open any report with image attachment. +2. Open attachment. +3. Reload the page. +4. Verify that after pressing back arrow in the header you are on the report where you sent the attachment. + + +#### There is a proper split navigator under RHP with a sidebar screen only for screens that can be opened from the sidebar + +1. Open the browser on narrow layout with url /settings/profile/status. +2. Reload the page. +3. Verify that after pressing back arrow in the header you are on the settings root page. + + +#### There is a proper split navigator under the overlay after refreshing page with RHP/LHP on wide screen + +1. Open the browser on wide screen with url /settings/profile/details. +2. Verify that you can see settings profile page under the overlay of RHP. + + +#### There is a proper split navigator under the overlay after deeplinking to page with RHP/LHP on wide screen + +1. Open the browser on wide screen. +2. Open any report. +3. Send message with url /settings/profile/details. +4. Press the sent link +5. Verify that the settings profile screen is now visible under the overlay + + +#### The Workspace list page is displayed (SCREENS.SETTINGS.WORKSPACES) after clicking the Settings tab from the Workspace settings screen + +1. Open the workspace settings (use a link in format: https://dev.new.expensify.com:8082/settings/workspaces/:policyID:/profile or open it using this flow Settings → Workspaces → Select any workspace) +2. Click the Settings button on the bottom tab. +3. Verify that the Workspace list is displayed (https://dev.new.expensify.com:8082/settings/workspaces) + + +#### The last visited screen in the settings tab is saved when switching between tabs + +1. Open the app. +2. Go to the settings tab. +3. Open the workspace list. +4. Select any workspace. +5. Switch between tabs and open the settings tabs again. +6. Verify that the last visited page in this tab is displayed. + + +#### The Workspace selected in the application is reset when you select a chat that does not belong to the current policy + +1. Open the home page. +2. Click on the Expensify icon in the upper left corner. +3. Select any workspace. +4. Click on the magnifying glass above the list of available chats. +5. Select a chat that does not belong to the workspace selected in the third step. +6. Verify if the chat is opened and the global workspace is selected. + + +#### The selected workspace is saved between Search and Inbox tabs + +1. Open the Inbox tab. +2. Change the workspace using the workspace switcher. +3. Switch to the Search tab and verify if the workspace selected in the second step is also selected in the Search. +4. Repeat the second step. +5. Go back to the Inbox. +6. Verify if the workspace selected in the fourth step is also selected in the Inbox tab. + +#### Going up to the workspace list page after refreshing on the workspace settings and pressing the up button + +1. Open the workspace settings from the deep link (use a link in format: https://dev.new.expensify.com:8082/settings/workspaces/:policyID:/profile) +2. Click the app’s back button. +3. Verify if the workspace list is displayed. + +#### Going up to the RHP screen provided in the backTo parameter in the url + +1. Open the settings tab. +2. Go to the Profile page. +3. Click the Address button. +4. Click the Country button. +5. Reload the page. +6. Click the app’s back button. +7. Verify if the Profile address page is displayed (https://dev.new.expensify.com:8082/settings/profile/address) + +#### There is proper split navigator under the overlay after refreshing page in RHP that includes valid reportID in params + +wide layout : + +1. Open any report. +2. Open report details (press the chat header). +3. Reload the app. +4. Verify that the report under the overlay is the same as the one opened in report details. + +narrow layout : + +1. Open any report +2. Open report details (press the chat header). +3. Reload the app. +4. Verify that after pressing back arrow in the header you are on the report previously seen in the details page. + +#### Navigating back to the Workspace Switcher from the created workspace + +1. Open the app and go to the Inbox tab. +2. Open the workspace switcher (Click on the button in the upper left corner). +3. Create a new workspace by clicking on the + button. +4. Navigate back using the back button in the app. +5. Verify if the workspace switcher is displayed with the report screen below it + +#### Going up to the sidebar screen + +Linked issue: https://github.com/Expensify/App/pull/44138 + +1. Go to Subscription page in the settings tab. +2. Click on Request refund button +3. Verify that modal shown +4. Next click Downgrade... +5. Verify that modal got closed, your account is downgraded and the Home page is opened. + +#### Navigating back from the Search page with invalid query parameters + +1. Open the search page with invalid query parameters (e.g https://dev.new.expensify.com:8082/search?q=from%3a) +2. Press the app's back button on the not found page. +3. Verify that the Search page with default query parameters is displayed. + +#### Navigating to the chat from the link in the thread + +1. Open any chat. +2. If there are no messages in the chat, send a message. +3. Reply to the message you created in the thread. +4. After being redirected to the thread screen, click on the link displayed in the header. +5. Verify if the link correctly redirects to the chat opened in the first step. \ No newline at end of file From 9e34f969e28c3534946fbd4223ccc432d61f51c4 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 11 Oct 2024 11:05:03 +0200 Subject: [PATCH 093/257] Add freezing sidebar screen --- .../Navigators/ReportsSplitNavigator.tsx | 51 +++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index d356c2519abe..4f7a29430747 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -1,17 +1,40 @@ -import React, {useRef} from 'react'; +import {useNavigation, useRoute} from '@react-navigation/native'; +import React, {useEffect, useRef, useState} from 'react'; +import {Freeze} from 'react-freeze'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import usePermissions from '@hooks/usePermissions'; +import memoize from '@libs/memoize'; import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; import getCurrentUrl from '@libs/Navigation/currentUrl'; import shouldOpenOnAdminRoom from '@libs/Navigation/shouldOpenOnAdminRoom'; import type {ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; -import SidebarScreen from '@pages/home/sidebar/SidebarScreen'; import CONST from '@src/CONST'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; +function FrozenScreen(WrappedComponent: React.ComponentType, freeze: boolean) { + return (props: TProps) => ( + + + + ); +} + +function freezeScreenWithLazyLoading(lazyComponent: () => React.ComponentType, freeze: boolean) { + return memoize( + () => { + const Component = lazyComponent(); + return FrozenScreen(Component, freeze); + }, + {monitoringName: 'freezeScreenWithLazyLoading'}, + ); +} + const loadReportScreen = () => require('../../../../pages/home/ReportScreen').default; const Stack = createSplitStackNavigator(); @@ -20,9 +43,29 @@ function ReportsSplitNavigator() { const {canUseDefaultRooms} = usePermissions(); const {activeWorkspaceID} = useActiveWorkspace(); + const [isScreenBlurred, setIsScreenBlurred] = useState(false); + let initialReportID: string | undefined; const isInitialRender = useRef(true); + const screenIndexRef = useRef(null); + const navigation = useNavigation(); + const currentRoute = useRoute(); + + useEffect(() => { + const index = navigation.getState()?.routes.findIndex((route) => route.key === currentRoute.key) ?? 0; + screenIndexRef.current = index; + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + const unsubscribe = navigation.addListener('state', () => { + const navigationIndex = (navigation.getState()?.index ?? 0) - (screenIndexRef.current ?? 0); + setIsScreenBlurred(navigationIndex >= 1); + }); + return () => unsubscribe(); + }, [navigation]); + if (isInitialRender.current) { const currentURL = getCurrentUrl(); if (currentURL) { @@ -37,6 +80,8 @@ function ReportsSplitNavigator() { isInitialRender.current = false; } + const getSidebarScreen = freezeScreenWithLazyLoading(() => require('@pages/home/sidebar/SidebarScreen').default, isScreenBlurred); + return ( Date: Fri, 11 Oct 2024 11:31:31 +0200 Subject: [PATCH 094/257] Dont freeze sidebar screen when modal navigator is above in the navigation state --- .../AppNavigator/Navigators/ReportsSplitNavigator.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index 4f7a29430747..cee38c625cff 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -60,7 +60,8 @@ function ReportsSplitNavigator() { useEffect(() => { const unsubscribe = navigation.addListener('state', () => { - const navigationIndex = (navigation.getState()?.index ?? 0) - (screenIndexRef.current ?? 0); + const modalNavigatorsCount = navigation.getState()?.routes?.filter((route) => route.name.endsWith('ModalNavigator'))?.length ?? 0; + const navigationIndex = (navigation.getState()?.index ?? 0) - (screenIndexRef.current ?? 0) - modalNavigatorsCount; setIsScreenBlurred(navigationIndex >= 1); }); return () => unsubscribe(); From 413e777ef3fd8d11270221f7957a9140f0a86a43 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 11 Oct 2024 11:55:13 +0200 Subject: [PATCH 095/257] Fix navigating from SearchRouterList to chat --- src/components/Search/SearchRouter/SearchRouterList.tsx | 3 +-- src/components/Search/index.tsx | 8 +------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/components/Search/SearchRouter/SearchRouterList.tsx b/src/components/Search/SearchRouter/SearchRouterList.tsx index d891e3e6a9aa..ef4081281eb8 100644 --- a/src/components/Search/SearchRouter/SearchRouterList.tsx +++ b/src/components/Search/SearchRouter/SearchRouterList.tsx @@ -159,8 +159,7 @@ function SearchRouterList( // Handle selection of "Recent chat" closeAndClearRouter(); if ('reportID' in item && item?.reportID) { - // @TODO: Previously Navigation.closeAndNavigate was used here, remember to verify if it works correctly - Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(item?.reportID)); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(item?.reportID)); } else if ('login' in item) { Report.navigateToAndOpenReport(item?.login ? [item.login] : []); } diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 3c8d6260698c..7cd555ea9e4e 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -91,8 +91,8 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr const {isSmallScreenWidth, isLargeScreenWidth} = useResponsiveLayout(); const navigation = useNavigation>(); const lastSearchResultsRef = useRef>(); - const {selectionMode} = useMobileSelectionMode(false); const {setCurrentSearchHash, setSelectedTransactions, selectedTransactions, clearSelectedTransactions, setShouldShowStatusBarLoading} = useSearchContext(); + const {selectionMode} = useMobileSelectionMode(); const [offset, setOffset] = useState(0); const {type, status, sortBy, sortOrder, hash} = queryJSON; @@ -379,11 +379,6 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr onTurnOnSelectionMode={(item) => item && toggleTransaction(item)} onCheckboxPress={toggleTransaction} onSelectAll={toggleAllTransactions} - isSelected={(item) => - status !== CONST.SEARCH.STATUS.EXPENSE.ALL && SearchUtils.isReportListItemType(item) - ? item.transactions.some((transaction) => selectedTransactions[transaction.keyForList]?.isSelected) - : !!item.isSelected - } customListHeader={ !isLargeScreenWidth ? null : ( ) } - shouldAutoTurnOff={false} onScroll={onSearchListScroll} canSelectMultiple={type !== CONST.SEARCH.DATA_TYPES.CHAT && canSelectMultiple} customListHeaderHeight={searchHeaderHeight} From d2e211914c11e61529a30d486b7a2b52aed7c9ba Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 11 Oct 2024 13:25:30 +0200 Subject: [PATCH 096/257] Handle deeplinking to the url with policyID --- src/libs/Navigation/linkTo/index.ts | 32 +++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 40d51cd6ec9f..49db0ef4db0c 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -1,8 +1,8 @@ import {getActionFromState} from '@react-navigation/core'; -import type {NavigationContainerRef, NavigationState, PartialState} from '@react-navigation/native'; +import type {NavigationContainerRef, NavigationState, PartialState, StackActionType} from '@react-navigation/native'; import {findFocusedRoute} from '@react-navigation/native'; import {shallowCompare} from '@libs/ObjectUtils'; -import {getPathWithoutPolicyID} from '@libs/PolicyUtils'; +import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import getStateFromPath from '@navigation/getStateFromPath'; import linkingConfig from '@navigation/linkingConfig'; import type {RootStackParamList, StackNavigationAction} from '@navigation/types'; @@ -10,6 +10,23 @@ import CONST from '@src/CONST'; import type {Route} from '@src/ROUTES'; import getMinimalAction from './getMinimalAction'; +function createActionWithPolicyID(action: StackActionType, policyID: string): StackActionType | undefined { + if (action.type !== 'PUSH' && action.type !== 'REPLACE') { + return; + } + + return { + ...action, + payload: { + ...action.payload, + params: { + ...action.payload.params, + policyID, + }, + }, + }; +} + function shouldDispatchAction(currentState: NavigationState, stateFromPath: PartialState>) { const currentFocusedRoute = findFocusedRoute(currentState); const targetFocusedRoute = findFocusedRoute(stateFromPath); @@ -29,6 +46,7 @@ export default function linkTo(navigation: NavigationContainerRef Date: Mon, 14 Oct 2024 14:47:24 +0200 Subject: [PATCH 097/257] Remove unused code, add fixes to search --- .../CustomRouter.ts | 13 +- src/libs/Navigation/dismissModal.ts | 41 ----- .../index.android.ts | 55 +------ src/libs/Navigation/switchPolicyID.ts | 146 ------------------ src/pages/Search/SearchPage.tsx | 98 ++++++------ 5 files changed, 58 insertions(+), 295 deletions(-) delete mode 100644 src/libs/Navigation/dismissModal.ts delete mode 100644 src/libs/Navigation/switchPolicyID.ts diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 6f68b7a8e373..19b8c8a160f8 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -160,7 +160,6 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { } if (action.type === 'PUSH' && action.payload.name === SCREENS.SEARCH.CENTRAL_PANE) { - const policyID = getPolicyIDFromState(state as State); const currentParams = action.payload.params as RootStackParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; const queryJSON = SearchUtils.buildSearchQueryJSON(currentParams.q); @@ -168,10 +167,16 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { return null; } - if (policyID) { - queryJSON.policyID = policyID; + if (!queryJSON.policyID) { + const policyID = getPolicyIDFromState(state as State); + + if (policyID) { + queryJSON.policyID = policyID; + } else { + delete queryJSON.policyID; + } } else { - delete queryJSON.policyID; + setActiveWorkspaceID(queryJSON.policyID); } const modifiedAction = { diff --git a/src/libs/Navigation/dismissModal.ts b/src/libs/Navigation/dismissModal.ts deleted file mode 100644 index ff24f8f944b1..000000000000 --- a/src/libs/Navigation/dismissModal.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type {NavigationContainerRef} from '@react-navigation/native'; -import {StackActions} from '@react-navigation/native'; -import Log from '@libs/Log'; -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; -import type {RootStackParamList} from './types'; - -// This function is in a separate file than Navigation.ts to avoid cyclic dependency. - -/** - * Dismisses the last modal stack if there is any - */ -function dismissModal(navigationRef: NavigationContainerRef) { - if (!navigationRef.isReady()) { - return; - } - - const state = navigationRef.getState(); - const lastRoute = state.routes.at(-1); - switch (lastRoute?.name) { - case NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR: - case NAVIGATORS.LEFT_MODAL_NAVIGATOR: - case NAVIGATORS.RIGHT_MODAL_NAVIGATOR: - case NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR: - case NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR: - case SCREENS.NOT_FOUND: - case SCREENS.ATTACHMENTS: - case SCREENS.TRANSACTION_RECEIPT: - case SCREENS.PROFILE_AVATAR: - case SCREENS.WORKSPACE_AVATAR: - case SCREENS.REPORT_AVATAR: - case SCREENS.CONCIERGE: - navigationRef.dispatch({...StackActions.pop(), target: state.key}); - break; - default: { - Log.hmmm('[Navigation] dismissModal failed because there is no modal stack to dismiss'); - } - } -} - -export default dismissModal; diff --git a/src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts b/src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts index f7c2140b1117..04c1791145ca 100644 --- a/src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts +++ b/src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts @@ -1,68 +1,15 @@ -import {findFocusedRoute, StackActions} from '@react-navigation/native'; -import type {StackScreenProps} from '@react-navigation/stack'; import {BackHandler, NativeModules} from 'react-native'; -import getTopmostCentralPaneRoute from '@navigation/getTopmostCentralPaneRoute'; import navigationRef from '@navigation/navigationRef'; -import type {BottomTabNavigatorParamList, RootStackParamList, State} from '@navigation/types'; -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; - -type SearchPageProps = StackScreenProps; // We need to do some custom handling for the back button on Android for actions related to the search page. function setupCustomAndroidBackHandler() { const onBackPress = () => { const rootState = navigationRef.getRootState(); - const bottomTabRoute = rootState?.routes?.find((route) => route.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR); - const bottomTabRoutes = bottomTabRoute?.state?.routes; - const focusedRoute = findFocusedRoute(rootState); - - // Shouldn't happen but for type safety. - if (!bottomTabRoutes) { - return false; - } - - const isLastScreenOnStack = bottomTabRoutes.length === 1 && rootState?.routes?.length === 1; - + const isLastScreenOnStack = rootState?.routes?.length === 1 && (rootState?.routes.at(0)?.state?.routes?.length ?? 1) === 1; if (NativeModules.HybridAppModule && isLastScreenOnStack) { NativeModules.HybridAppModule.exitApp(); } - // Handle back press on the search page. - // We need to pop two screens, from the central pane and from the bottom tab. - if (bottomTabRoutes[bottomTabRoutes.length - 1].name === SCREENS.SEARCH.BOTTOM_TAB && focusedRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { - navigationRef.dispatch({...StackActions.pop(), target: bottomTabRoute?.state?.key}); - navigationRef.dispatch({...StackActions.pop()}); - - const centralPaneRouteAfterPop = getTopmostCentralPaneRoute({routes: [rootState?.routes?.at(-2)]} as State); - const bottomTabRouteAfterPop = bottomTabRoutes.at(-2); - - // It's possible that central pane search is desynchronized with the bottom tab search. - // e.g. opening a tab different from search will wipe out central pane screens. - // In that case we have to push the proper one. - if ( - bottomTabRouteAfterPop && - bottomTabRouteAfterPop.name === SCREENS.SEARCH.BOTTOM_TAB && - (!centralPaneRouteAfterPop || centralPaneRouteAfterPop.name !== SCREENS.SEARCH.CENTRAL_PANE) - ) { - const searchParams = bottomTabRoutes[bottomTabRoutes.length - 2].params as SearchPageProps['route']['params']; - navigationRef.dispatch({...StackActions.push(SCREENS.SEARCH.CENTRAL_PANE, searchParams)}); - } - - return true; - } - - // Handle back press to go back to the search page. - // It's possible that central pane search is desynchronized with the bottom tab search. - // e.g. opening a tab different from search will wipe out central pane screens. - // In that case we have to push the proper one. - if (bottomTabRoutes && bottomTabRoutes?.length >= 2 && bottomTabRoutes[bottomTabRoutes.length - 2].name === SCREENS.SEARCH.BOTTOM_TAB && rootState?.routes?.length === 1) { - const searchParams = bottomTabRoutes[bottomTabRoutes.length - 2].params as SearchPageProps['route']['params']; - navigationRef.dispatch({...StackActions.push(SCREENS.SEARCH.CENTRAL_PANE, searchParams)}); - navigationRef.dispatch({...StackActions.pop(), target: bottomTabRoute?.state?.key}); - return true; - } - // Handle all other cases with default handler. return false; }; diff --git a/src/libs/Navigation/switchPolicyID.ts b/src/libs/Navigation/switchPolicyID.ts deleted file mode 100644 index 5ccc2da54418..000000000000 --- a/src/libs/Navigation/switchPolicyID.ts +++ /dev/null @@ -1,146 +0,0 @@ -import {getActionFromState} from '@react-navigation/core'; -import type {NavigationAction, NavigationContainerRef, NavigationState, PartialState} from '@react-navigation/native'; -import {getPathFromState} from '@react-navigation/native'; -import type {Writable} from 'type-fest'; -import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import {isCentralPaneName} from '@libs/NavigationUtils'; -import * as SearchUtils from '@libs/SearchUtils'; -import CONST from '@src/CONST'; -import type {Route} from '@src/ROUTES'; -import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; -import getStateFromPath from './getStateFromPath'; -import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute'; -import linkingConfig from './linkingConfig'; -import type {NavigationRoot, RootStackParamList, StackNavigationAction, State, SwitchPolicyIDParams} from './types'; - -type ActionPayloadParams = { - screen?: string; - params?: unknown; - path?: string; -}; - -type CentralPaneRouteParams = Record & {policyID?: string; q?: string; reportID?: string}; - -function checkIfActionPayloadNameIsEqual(action: Writable, screenName: string) { - return action?.payload && 'name' in action.payload && action?.payload?.name === screenName; -} - -function getActionForBottomTabNavigator(action: StackNavigationAction, state: NavigationState, policyID?: string): Writable | undefined { - const bottomTabNavigatorRoute = state.routes.at(0); - - if (!bottomTabNavigatorRoute || bottomTabNavigatorRoute.state === undefined || !action || action.type !== CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { - return; - } - - let name: string | undefined; - let params: Record; - if (isCentralPaneName(action.payload.name)) { - name = action.payload.name; - params = action.payload.params as Record; - } else { - const actionPayloadParams = action.payload.params as ActionPayloadParams; - name = actionPayloadParams.screen; - params = actionPayloadParams?.params as Record; - } - - if (name === SCREENS.SEARCH.CENTRAL_PANE) { - name = SCREENS.SEARCH.BOTTOM_TAB; - } else if (!params) { - params = {policyID}; - } else { - params.policyID = policyID; - } - - return { - type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - payload: { - name, - params, - }, - target: bottomTabNavigatorRoute.state.key, - }; -} - -export default function switchPolicyID(navigation: NavigationContainerRef | null, {policyID, route}: SwitchPolicyIDParams) { - if (!navigation) { - throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); - } - let root: NavigationRoot = navigation; - let current: NavigationRoot | undefined; - - // Traverse up to get the root navigation - // eslint-disable-next-line no-cond-assign - while ((current = root.getParent())) { - root = current; - } - - const rootState = navigation.getRootState() as NavigationState; - const topmostCentralPaneRoute = getTopmostCentralPaneRoute(rootState); - let newPath = route ?? getPathFromState({routes: rootState.routes} as State, linkingConfig.config); - - // Currently, the search page displayed in the bottom tab has the same URL as the page in the central pane, so we need to redirect to the correct search route. - // Here's the configuration: src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx - const isOpeningSearchFromBottomTab = !route && topmostCentralPaneRoute?.name === SCREENS.SEARCH.CENTRAL_PANE; - if (isOpeningSearchFromBottomTab) { - newPath = ROUTES.SEARCH_CENTRAL_PANE.getRoute({query: SearchUtils.buildCannedSearchQuery()}); - } - const stateFromPath = getStateFromPath(newPath as Route) as PartialState>; - const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); - - const actionForBottomTabNavigator = getActionForBottomTabNavigator(action, rootState, policyID); - - if (!actionForBottomTabNavigator) { - return; - } - - root.dispatch(actionForBottomTabNavigator); - - // If path is passed to this method, it means that screen is pushed to the Central Pane from another place in code - if (route) { - return; - } - - // The correct route for SearchPage is located in the CentralPane - const shouldAddToCentralPane = !getIsNarrowLayout() || isOpeningSearchFromBottomTab; - - // If the layout is wide we need to push matching central pane route to the stack. - if (shouldAddToCentralPane) { - const params: CentralPaneRouteParams = {...topmostCentralPaneRoute?.params}; - - if (isOpeningSearchFromBottomTab && params.q) { - delete params.policyID; - const queryJSON = SearchUtils.buildSearchQueryJSON(params.q); - - if (policyID) { - if (queryJSON) { - queryJSON.policyID = policyID; - params.q = SearchUtils.buildSearchQueryString(queryJSON); - } - } else if (queryJSON) { - delete queryJSON.policyID; - params.q = SearchUtils.buildSearchQueryString(queryJSON); - } - } - - // If the user is on the home page and changes the current workspace, then should be displayed a report from the selected workspace. - // To achieve that, it's necessary to navigate without the reportID param. - if (checkIfActionPayloadNameIsEqual(actionForBottomTabNavigator, SCREENS.HOME)) { - delete params.reportID; - } - - root.dispatch({ - type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - payload: { - name: topmostCentralPaneRoute?.name, - params, - }, - }); - } else { - // If the layout is small we need to pop everything from the central pane so the bottom tab navigator is visible. - root.dispatch({ - type: 'POP_TO_TOP', - target: rootState.key, - }); - } -} diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index d7c06dc689ef..267b10f22d97 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -55,60 +55,58 @@ function SearchPage({route}: SearchPageProps) { } return ( - - - {queryJSON && ( - - - {/* {!selectionMode?.isEnabled && queryJSON ? ( */} - {queryJSON ? ( - - - - - ) : ( - { - clearSelectedTransactions(); - turnOffMobileSelectionMode(); - }} + {queryJSON && ( + + + {/* {!selectionMode?.isEnabled && queryJSON ? ( */} + {queryJSON ? ( + + - )} - - - - - + + ) : ( + { + clearSelectedTransactions(); + turnOffMobileSelectionMode(); + }} /> - - + )} + - )} - - + + + + + + + )} + ); } From 1e1e06bc0f4f8d5dab214c96345439563da21c72 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 14 Oct 2024 15:55:26 +0200 Subject: [PATCH 098/257] Fix sidebar tests --- tests/unit/SidebarOrderTest.ts | 1 - tests/unit/SidebarTest.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/unit/SidebarOrderTest.ts b/tests/unit/SidebarOrderTest.ts index 1de2654c09bf..ca38f9b8e64e 100644 --- a/tests/unit/SidebarOrderTest.ts +++ b/tests/unit/SidebarOrderTest.ts @@ -15,7 +15,6 @@ import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatch // Be sure to include the mocked Permissions and Expensicons libraries or else the beta tests won't work jest.mock('@libs/Permissions'); jest.mock('@components/Icon/Expensicons'); -jest.mock('@src/hooks/useActiveWorkspaceFromNavigationState'); jest.mock('@src/hooks/useResponsiveLayout'); describe('Sidebar', () => { diff --git a/tests/unit/SidebarTest.ts b/tests/unit/SidebarTest.ts index 2c8d28c537c6..0163d175a1ce 100644 --- a/tests/unit/SidebarTest.ts +++ b/tests/unit/SidebarTest.ts @@ -13,7 +13,6 @@ import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatch // Be sure to include the mocked Permissions and Expensicons libraries or else the beta tests won't work jest.mock('@src/libs/Permissions'); -jest.mock('@src/hooks/useActiveWorkspaceFromNavigationState'); jest.mock('@src/components/Icon/Expensicons'); const TEST_USER_ACCOUNT_ID = 1; From cd5cf441d3db78dee944a9932d5b83bcdfb03578 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 14 Oct 2024 16:16:08 +0200 Subject: [PATCH 099/257] Add ts fixes --- .../CustomRouter.ts | 190 +++++++++--------- src/libs/Navigation/linkTo/index.ts | 2 +- .../linkingConfig/getAdaptedStateFromPath.ts | 4 +- .../subscribePushNotification/index.ts | 6 +- 4 files changed, 97 insertions(+), 105 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts index b57d8c3d9faa..0dd55191dd73 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts @@ -1,108 +1,104 @@ import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; import {findFocusedRoute, getPathFromState, StackRouter} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/routers'; -import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import * as Localize from '@libs/Localize'; -import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; -import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; import linkingConfig from '@libs/Navigation/linkingConfig'; -import getAdaptedStateFromPath from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; import type {PlatformStackRouterOptions} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; -import {isCentralPaneName, isOnboardingFlowName} from '@libs/NavigationUtils'; +import type {RootStackParamList} from '@libs/Navigation/types'; +import {isOnboardingFlowName} from '@libs/NavigationUtils'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; - -function insertRootRoute(state: State, routeToInsert: NavigationPartialRoute) { - const nonModalRoutes = state.routes.filter( - (route) => route.name !== NAVIGATORS.RIGHT_MODAL_NAVIGATOR && route.name !== NAVIGATORS.LEFT_MODAL_NAVIGATOR && route.name !== NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR, - ); - const modalRoutes = state.routes.filter( - (route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || route.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR || route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR, - ); - - // It's safe to modify this state before returning in getRehydratedState. - - // @ts-expect-error Updating read only property - // noinspection JSConstantReassignment - state.routes = [...nonModalRoutes, routeToInsert, ...modalRoutes]; // eslint-disable-line - - // @ts-expect-error Updating read only property - // noinspection JSConstantReassignment - state.index = state.routes.length - 1; // eslint-disable-line - - // @ts-expect-error Updating read only property - // noinspection JSConstantReassignment - state.stale = true; // eslint-disable-line -} - -function compareAndAdaptState(state: StackNavigationState) { - // If the state of the last path is not defined the getPathFromState won't work correctly. - if (!state?.routes.at(-1)?.state) { - return; - } - // We need to be sure that the bottom tab state is defined. - const topmostBottomTabRoute = getTopmostBottomTabRoute(state); - const isNarrowLayout = getIsNarrowLayout(); - - // This solutions is heuristics and will work for our cases. We may need to improve it in the future if we will have more cases to handle. - if (topmostBottomTabRoute && !isNarrowLayout) { - const fullScreenRoute = state.routes.find((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR); - - // If there is fullScreenRoute we don't need to add anything. - if (fullScreenRoute) { - return; - } - - // We will generate a template state and compare the current state with it. - // If there is a difference in the screens that should be visible under the overlay, we will add the screen from templateState to the current state. - const pathFromCurrentState = getPathFromState(state, linkingConfig.config); - const {adaptedState: templateState} = getAdaptedStateFromPath(pathFromCurrentState, linkingConfig.config); - - if (!templateState) { - return; - } - - const templateFullScreenRoute = templateState.routes.find((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR); - - // If templateFullScreenRoute is defined, and full screen route is not in the state, we need to add it. - if (templateFullScreenRoute) { - insertRootRoute(state, templateFullScreenRoute); - return; - } - - const topmostCentralPaneRoute = state.routes.filter((route) => isCentralPaneName(route.name)).at(-1); - const templateCentralPaneRoute = templateState.routes.find((route) => isCentralPaneName(route.name)); - - const topmostCentralPaneRouteExtracted = getTopmostCentralPaneRoute(state); - const templateCentralPaneRouteExtracted = getTopmostCentralPaneRoute(templateState as State); - - // If there is no templateCentralPaneRoute, we don't have anything to add. - if (!templateCentralPaneRoute) { - return; - } - - // If there is no topmostCentralPaneRoute in the state and template state has one, we need to add it. - if (!topmostCentralPaneRoute) { - insertRootRoute(state, templateCentralPaneRoute); - return; - } - - // If there is central pane route in state and template state has one, we need to check if they are the same. - if (topmostCentralPaneRouteExtracted && templateCentralPaneRouteExtracted && topmostCentralPaneRouteExtracted.name !== templateCentralPaneRouteExtracted.name) { - // Not every RHP screen has matching central pane defined. In that case we use the REPORT screen as default for initial screen. - // But we don't want to override the central pane for those screens as they may be opened with different central panes under the overlay. - // e.g. i-know-a-teacher may be opened with different central panes under the overlay - if (templateCentralPaneRouteExtracted.name === SCREENS.REPORT) { - return; - } - insertRootRoute(state, templateCentralPaneRoute); - } - } -} +// @TODO: Verify if these functions are still needed + +// function insertRootRoute(state: State, routeToInsert: NavigationPartialRoute) { +// const nonModalRoutes = state.routes.filter( +// (route) => route.name !== NAVIGATORS.RIGHT_MODAL_NAVIGATOR && route.name !== NAVIGATORS.LEFT_MODAL_NAVIGATOR && route.name !== NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR, +// ); +// const modalRoutes = state.routes.filter( +// (route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || route.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR || route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR, +// ); + +// // It's safe to modify this state before returning in getRehydratedState. + +// // @ts-expect-error Updating read only property +// // noinspection JSConstantReassignment +// state.routes = [...nonModalRoutes, routeToInsert, ...modalRoutes]; // eslint-disable-line + +// // @ts-expect-error Updating read only property +// // noinspection JSConstantReassignment +// state.index = state.routes.length - 1; // eslint-disable-line + +// // @ts-expect-error Updating read only property +// // noinspection JSConstantReassignment +// state.stale = true; // eslint-disable-line +// } + +// function compareAndAdaptState(state: StackNavigationState) { +// // If the state of the last path is not defined the getPathFromState won't work correctly. +// if (!state?.routes.at(-1)?.state) { +// return; +// } + +// // We need to be sure that the bottom tab state is defined. +// const topmostBottomTabRoute = getTopmostBottomTabRoute(state); +// const isNarrowLayout = getIsNarrowLayout(); + +// // This solutions is heuristics and will work for our cases. We may need to improve it in the future if we will have more cases to handle. +// if (topmostBottomTabRoute && !isNarrowLayout) { +// const fullScreenRoute = state.routes.find((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR); + +// // If there is fullScreenRoute we don't need to add anything. +// if (fullScreenRoute) { +// return; +// } + +// // We will generate a template state and compare the current state with it. +// // If there is a difference in the screens that should be visible under the overlay, we will add the screen from templateState to the current state. +// const pathFromCurrentState = getPathFromState(state, linkingConfig.config); +// const {adaptedState: templateState} = getAdaptedStateFromPath(pathFromCurrentState, linkingConfig.config); + +// if (!templateState) { +// return; +// } + +// const templateFullScreenRoute = templateState.routes.find((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR); + +// // If templateFullScreenRoute is defined, and full screen route is not in the state, we need to add it. +// if (templateFullScreenRoute) { +// insertRootRoute(state, templateFullScreenRoute); +// return; +// } + +// const topmostCentralPaneRoute = state.routes.filter((route) => isCentralPaneName(route.name)).at(-1); +// const templateCentralPaneRoute = templateState.routes.find((route) => isCentralPaneName(route.name)); + +// const topmostCentralPaneRouteExtracted = getTopmostCentralPaneRoute(state); +// const templateCentralPaneRouteExtracted = getTopmostCentralPaneRoute(templateState as State); + +// // If there is no templateCentralPaneRoute, we don't have anything to add. +// if (!templateCentralPaneRoute) { +// return; +// } + +// // If there is no topmostCentralPaneRoute in the state and template state has one, we need to add it. +// if (!topmostCentralPaneRoute) { +// insertRootRoute(state, templateCentralPaneRoute); +// return; +// } + +// // If there is central pane route in state and template state has one, we need to check if they are the same. +// if (topmostCentralPaneRouteExtracted && templateCentralPaneRouteExtracted && topmostCentralPaneRouteExtracted.name !== templateCentralPaneRouteExtracted.name) { +// // Not every RHP screen has matching central pane defined. In that case we use the REPORT screen as default for initial screen. +// // But we don't want to override the central pane for those screens as they may be opened with different central panes under the overlay. +// // e.g. i-know-a-teacher may be opened with different central panes under the overlay +// if (templateCentralPaneRouteExtracted.name === SCREENS.REPORT) { +// return; +// } +// insertRootRoute(state, templateCentralPaneRoute); +// } +// } +// } function shouldPreventReset(state: StackNavigationState, action: CommonActions.Action | StackActionType) { if (action.type !== CONST.NAVIGATION_ACTIONS.RESET || !action?.payload) { @@ -127,7 +123,7 @@ function CustomRouter(options: PlatformStackRouterOptions) { return { ...stackRouter, getRehydratedState(partialState: StackNavigationState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): StackNavigationState { - compareAndAdaptState(partialState); + // compareAndAdaptState(partialState); const state = stackRouter.getRehydratedState(partialState, {routeNames, routeParamList, routeGetIdList}); return state; }, diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 49db0ef4db0c..5ed9bc33c912 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -41,7 +41,7 @@ function shouldDispatchAction(currentState: NavigationState, return true; } -export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: typeof CONST.NAVIGATION.ACTION_TYPE.REPLACE) { +export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string) { if (!navigation) { throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); } diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 2685cc5fa1b3..9c883dde2219 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -2,7 +2,7 @@ import type {NavigationState, PartialState, Route} from '@react-navigation/nativ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import pick from 'lodash/pick'; import {isAnonymousUser} from '@libs/actions/Session'; -import type {NavigationPartialRoute, RootStackParamList, SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; +import type {NavigationPartialRoute, RootStackParamList, SettingsSplitNavigatorParamList, WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; @@ -85,7 +85,7 @@ function getMatchingFullScreenRouteForState(state: PartialState Date: Mon, 14 Oct 2024 16:14:37 +0200 Subject: [PATCH 100/257] Migrate FloatingActionButton to useOnyx and add small cleanups --- src/libs/actions/Policy/Policy.ts | 3 +- src/pages/home/sidebar/BottomTabAvatar.tsx | 12 +- .../FloatingActionButtonAndPopover.tsx | 138 +++++------------- 3 files changed, 38 insertions(+), 115 deletions(-) diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index ec37b2c4e1fa..5d86c30cc42a 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -73,7 +73,6 @@ import * as ReportActionsConnection from '@libs/ReportActionsConnection'; import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; -import type {PolicySelector} from '@pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover'; import * as PaymentMethods from '@userActions/PaymentMethods'; import * as PersistedRequests from '@userActions/PersistedRequests'; import CONST from '@src/CONST'; @@ -96,6 +95,8 @@ import type {OnyxData} from '@src/types/onyx/Request'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import {buildOptimisticPolicyCategories} from './Category'; +type PolicySelector = Pick; + type ReportCreationData = Record< string, { diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index 137cd0ffe876..eeaad1fd32f3 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -21,14 +21,11 @@ import AvatarWithOptionalStatus from './AvatarWithOptionalStatus'; import ProfileAvatarWithIndicator from './ProfileAvatarWithIndicator'; type BottomTabAvatarProps = { - /** Whether the create menu is open or not */ - isCreateMenuOpen?: boolean; - /** Whether the avatar is selected */ isSelected?: boolean; }; -function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomTabAvatarProps) { +function BottomTabAvatar({isSelected = false}: BottomTabAvatarProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const [account] = useOnyx(ONYXKEYS.ACCOUNT); @@ -39,11 +36,6 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT const {shouldUseNarrowLayout} = useResponsiveLayout(); const showSettingsPage = useCallback(() => { - if (isCreateMenuOpen) { - // Prevent opening Settings page when click profile avatar quickly after clicking FAB icon - return; - } - if (route.name === SCREENS.SETTINGS.WORKSPACES && shouldUseNarrowLayout) { Navigation.goUp(ROUTES.SETTINGS); return; @@ -84,7 +76,7 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT // This case also covers if there is no route to remember. Navigation.navigate(ROUTES.SETTINGS); }); - }, [isCreateMenuOpen, shouldUseNarrowLayout, route.name]); + }, [shouldUseNarrowLayout, route.name]); let children; diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx index a49b474b185e..c51df3c46329 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx @@ -1,10 +1,9 @@ import {useIsFocused as useIsFocusedOriginal, useNavigationState} from '@react-navigation/native'; import type {ImageContentFit} from 'expo-image'; -import type {ForwardedRef, RefAttributes} from 'react'; +import type {ForwardedRef} from 'react'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; -import {useOnyx, withOnyx} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; import type {SvgProps} from 'react-native-svg'; import FloatingActionButton from '@components/FloatingActionButton'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -36,7 +35,6 @@ import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; -import type * as OnyxTypes from '@src/types/onyx'; import type {QuickActionName} from '@src/types/onyx/QuickAction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -49,35 +47,7 @@ const useIsFocused = () => { return isFocused || (topmostCentralPane?.name === SCREENS.SEARCH.CENTRAL_PANE && shouldUseNarrowLayout); }; -type PolicySelector = Pick; - -type FloatingActionButtonAndPopoverOnyxProps = { - /** The list of policies the user has access to. */ - allPolicies: OnyxCollection; - - /** Whether app is in loading state */ - isLoading: OnyxEntry; - - /** Information on the last taken action to display as Quick Action */ - quickAction: OnyxEntry; - - /** The report data of the quick action */ - quickActionReport: OnyxEntry; - - /** The policy data of the quick action */ - quickActionPolicy: OnyxEntry; - - /** The current session */ - session: OnyxEntry; - - /** Personal details of all the users */ - personalDetails: OnyxEntry; - - /** Has user seen track expense training interstitial */ - hasSeenTrackTraining: OnyxEntry; -}; - -type FloatingActionButtonAndPopoverProps = FloatingActionButtonAndPopoverOnyxProps & { +type FloatingActionButtonAndPopoverProps = { /* Callback function when the menu is shown */ onShowCreateMenu?: () => void; @@ -89,18 +59,6 @@ type FloatingActionButtonAndPopoverRef = { hideCreateMenu: () => void; }; -const policySelector = (policy: OnyxEntry): PolicySelector => - (policy && { - type: policy.type, - role: policy.role, - id: policy.id, - isPolicyExpenseChatEnabled: policy.isPolicyExpenseChatEnabled, - pendingAction: policy.pendingAction, - avatarURL: policy.avatarURL, - name: policy.name, - areInvoicesEnabled: policy.areInvoicesEnabled, - }) as PolicySelector; - const getQuickActionIcon = (action: QuickActionName): React.FC => { switch (action) { case CONST.QUICK_ACTIONS.REQUEST_MANUAL: @@ -161,24 +119,9 @@ const getQuickActionTitle = (action: QuickActionName): TranslationPaths => { * Responsible for rendering the {@link PopoverMenu}, and the accompanying * FAB that can open or close the menu. */ -function FloatingActionButtonAndPopover( - { - onHideCreateMenu, - onShowCreateMenu, - isLoading = false, - allPolicies, - quickAction, - quickActionReport, - quickActionPolicy, - session, - personalDetails, - hasSeenTrackTraining, - }: FloatingActionButtonAndPopoverProps, - ref: ForwardedRef, -) { +function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: FloatingActionButtonAndPopoverProps, ref: ForwardedRef) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${quickActionReport?.reportID ?? -1}`); const [isCreateMenuActive, setIsCreateMenuActive] = useState(false); const fabRef = useRef(null); const {windowHeight} = useWindowDimensions(); @@ -186,19 +129,33 @@ function FloatingActionButtonAndPopover( const isFocused = useIsFocused(); const prevIsFocused = usePrevious(isFocused); const {isOffline} = useNetwork(); - const {canUseSpotnanaTravel, canUseCombinedTrackSubmit} = usePermissions(); - const canSendInvoice = useMemo(() => PolicyUtils.canSendInvoice(allPolicies as OnyxCollection, session?.email), [allPolicies, session?.email]); + + const [isLoading] = useOnyx(ONYXKEYS.IS_LOADING_APP); + const [policies = {}] = useOnyx(ONYXKEYS.COLLECTION.POLICY); + const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); + const [session] = useOnyx(ONYXKEYS.SESSION); + const [hasSeenTrackTraining] = useOnyx(ONYXKEYS.NVP_HAS_SEEN_TRACK_TRAINING); + const [quickAction = {}] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE); + const [quickActionReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${quickAction?.chatReportID}`); + const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${quickActionReport?.reportID ?? -1}`); + const [quickActionPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${quickActionReport?.policyID}`); + + const sessionEmail = session?.email; + const sessionAccountID = session?.accountID; + const canSendInvoice = useMemo(() => PolicyUtils.canSendInvoice(policies, sessionEmail), [policies, sessionEmail]); + + const quickActionName = quickAction.action; const quickActionAvatars = useMemo(() => { if (quickActionReport) { const avatars = ReportUtils.getIcons(quickActionReport, personalDetails); - return avatars.length <= 1 || ReportUtils.isPolicyExpenseChat(quickActionReport) ? avatars : avatars.filter((avatar) => avatar.id !== session?.accountID); + return avatars.length <= 1 || ReportUtils.isPolicyExpenseChat(quickActionReport) ? avatars : avatars.filter((avatar) => avatar.id !== sessionAccountID); } return []; // Policy is needed as a dependency in order to update the shortcut details when the workspace changes // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, [personalDetails, session?.accountID, quickActionReport, quickActionPolicy]); + }, [personalDetails, sessionAccountID, quickActionReport, quickActionPolicy]); const renderQuickActionTooltip = useCallback( () => ( @@ -214,13 +171,14 @@ function FloatingActionButtonAndPopover( if (isEmptyObject(quickActionReport)) { return ''; } - if (quickAction?.action === CONST.QUICK_ACTIONS.SEND_MONEY && quickActionAvatars.length > 0) { - const name: string = ReportUtils.getDisplayNameForParticipant(+(quickActionAvatars.at(0)?.id ?? -1), true) ?? ''; + + if (quickActionName === CONST.QUICK_ACTIONS.SEND_MONEY && quickActionAvatars.length > 0) { + const name = ReportUtils.getDisplayNameForParticipant(+(quickActionAvatars.at(0)?.id ?? -1), true) ?? ''; return translate('quickAction.paySomeone', {name}); } - const titleKey = getQuickActionTitle(quickAction?.action ?? ('' as QuickActionName)); + const titleKey = getQuickActionTitle(quickActionName ?? ('' as QuickActionName)); return titleKey ? translate(titleKey) : ''; - }, [quickAction, translate, quickActionAvatars, quickActionReport]); + }, [quickActionName, translate, quickActionAvatars, quickActionReport]); const hideQABSubtitle = useMemo(() => { if (isEmptyObject(quickActionReport)) { @@ -230,8 +188,8 @@ function FloatingActionButtonAndPopover( return false; } const displayName = personalDetails?.[quickActionAvatars.at(0)?.id ?? -1]?.firstName ?? ''; - return quickAction?.action === CONST.QUICK_ACTIONS.SEND_MONEY && displayName.length === 0; - }, [personalDetails, quickActionReport, quickAction?.action, quickActionAvatars]); + return quickActionName === CONST.QUICK_ACTIONS.SEND_MONEY && displayName.length === 0; + }, [personalDetails, quickActionReport, quickActionName, quickActionAvatars]); const navigateToQuickAction = () => { const selectOption = (onSelected: () => void, shouldRestrictAction: boolean) => { @@ -246,7 +204,7 @@ function FloatingActionButtonAndPopover( const isValidReport = !(isEmptyObject(quickActionReport) || ReportUtils.isArchivedRoom(quickActionReport, reportNameValuePairs)); const quickActionReportID = isValidReport ? quickActionReport?.reportID ?? '-1' : ReportUtils.generateReportID(); - switch (quickAction?.action) { + switch (quickActionName) { case CONST.QUICK_ACTIONS.REQUEST_MANUAL: selectOption(() => IOU.startMoneyRequest(CONST.IOU.TYPE.SUBMIT, quickActionReportID, CONST.IOU.REQUEST_TYPE.MANUAL, true), true); return; @@ -454,7 +412,7 @@ function FloatingActionButtonAndPopover( }, ] : []), - ...(!isLoading && !Policy.hasActiveChatEnabledPolicies(allPolicies) + ...(!isLoading && !Policy.hasActiveChatEnabledPolicies(policies) ? [ { displayInDefaultIconColor: true, @@ -468,10 +426,10 @@ function FloatingActionButtonAndPopover( }, ] : []), - ...(quickAction?.action + ...(quickActionName ? [ { - icon: getQuickActionIcon(quickAction?.action), + icon: getQuickActionIcon(quickActionName), text: quickActionTitle, label: translate('quickAction.header'), isLabelHoverable: false, @@ -510,32 +468,4 @@ function FloatingActionButtonAndPopover( FloatingActionButtonAndPopover.displayName = 'FloatingActionButtonAndPopover'; -export default withOnyx, FloatingActionButtonAndPopoverOnyxProps>({ - allPolicies: { - key: ONYXKEYS.COLLECTION.POLICY, - selector: policySelector, - }, - isLoading: { - key: ONYXKEYS.IS_LOADING_APP, - }, - quickAction: { - key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, - }, - quickActionReport: { - key: ({quickAction}) => `${ONYXKEYS.COLLECTION.REPORT}${quickAction?.chatReportID}`, - }, - quickActionPolicy: { - key: ({quickActionReport}) => `${ONYXKEYS.COLLECTION.POLICY}${quickActionReport?.policyID}`, - }, - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - }, - session: { - key: ONYXKEYS.SESSION, - }, - hasSeenTrackTraining: { - key: ONYXKEYS.NVP_HAS_SEEN_TRACK_TRAINING, - }, -})(forwardRef(FloatingActionButtonAndPopover)); - -export type {PolicySelector}; +export default forwardRef(FloatingActionButtonAndPopover); From 74f8e188d72d854d55b29b0f7075f156163e8fce Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 14 Oct 2024 16:49:08 +0200 Subject: [PATCH 101/257] Add lint fixes --- src/libs/Navigation/Navigation.ts | 2 +- src/libs/actions/Report.ts | 5 +---- src/pages/ChatFinderPage/index.tsx | 1 - src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx | 4 +--- src/pages/settings/InitialSettingsPage.tsx | 2 +- 5 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index b741f0d55151..c9bfd2195e8b 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -31,7 +31,7 @@ import linkTo from './linkTo'; import getMinimalAction from './linkTo/getMinimalAction'; import navigationRef from './navigationRef'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; -import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, SplitNavigatorLHNScreen, SplitNavigatorParamListType, State, StateOrRoute} from './types'; +import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, SplitNavigatorLHNScreen, SplitNavigatorParamListType, State} from './types'; const PARAMS_TO_OMIT_WHEN_COMPARING_ROUTES = ['path', 'initial', 'params', 'state', 'screen', 'policyID'] as const; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index c1e464ac3f2b..7f3d58628b69 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -69,7 +69,6 @@ import LocalNotification from '@libs/Notification/LocalNotification'; import Parser from '@libs/Parser'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PhoneNumber from '@libs/PhoneNumber'; -import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils'; import {extractPolicyIDFromPath} from '@libs/PolicyUtils'; import processReportIDDeeplink from '@libs/processReportIDDeeplink'; import * as Pusher from '@libs/Pusher/pusher'; @@ -77,7 +76,6 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportConnection from '@libs/ReportConnection'; import type {OptimisticAddCommentReportAction} from '@libs/ReportUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import {doesReportBelongToWorkspace} from '@libs/ReportUtils'; import shouldSkipDeepLinkNavigation from '@libs/shouldSkipDeepLinkNavigation'; import Visibility from '@libs/Visibility'; import CONFIG from '@src/CONFIG'; @@ -100,13 +98,12 @@ import type { } from '@src/types/onyx'; import type {Decision} from '@src/types/onyx/OriginalMessage'; import type {ConnectionName} from '@src/types/onyx/Policy'; -import type {NotificationPreference, Participants, Participant as ReportParticipant, RoomVisibility, WriteCapability} from '@src/types/onyx/Report'; import type Report from '@src/types/onyx/Report'; +import type {NotificationPreference, Participants, Participant as ReportParticipant, RoomVisibility, WriteCapability} from '@src/types/onyx/Report'; import type {Message, ReportActions} from '@src/types/onyx/ReportAction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as CachedPDFPaths from './CachedPDFPaths'; import * as Modal from './Modal'; -import navigateFromNotification from './navigateFromNotification'; import * as Session from './Session'; import * as Welcome from './Welcome'; import * as OnboardingFlow from './Welcome/OnboardingFlow'; diff --git a/src/pages/ChatFinderPage/index.tsx b/src/pages/ChatFinderPage/index.tsx index b18917e20b40..a4e98ad1b8eb 100644 --- a/src/pages/ChatFinderPage/index.tsx +++ b/src/pages/ChatFinderPage/index.tsx @@ -22,7 +22,6 @@ import * as Report from '@userActions/Report'; import Timing from '@userActions/Timing'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import ChatFinderPageFooter from './ChatFinderPageFooter'; diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx index a9377a9b9b27..2cc037bf250c 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx @@ -1,6 +1,5 @@ import React, {useEffect} from 'react'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; import ScreenWrapper from '@components/ScreenWrapper'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; @@ -12,7 +11,6 @@ import Performance from '@libs/Performance'; import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import Timing from '@userActions/Timing'; import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; import SCREENS from '@src/SCREENS'; /** @@ -27,7 +25,7 @@ function BaseSidebarScreen() { const styles = useThemeStyles(); const {activeWorkspaceID} = useActiveWorkspace(); const {translate} = useLocalize(); - const [activeWorkspace] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activeWorkspaceID ?? -1}`); + // const [activeWorkspace] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activeWorkspaceID ?? -1}`); useEffect(() => { Performance.markStart(CONST.TIMING.SIDEBAR_LOADED); diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 32ca20741d07..d78813ff535b 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -1,5 +1,6 @@ import {useNavigationState, useRoute} from '@react-navigation/native'; import React, {useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react'; +// eslint-disable-next-line no-restricted-imports import type {GestureResponderEvent, ScrollView as RNScrollView, ScrollViewProps, StyleProp, ViewStyle} from 'react-native'; import {NativeModules, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; @@ -47,7 +48,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; -import type * as OnyxTypes from '@src/types/onyx'; import type {Icon as TIcon} from '@src/types/onyx/OnyxCommon'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; From 9aed8a0a8f05d39926c87eeb219eee1a4fcbfeeb Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 15 Oct 2024 10:25:59 +0200 Subject: [PATCH 102/257] Remove shouldEnforceFallback param, add comments --- src/components/ParentNavigationSubtitle.tsx | 3 ++- .../usePrepareSplitStackNavigatorChildren.ts | 12 ++++++++++-- src/libs/Navigation/Navigation.ts | 15 ++++++++------- src/libs/actions/Report.ts | 6 ++++-- .../navigateAfterJoinRequest/index.desktop.ts | 3 ++- src/libs/navigateAfterJoinRequest/index.ts | 3 ++- src/libs/navigateAfterJoinRequest/index.web.ts | 3 ++- src/pages/home/ReportScreen.tsx | 6 ++++-- .../workspace/WorkspaceInviteMessagePage.tsx | 3 ++- src/pages/workspace/WorkspaceJoinUserPage.tsx | 3 ++- 10 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/components/ParentNavigationSubtitle.tsx b/src/components/ParentNavigationSubtitle.tsx index 997106f3e649..023ee0dc516b 100644 --- a/src/components/ParentNavigationSubtitle.tsx +++ b/src/components/ParentNavigationSubtitle.tsx @@ -44,7 +44,8 @@ function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportAct Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(parentReportID)); if (isVisibleAction && !isOffline) { // Pop the chat report screen before navigating to the linked report action. - Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(parentReportID, parentReportActionID), true); + // @TODO: Navigation.goBack was called here with shouldEnforceFallback set to true. Verify if this works correctly + Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(parentReportID, parentReportActionID)); } }} accessibilityLabel={translate('threads.parentNavigationSummary', {reportName, workspaceName})} diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts index d32e6b30f876..3637cdeded3b 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts @@ -1,3 +1,4 @@ +import type {EventMapBase, NavigationState, ParamListBase, RouteConfig} from '@react-navigation/native'; import type {StackNavigationOptions} from '@react-navigation/stack'; import {Children, isValidElement, useMemo} from 'react'; import type {ReactNode} from 'react'; @@ -6,12 +7,19 @@ export default function usePrepareSplitStackNavigatorChildren(screensNode: React return useMemo( () => Children.toArray(screensNode).map((screen: ReactNode) => { - if (isValidElement(screen) && screen?.props?.name === sidebarScreenName) { + if (!isValidElement(screen)) { + return screen; + } + + // @TODO: Fix types here + const screenProps = screen?.props as RouteConfig, EventMapBase>; + + if (screenProps?.name === sidebarScreenName) { // If we found the element we wanted, clone it with the provided prop changes. return { ...screen, props: { - ...screen.props, + ...screenProps, options: sidebarScreenOptions, }, }; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index c9bfd2195e8b..c3927891c975 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -1,7 +1,6 @@ import {getActionFromState} from '@react-navigation/core'; import type {EventArg, NavigationAction, NavigationContainerEventMap} from '@react-navigation/native'; import {CommonActions, getPathFromState, StackActions} from '@react-navigation/native'; -import lodashOmit from 'lodash/omit'; import type {OnyxEntry} from 'react-native-onyx'; import type {Writable} from 'type-fest'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; @@ -33,8 +32,6 @@ import navigationRef from './navigationRef'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, SplitNavigatorLHNScreen, SplitNavigatorParamListType, State} from './types'; -const PARAMS_TO_OMIT_WHEN_COMPARING_ROUTES = ['path', 'initial', 'params', 'state', 'screen', 'policyID'] as const; - const SPLIT_NAVIGATOR_TO_SIDEBAR_MAP: Record = { [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: SCREENS.HOME, [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: SCREENS.SETTINGS.ROOT, @@ -210,6 +207,11 @@ function navigate(route: Route = ROUTES.HOME, type?: string) { linkTo(navigationRef.current, route, type); } +function getRouteParamsToCompare(routeParams: Record) { + const {path, initial, params, state, screen, policyID, ...routeParamsToCompare} = routeParams; + return routeParamsToCompare; +} + function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | NavigationPartialRoute, minimalAction: Writable) { if (!minimalAction.payload) { return false; @@ -229,8 +231,8 @@ function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | Navi return false; } - const routeParams = lodashOmit(route.params ?? {}, PARAMS_TO_OMIT_WHEN_COMPARING_ROUTES) as Record; - const minimalActionParams = lodashOmit(minimalAction.payload.params ?? {}, PARAMS_TO_OMIT_WHEN_COMPARING_ROUTES) as Record; + const routeParams = getRouteParamsToCompare(route.params as Record); + const minimalActionParams = getRouteParamsToCompare(minimalAction.payload.params as Record); return shallowCompare(routeParams, minimalActionParams); } @@ -273,10 +275,9 @@ function goUp(fallbackRoute: Route) { /** * @param fallbackRoute - Fallback route if pop/goBack action should, but is not possible within RHP - * @param shouldEnforceFallback - Enforces navigation to fallback route * @param shouldPopToTop - Should we navigate to LHN on back press */ -function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopToTop = false) { +function goBack(fallbackRoute?: Route, shouldPopToTop = false) { if (!canNavigate('goBack')) { return; } diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 7f3d58628b69..b2f71acf4865 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1538,7 +1538,8 @@ function deleteReportComment(reportID: string, reportAction: ReportAction) { // if we are linking to the report action, and we are deleting it, and it's not a deleted parent action, // we should navigate to its report in order to not show not found page if (Navigation.isActiveRoute(ROUTES.REPORT_WITH_ID.getRoute(reportID, reportActionID)) && !isDeletedParentAction) { - Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(reportID), true); + // @TODO: Check if this method works the same as on the main branch + Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(reportID)); } } @@ -2299,7 +2300,8 @@ function navigateToConciergeChatAndDeleteReport(reportID: string, shouldPopToTop if (shouldPopToTop) { Navigation.setShouldPopAllStateOnUP(true); } - Navigation.goBack(undefined, undefined, shouldPopToTop); + // @TODO: Check if this method works the same as on the main branch + Navigation.goBack(undefined, shouldPopToTop); navigateToConciergeChat(); InteractionManager.runAfterInteractions(() => { deleteReport(reportID, shouldDeleteChildReports); diff --git a/src/libs/navigateAfterJoinRequest/index.desktop.ts b/src/libs/navigateAfterJoinRequest/index.desktop.ts index cf6d009291c8..15ebdca70a44 100644 --- a/src/libs/navigateAfterJoinRequest/index.desktop.ts +++ b/src/libs/navigateAfterJoinRequest/index.desktop.ts @@ -3,7 +3,8 @@ import Navigation from '@navigation/Navigation'; import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { - Navigation.goBack(undefined, false, true); + // @TODO: Check if this method works the same as on the main branch + Navigation.goBack(undefined, true); if (getIsSmallScreenWidth()) { Navigation.navigate(ROUTES.SETTINGS); } diff --git a/src/libs/navigateAfterJoinRequest/index.ts b/src/libs/navigateAfterJoinRequest/index.ts index 42e91d18c6ba..0425f52c1e56 100644 --- a/src/libs/navigateAfterJoinRequest/index.ts +++ b/src/libs/navigateAfterJoinRequest/index.ts @@ -2,7 +2,8 @@ import Navigation from '@navigation/Navigation'; import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { - Navigation.goBack(undefined, false, true); + // @TODO: Check if this method works the same as on the main branch + Navigation.goBack(undefined, true); Navigation.navigate(ROUTES.SETTINGS); Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); }; diff --git a/src/libs/navigateAfterJoinRequest/index.web.ts b/src/libs/navigateAfterJoinRequest/index.web.ts index cf6d009291c8..15ebdca70a44 100644 --- a/src/libs/navigateAfterJoinRequest/index.web.ts +++ b/src/libs/navigateAfterJoinRequest/index.web.ts @@ -3,7 +3,8 @@ import Navigation from '@navigation/Navigation'; import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { - Navigation.goBack(undefined, false, true); + // @TODO: Check if this method works the same as on the main branch + Navigation.goBack(undefined, true); if (getIsSmallScreenWidth()) { Navigation.navigate(ROUTES.SETTINGS); } diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 03ff5e24fa41..288c1a9c09c0 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -279,7 +279,8 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro Navigation.dismissModal(); return; } - Navigation.goBack(undefined, false, true); + // @TODO: Check if this method works the same as on the main branch + Navigation.goBack(undefined, true); }, [isInNarrowPaneModal]); let headerView = ( @@ -559,7 +560,8 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro Navigation.dismissModal(); if (Navigation.getTopmostReportId() === prevOnyxReportID) { Navigation.setShouldPopAllStateOnUP(true); - Navigation.goBack(undefined, false, true); + // @TODO: Check if this method works the same as on the main branch + Navigation.goBack(undefined, true); } if (prevReport?.parentReportID) { // Prevent navigation to the IOU/Expense Report if it is pending deletion. diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.tsx b/src/pages/workspace/WorkspaceInviteMessagePage.tsx index 65776deb7f9a..d314b1efaa11 100644 --- a/src/pages/workspace/WorkspaceInviteMessagePage.tsx +++ b/src/pages/workspace/WorkspaceInviteMessagePage.tsx @@ -82,7 +82,8 @@ function WorkspaceInviteMessagePage({policy, route, currentUserPersonalDetails}: if (isEmptyObject(policy)) { return; } - Navigation.goBack(ROUTES.WORKSPACE_INVITE.getRoute(route.params.policyID), true); + // @TODO: Check if this method works the same as on the main branch + Navigation.goBack(ROUTES.WORKSPACE_INVITE.getRoute(route.params.policyID)); // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); diff --git a/src/pages/workspace/WorkspaceJoinUserPage.tsx b/src/pages/workspace/WorkspaceJoinUserPage.tsx index d73dab51c4fe..ad8bfa1f39cd 100644 --- a/src/pages/workspace/WorkspaceJoinUserPage.tsx +++ b/src/pages/workspace/WorkspaceJoinUserPage.tsx @@ -45,7 +45,8 @@ function WorkspaceJoinUserPage({route, policy}: WorkspaceJoinUserPageProps) { } if (!isEmptyObject(policy) && !policy?.isJoinRequestPending && !PolicyUtils.isPendingDeletePolicy(policy)) { Navigation.isNavigationReady().then(() => { - Navigation.goBack(undefined, false, true); + // @TODO: Check if this method works the same as on the main branch + Navigation.goBack(undefined, true); Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID ?? '-1')); }); return; From dc6dfc2bfd227f80c532c03470581987e3d85754 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 16 Oct 2024 14:24:03 +0200 Subject: [PATCH 103/257] Refactor comments about goBack --- src/components/ParentNavigationSubtitle.tsx | 1 - src/pages/workspace/WorkspaceJoinUserPage.tsx | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ParentNavigationSubtitle.tsx b/src/components/ParentNavigationSubtitle.tsx index 023ee0dc516b..dc737eefb20c 100644 --- a/src/components/ParentNavigationSubtitle.tsx +++ b/src/components/ParentNavigationSubtitle.tsx @@ -44,7 +44,6 @@ function ParentNavigationSubtitle({parentNavigationSubtitleData, parentReportAct Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(parentReportID)); if (isVisibleAction && !isOffline) { // Pop the chat report screen before navigating to the linked report action. - // @TODO: Navigation.goBack was called here with shouldEnforceFallback set to true. Verify if this works correctly Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(parentReportID, parentReportActionID)); } }} diff --git a/src/pages/workspace/WorkspaceJoinUserPage.tsx b/src/pages/workspace/WorkspaceJoinUserPage.tsx index ad8bfa1f39cd..8d24690aad2a 100644 --- a/src/pages/workspace/WorkspaceJoinUserPage.tsx +++ b/src/pages/workspace/WorkspaceJoinUserPage.tsx @@ -46,6 +46,7 @@ function WorkspaceJoinUserPage({route, policy}: WorkspaceJoinUserPageProps) { if (!isEmptyObject(policy) && !policy?.isJoinRequestPending && !PolicyUtils.isPendingDeletePolicy(policy)) { Navigation.isNavigationReady().then(() => { // @TODO: Check if this method works the same as on the main branch + // NOTE: It probably doesn't need any params. When this method is called, shouldPopAllStateOnUP is always false Navigation.goBack(undefined, true); Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID ?? '-1')); }); From ee31d12c3d5d0d62b5274f60ff9cb5f2073adcb3 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 18 Oct 2024 08:12:39 +0200 Subject: [PATCH 104/257] Fix passing policyID to ReportsSplitNavigator when opening app from deeplink --- src/libs/Navigation/Navigation.ts | 3 +- .../linkingConfig/createSplitNavigator.ts | 2 +- .../linkingConfig/customGetPathFromState.ts | 10 +++--- .../linkingConfig/getAdaptedStateFromPath.ts | 31 ++++++++++--------- src/libs/Navigation/types.ts | 6 ++++ src/libs/NavigationUtils.ts | 27 ++++++++++++++-- 6 files changed, 56 insertions(+), 23 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index c9bfd2195e8b..44aa98afdc96 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -6,6 +6,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {Writable} from 'type-fest'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import Log from '@libs/Log'; +import {isSplitNavigatorRoute} from '@libs/NavigationUtils'; import {shallowCompare} from '@libs/ObjectUtils'; import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils'; import * as ReportConnection from '@libs/ReportConnection'; @@ -299,7 +300,7 @@ function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopT const canGoBack = navigationRef.current?.canGoBack(); - if (!canGoBack && lastRoute?.name.endsWith('SplitNavigator') && lastRoute?.state?.routes?.length === 1) { + if (!canGoBack && isSplitNavigatorRoute(lastRoute as NavigationPartialRoute) && lastRoute?.state?.routes?.length === 1) { const splitNavigatorName = lastRoute?.name as keyof SplitNavigatorParamListType; const name = SPLIT_NAVIGATOR_TO_SIDEBAR_MAP[splitNavigatorName]; const params = getSidebarScreenParams(lastRoute); diff --git a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts b/src/libs/Navigation/linkingConfig/createSplitNavigator.ts index aa1a1bef6760..c2d09d28dc87 100644 --- a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts +++ b/src/libs/Navigation/linkingConfig/createSplitNavigator.ts @@ -10,7 +10,7 @@ const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState( splitNavigatorLHN: NavigationPartialRoute, route?: NavigationPartialRoute>, - splitNavigatorParams?: SplitNavigatorParamListType[SplitNavigatorByLHN], + splitNavigatorParams?: Record, ): NavigationPartialRoute> { const routes = []; diff --git a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts index 74c38d130ad6..546f209cdb25 100644 --- a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts +++ b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts @@ -1,21 +1,21 @@ import {getPathFromState} from '@react-navigation/native'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; -import {removePolicyIDParamFromState} from '@libs/NavigationUtils'; +import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; +import {isFullScreenRoute, removePolicyIDParamFromState} from '@libs/NavigationUtils'; import NAVIGATORS from '@src/NAVIGATORS'; const customGetPathFromState: typeof getPathFromState = (state, options) => { // For the Home page we should remove policyID from the params, because on small screens it's displayed twice in the URL const stateWithoutPolicyID = removePolicyIDParamFromState(state as State); const path = getPathFromState(stateWithoutPolicyID, options); - const topmostRoute = state.routes.at(-1); + const topmostSplitOrSearchRoute = state.routes.findLast((route) => isFullScreenRoute(route as NavigationPartialRoute)); - const shouldAddPolicyID = !!topmostRoute && topmostRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; + const shouldAddPolicyID = topmostSplitOrSearchRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; if (!shouldAddPolicyID) { return path; } - const policyID = topmostRoute.params && `policyID` in topmostRoute.params ? (topmostRoute.params.policyID as string) : undefined; + const policyID = topmostSplitOrSearchRoute.params && `policyID` in topmostSplitOrSearchRoute.params ? (topmostSplitOrSearchRoute.params.policyID as string) : undefined; return `${policyID ? `/w/${policyID}` : ''}${path}`; }; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 9c883dde2219..ceb9aa9ca625 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -3,6 +3,7 @@ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import pick from 'lodash/pick'; import {isAnonymousUser} from '@libs/actions/Session'; import type {NavigationPartialRoute, RootStackParamList, SettingsSplitNavigatorParamList, WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; +import {isFullScreenRoute} from '@libs/NavigationUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; @@ -32,9 +33,11 @@ function isRouteWithReportID(route: NavigationPartialRoute): route is Route>) { +function getMatchingFullScreenRouteForState(state: PartialState>, policyID?: string) { const focusedRoute = findFocusedRoute(state); + const reportSplitParams = policyID ? {policyID} : undefined; + if (!focusedRoute) { return undefined; } @@ -57,7 +60,7 @@ function getMatchingFullScreenRouteForState(state: PartialState>); + return getMatchingFullScreenRouteForState(stateForBackTo as PartialState>, policyID); } if (RELATIONS.SEARCH_TO_RHP.includes(focusedRoute.name)) { @@ -71,9 +74,13 @@ function getMatchingFullScreenRouteForState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { const fullScreenRoute = state.routes.find(isFullScreenRoute); const reportsSplitNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); @@ -159,8 +161,7 @@ function getAdaptedState(state: PartialState // If there is no full screen route in the root, we want to add it. if (!fullScreenRoute) { - const matchingRootRoute = getMatchingFullScreenRouteForState(state); - + const matchingRootRoute = getMatchingFullScreenRouteForState(state, policyID); // If there is a matching root route, add it to the state. if (matchingRootRoute) { return { @@ -168,9 +169,11 @@ function getAdaptedState(state: PartialState }; } + const reportSplitParams = policyID ? {policyID} : undefined; + // If not, add the default full screen route. return { - adaptedState: getRoutesWithIndex([{name: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR}, ...state.routes]), + adaptedState: getRoutesWithIndex([{name: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, params: reportSplitParams}, ...state.routes]), }; } diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index aae0c52adbf0..c4c88fb99fa6 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1581,8 +1581,12 @@ type CentralPaneName = keyof CentralPaneScreensParamList; type OnboardingFlowName = keyof OnboardingModalNavigatorParamList; +type SplitNavigatorName = keyof SplitNavigatorParamListType; + type SplitNavigatorScreenName = keyof (WorkspaceSplitNavigatorParamList & SettingsSplitNavigatorParamList & ReportsSplitNavigatorParamList); +type FullScreenName = SplitNavigatorName | typeof SCREENS.SEARCH.CENTRAL_PANE; + type SwitchPolicyIDParams = { policyID?: string; route?: Routes; @@ -1657,7 +1661,9 @@ export type { RestrictedActionParamList, MissingPersonalDetailsParamList, DebugParamList, + SplitNavigatorName, SplitNavigatorScreenName, + FullScreenName, SplitNavigatorLHNScreen, SplitNavigatorParamListType, SplitNavigatorByLHN, diff --git a/src/libs/NavigationUtils.ts b/src/libs/NavigationUtils.ts index ea1710b9931c..e11255314c86 100644 --- a/src/libs/NavigationUtils.ts +++ b/src/libs/NavigationUtils.ts @@ -1,7 +1,14 @@ import cloneDeep from 'lodash/cloneDeep'; +import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import getTopmostBottomTabRoute from './Navigation/getTopmostBottomTabRoute'; -import type {CentralPaneName, OnboardingFlowName, RootStackParamList, State} from './Navigation/types'; +import type {CentralPaneName, FullScreenName, NavigationPartialRoute, OnboardingFlowName, RootStackParamList, SplitNavigatorName, State} from './Navigation/types'; + +const SPLIT_NAVIGATORS = [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]; + +const SPLIT_NAVIGATORS_SET = new Set(SPLIT_NAVIGATORS); + +const FULL_SCREEN_ROUTES_SET = new Set([...SPLIT_NAVIGATORS, SCREENS.SEARCH.CENTRAL_PANE]); const CENTRAL_PANE_SCREEN_NAMES = new Set([ SCREENS.SETTINGS.WORKSPACES, @@ -43,4 +50,20 @@ function isOnboardingFlowName(screen: string | undefined): screen is OnboardingF return ONBOARDING_SCREEN_NAMES.has(screen as OnboardingFlowName); } -export {isCentralPaneName, removePolicyIDParamFromState, isOnboardingFlowName}; +function isSplitNavigatorRoute(route: NavigationPartialRoute | undefined): route is NavigationPartialRoute { + if (!route?.name) { + return false; + } + + return SPLIT_NAVIGATORS_SET.has(route.name as SplitNavigatorName); +} + +function isFullScreenRoute(route: NavigationPartialRoute | undefined): route is NavigationPartialRoute { + if (!route?.name) { + return false; + } + + return FULL_SCREEN_ROUTES_SET.has(route.name as FullScreenName); +} + +export {isCentralPaneName, removePolicyIDParamFromState, isOnboardingFlowName, isFullScreenRoute, isSplitNavigatorRoute}; From b6b4ad83250dbd29da407330841ef9769eb24e46 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 18 Oct 2024 08:13:23 +0200 Subject: [PATCH 105/257] Fix passsing backTo from SCREENS.WORKSPACE.PROFILE to SCREENS.WORKSPACE.INITIAL --- .../createSplitStackNavigator/SplitStackRouter.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts index 6e97bb18cfaa..8ff509cd5269 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts @@ -4,6 +4,7 @@ import pick from 'lodash/pick'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import getParamsFromRoute from '@libs/Navigation/linkingConfig/getParamsFromRoute'; import navigationRef from '@libs/Navigation/navigationRef'; +import SCREENS from '@src/SCREENS'; import type {SplitStackNavigatorRouterOptions} from './types'; import {getPreservedSplitNavigatorState} from './usePreserveSplitNavigatorState'; @@ -26,6 +27,16 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc // - defaultCentralScreen to cover central pane. if (!isAtLeastOneInState(state, sidebarScreen) && !isNarrowLayout) { const paramsFromRoute = getParamsFromRoute(sidebarScreen); + let params = pick(lastRoute?.params, paramsFromRoute); + + // On a wide screen the backTo param has to be passed to the sidebar screen (SCREENS.WORKSPACE.INITIAL), because the back action is performed from this page + if (lastRoute?.name === SCREENS.WORKSPACE.PROFILE) { + const hasRouteBackToParam = lastRoute?.params && 'backTo' in lastRoute.params; + + if (hasRouteBackToParam) { + params = {...params, backTo: lastRoute.params.backTo}; + } + } // @ts-expect-error Updating read only property // noinspection JSConstantReassignment @@ -37,7 +48,7 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc state.routes.unshift({ name: sidebarScreen, // This handles the case where the sidebar should have params included in the central screen e.g. policyID for workspace initial. - params: pick(lastRoute?.params, paramsFromRoute), + params, }); } } From 356519c8cfa28b7f7a0a86ea91a1cd38b99c55f9 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 18 Oct 2024 13:06:26 +0200 Subject: [PATCH 106/257] changes in doc --- contributingGuides/NAVIGATION.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index e91cb3e473ef..c04696b7ad1d 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -212,9 +212,8 @@ There is no minimal action for deeplinking directly to the `Profile` screen. But ### Tests #### There should be a proper report under attachment screen after reload -narrow layout: -1. Open any report with image attachment. +1. Open any report with image attachment on narrow layout. 2. Open attachment. 3. Reload the page. 4. Verify that after pressing back arrow in the header you are on the report where you sent the attachment. @@ -222,14 +221,14 @@ narrow layout: #### There is a proper split navigator under RHP with a sidebar screen only for screens that can be opened from the sidebar -1. Open the browser on narrow layout with url /settings/profile/status. +1. Open the browser on narrow layout with url `/settings/profile/status`. 2. Reload the page. 3. Verify that after pressing back arrow in the header you are on the settings root page. #### There is a proper split navigator under the overlay after refreshing page with RHP/LHP on wide screen -1. Open the browser on wide screen with url /settings/profile/details. +1. Open the browser on wide screen with url `/settings/profile/display-name`. 2. Verify that you can see settings profile page under the overlay of RHP. @@ -237,16 +236,19 @@ narrow layout: 1. Open the browser on wide screen. 2. Open any report. -3. Send message with url /settings/profile/details. +3. Send message with url `/settings/profile/display-name`. 4. Press the sent link 5. Verify that the settings profile screen is now visible under the overlay - #### The Workspace list page is displayed (SCREENS.SETTINGS.WORKSPACES) after clicking the Settings tab from the Workspace settings screen -1. Open the workspace settings (use a link in format: https://dev.new.expensify.com:8082/settings/workspaces/:policyID:/profile or open it using this flow Settings → Workspaces → Select any workspace) +1. Open any workspace settings (Settings → Workspaces → Select any workspace) 2. Click the Settings button on the bottom tab. -3. Verify that the Workspace list is displayed (https://dev.new.expensify.com:8082/settings/workspaces) +3. Verify that the Workspace list is displayed (`/settings/workspaces`) +4. Select any workspace again. +5. Reload the page. +6. Click the Settings button on the bottom tab. +7. Verify that the Workspace list is displayed (`/settings/workspaces`) #### The last visited screen in the settings tab is saved when switching between tabs @@ -274,13 +276,13 @@ narrow layout: 1. Open the Inbox tab. 2. Change the workspace using the workspace switcher. 3. Switch to the Search tab and verify if the workspace selected in the second step is also selected in the Search. -4. Repeat the second step. +4. Change the workspace once again. 5. Go back to the Inbox. 6. Verify if the workspace selected in the fourth step is also selected in the Inbox tab. #### Going up to the workspace list page after refreshing on the workspace settings and pressing the up button -1. Open the workspace settings from the deep link (use a link in format: https://dev.new.expensify.com:8082/settings/workspaces/:policyID:/profile) +1. Open the workspace settings from the deep link (use a link in format: `/settings/workspaces/:policyID:/profile`) 2. Click the app’s back button. 3. Verify if the workspace list is displayed. @@ -292,7 +294,7 @@ narrow layout: 4. Click the Country button. 5. Reload the page. 6. Click the app’s back button. -7. Verify if the Profile address page is displayed (https://dev.new.expensify.com:8082/settings/profile/address) +7. Verify if the Profile address page is displayed (`/settings/profile/address`) #### There is proper split navigator under the overlay after refreshing page in RHP that includes valid reportID in params @@ -330,7 +332,7 @@ Linked issue: https://github.com/Expensify/App/pull/44138 #### Navigating back from the Search page with invalid query parameters -1. Open the search page with invalid query parameters (e.g https://dev.new.expensify.com:8082/search?q=from%3a) +1. Open the search page with invalid query parameters (e.g `/search?q=from%3a`) 2. Press the app's back button on the not found page. 3. Verify that the Search page with default query parameters is displayed. @@ -338,6 +340,6 @@ Linked issue: https://github.com/Expensify/App/pull/44138 1. Open any chat. 2. If there are no messages in the chat, send a message. -3. Reply to the message you created in the thread. -4. After being redirected to the thread screen, click on the link displayed in the header. +3. Press reply in thread. +4. Press the "From" link in the displayed header. 5. Verify if the link correctly redirects to the chat opened in the first step. \ No newline at end of file From 481f5916fee85952034b8109a90a5c857f0fb267 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 18 Oct 2024 13:09:16 +0200 Subject: [PATCH 107/257] Refactor variables names in customGetPathFromState --- src/libs/Navigation/linkingConfig/customGetPathFromState.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts index 546f209cdb25..8d0134360d7d 100644 --- a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts +++ b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts @@ -7,15 +7,15 @@ const customGetPathFromState: typeof getPathFromState = (state, options) => { // For the Home page we should remove policyID from the params, because on small screens it's displayed twice in the URL const stateWithoutPolicyID = removePolicyIDParamFromState(state as State); const path = getPathFromState(stateWithoutPolicyID, options); - const topmostSplitOrSearchRoute = state.routes.findLast((route) => isFullScreenRoute(route as NavigationPartialRoute)); + const fullScreenRoute = state.routes.findLast((route) => isFullScreenRoute(route as NavigationPartialRoute)); - const shouldAddPolicyID = topmostSplitOrSearchRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; + const shouldAddPolicyID = fullScreenRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; if (!shouldAddPolicyID) { return path; } - const policyID = topmostSplitOrSearchRoute.params && `policyID` in topmostSplitOrSearchRoute.params ? (topmostSplitOrSearchRoute.params.policyID as string) : undefined; + const policyID = fullScreenRoute.params && `policyID` in fullScreenRoute.params ? (fullScreenRoute.params.policyID as string) : undefined; return `${policyID ? `/w/${policyID}` : ''}${path}`; }; From 2f137ca99e6e24ae2966fc73109757b2565a5cbb Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 18 Oct 2024 14:53:45 +0200 Subject: [PATCH 108/257] Fix getting topmost route in AddPersonalBankAccountPage, add todo comments --- src/libs/ReportUtils.ts | 1 + src/pages/AddPersonalBankAccountPage.tsx | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 4bae619d928e..b49d721d1350 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4096,6 +4096,7 @@ function navigateBackAfterDeleteTransaction(backRoute: Route | undefined, isFrom if (!backRoute) { return; } + // @TODO: Refactor this method const topmostCentralPaneRoute = Navigation.getTopMostCentralPaneRouteFromRootState(); if (topmostCentralPaneRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { Navigation.dismissModal(); diff --git a/src/pages/AddPersonalBankAccountPage.tsx b/src/pages/AddPersonalBankAccountPage.tsx index 7b0a76e59922..bcc8073a6568 100644 --- a/src/pages/AddPersonalBankAccountPage.tsx +++ b/src/pages/AddPersonalBankAccountPage.tsx @@ -10,12 +10,14 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import getPlaidOAuthReceivedRedirectURI from '@libs/getPlaidOAuthReceivedRedirectURI'; -import Navigation from '@libs/Navigation/Navigation'; +import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; +import type {NavigationPartialRoute} from '@libs/Navigation/types'; +import {isFullScreenRoute} from '@libs/NavigationUtils'; import * as BankAccounts from '@userActions/BankAccounts'; import * as PaymentMethods from '@userActions/PaymentMethods'; +import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; function AddPersonalBankAccountPage() { @@ -26,21 +28,22 @@ function AddPersonalBankAccountPage() { const [personalBankAccount] = useOnyx(ONYXKEYS.PERSONAL_BANK_ACCOUNT); const [plaidData] = useOnyx(ONYXKEYS.PLAID_DATA); const shouldShowSuccess = personalBankAccount?.shouldShowSuccess ?? false; - const topMostCentralPane = Navigation.getTopMostCentralPaneRouteFromRootState(); + const topmostFullScreenRoute = navigationRef.current?.getRootState().routes.findLast((route) => isFullScreenRoute(route as NavigationPartialRoute)); + // @TODO: Verify if this methods works correctly const goBack = useCallback(() => { - switch (topMostCentralPane?.name) { - case SCREENS.SETTINGS.WALLET.ROOT: - Navigation.goBack(ROUTES.SETTINGS_WALLET, true); + switch (topmostFullScreenRoute?.name) { + case NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR: + Navigation.goBack(ROUTES.SETTINGS_WALLET); break; - case SCREENS.REPORT: + case NAVIGATORS.REPORTS_SPLIT_NAVIGATOR: Navigation.closeRHPFlow(); break; default: Navigation.goBack(); break; } - }, [topMostCentralPane]); + }, [topmostFullScreenRoute]); const submitBankAccountForm = useCallback(() => { const bankAccounts = plaidData?.bankAccounts ?? []; From e6a4c54bf9f00ab2e6b2fafc39f402d31b446c84 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 18 Oct 2024 15:22:44 +0200 Subject: [PATCH 109/257] Fix ts in getStateToRender in createSplitStackNavigator/index.tsx --- .../AppNavigator/createSplitStackNavigator/index.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index c912a428dcce..e11df72993cc 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -17,15 +17,17 @@ import usePreserveSplitNavigatorState from './usePreserveSplitNavigatorState'; function getStateToRender(state: StackNavigationState, isSmallScreenWidth: boolean): StackNavigationState { const sidebarScreenRoute = state.routes.at(0); + + if (!sidebarScreenRoute) { + return state; + } + const centralScreenRoutes = state.routes.slice(1); const routes = isSmallScreenWidth ? state.routes.slice(-2) : [sidebarScreenRoute, ...centralScreenRoutes.slice(-2)]; - // Routes passed to the state have to be defined - const definedRoutes = routes.filter((route) => route !== undefined); - return { ...state, - routes: definedRoutes, + routes, index: routes.length - 1, }; } From c7f704033b4a25ad4d5426234696e83b2fe25dfe Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 18 Oct 2024 16:50:55 +0200 Subject: [PATCH 110/257] fix perf and matching central screen after deeplink --- .../Navigators/ReportsSplitNavigator.tsx | 67 ++++++++----------- .../createCustomStackNavigator/index.tsx | 5 +- src/libs/Navigation/linkTo/index.ts | 23 ++++++- .../linkingConfig/getAdaptedStateFromPath.ts | 62 +++++++++-------- 4 files changed, 87 insertions(+), 70 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index cee38c625cff..28d5cc0c05f6 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -1,5 +1,5 @@ -import {useNavigation, useRoute} from '@react-navigation/native'; -import React, {useEffect, useRef, useState} from 'react'; +import {useNavigationState, useRoute} from '@react-navigation/native'; +import React, {useRef} from 'react'; import {Freeze} from 'react-freeze'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; @@ -8,7 +8,8 @@ import memoize from '@libs/memoize'; import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; import getCurrentUrl from '@libs/Navigation/currentUrl'; import shouldOpenOnAdminRoom from '@libs/Navigation/shouldOpenOnAdminRoom'; -import type {ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; +import type {NavigationPartialRoute, ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; +import {isFullScreenRoute} from '@libs/NavigationUtils'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import SCREENS from '@src/SCREENS'; @@ -43,30 +44,11 @@ function ReportsSplitNavigator() { const {canUseDefaultRooms} = usePermissions(); const {activeWorkspaceID} = useActiveWorkspace(); - const [isScreenBlurred, setIsScreenBlurred] = useState(false); - let initialReportID: string | undefined; const isInitialRender = useRef(true); - const screenIndexRef = useRef(null); - const navigation = useNavigation(); const currentRoute = useRoute(); - useEffect(() => { - const index = navigation.getState()?.routes.findIndex((route) => route.key === currentRoute.key) ?? 0; - screenIndexRef.current = index; - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - const unsubscribe = navigation.addListener('state', () => { - const modalNavigatorsCount = navigation.getState()?.routes?.filter((route) => route.name.endsWith('ModalNavigator'))?.length ?? 0; - const navigationIndex = (navigation.getState()?.index ?? 0) - (screenIndexRef.current ?? 0) - modalNavigatorsCount; - setIsScreenBlurred(navigationIndex >= 1); - }); - return () => unsubscribe(); - }, [navigation]); - if (isInitialRender.current) { const currentURL = getCurrentUrl(); if (currentURL) { @@ -81,25 +63,32 @@ function ReportsSplitNavigator() { isInitialRender.current = false; } - const getSidebarScreen = freezeScreenWithLazyLoading(() => require('@pages/home/sidebar/SidebarScreen').default, isScreenBlurred); + const shouldFreeze = useNavigationState((state) => { + const lastFullScreenRoute = state.routes.findLast((route) => isFullScreenRoute(route as NavigationPartialRoute)); + return lastFullScreenRoute?.key !== currentRoute.key; + }); + + const getSidebarScreen = freezeScreenWithLazyLoading(() => require('@pages/home/sidebar/SidebarScreen').default, shouldFreeze); return ( - - - - - - + + + + + + + + ); } diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx index 1ba5b5bdcd25..4e33a0251552 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx @@ -3,11 +3,14 @@ import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/na import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; import {StackView} from '@react-navigation/stack'; import React, {useMemo} from 'react'; +import {isFullScreenRoute} from '@libs/NavigationUtils'; import CustomRouter from './CustomRouter'; import type {ResponsiveStackNavigatorProps, ResponsiveStackNavigatorRouterOptions} from './types'; function getStateToRender(state: StackNavigationState): StackNavigationState { - const routes = state.routes.slice(-2); + // @ts-expect-error TODO: Fix this utility function types. + const lastSplitIndex = state.routes.findLastIndex((route) => isFullScreenRoute(route)); + const routes = state.routes.slice(Math.max(0, lastSplitIndex - 1), state.routes.length); return { ...state, diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 5ed9bc33c912..deca187af2fe 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -1,12 +1,14 @@ import {getActionFromState} from '@react-navigation/core'; import type {NavigationContainerRef, NavigationState, PartialState, StackActionType} from '@react-navigation/native'; -import {findFocusedRoute} from '@react-navigation/native'; +import {findFocusedRoute, StackActions} from '@react-navigation/native'; +import {getMatchingFullScreenRouteForRoute, isFullScreenRoute} from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; import {shallowCompare} from '@libs/ObjectUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import getStateFromPath from '@navigation/getStateFromPath'; import linkingConfig from '@navigation/linkingConfig'; import type {RootStackParamList, StackNavigationAction} from '@navigation/types'; import CONST from '@src/CONST'; +import NAVIGATORS from '@src/NAVIGATORS'; import type {Route} from '@src/ROUTES'; import getMinimalAction from './getMinimalAction'; @@ -41,6 +43,10 @@ function shouldDispatchAction(currentState: NavigationState, return true; } +function shouldCheckFullScreenRouteMatching(action: StackNavigationAction): action is StackNavigationAction & {type: 'PUSH'; payload: {name: typeof NAVIGATORS.RIGHT_MODAL_NAVIGATOR}} { + return action !== undefined && action.type === 'PUSH' && action.payload.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR; +} + export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string) { if (!navigation) { throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); @@ -84,6 +90,21 @@ export default function linkTo(navigation: NavigationContainerRef>, policyID?: string) { - const focusedRoute = findFocusedRoute(state); - +function getMatchingFullScreenRouteForRoute(route: NavigationPartialRoute, policyID?: string) { const reportSplitParams = policyID ? {policyID} : undefined; - if (!focusedRoute) { - return undefined; - } - // Check for backTo param. One screen with different backTo value may need different screens visible under the overlay. - if (isRouteWithBackToParam(focusedRoute)) { - const stateForBackTo = getStateFromPath(focusedRoute.params.backTo, config); + if (isRouteWithBackToParam(route)) { + const stateForBackTo = getStateFromPath(route.params.backTo, config); // This may happen if the backTo url is invalid. const lastRoute = stateForBackTo?.routes.at(-1); @@ -59,24 +53,29 @@ function getMatchingFullScreenRouteForState(state: PartialState>, policyID); + return getMatchingFullScreenRouteForRoute(focusedStateForBackToRoute, policyID); } - if (RELATIONS.SEARCH_TO_RHP.includes(focusedRoute.name)) { + if (RELATIONS.SEARCH_TO_RHP.includes(route.name)) { const paramsFromRoute = getParamsFromRoute(SCREENS.SEARCH.CENTRAL_PANE); return { name: SCREENS.SEARCH.CENTRAL_PANE, - params: pick(focusedRoute.params, paramsFromRoute), + params: pick(route.params, paramsFromRoute), }; } - if (RELATIONS.RHP_TO_SIDEBAR[focusedRoute.name]) { + if (RELATIONS.RHP_TO_SIDEBAR[route.name]) { // @TODO: Figure out better types for this. return createSplitNavigator( { - name: RELATIONS.RHP_TO_SIDEBAR[focusedRoute.name] as typeof SCREENS.HOME, + name: RELATIONS.RHP_TO_SIDEBAR[route.name] as typeof SCREENS.HOME, }, undefined, reportSplitParams, @@ -84,7 +83,7 @@ function getMatchingFullScreenRouteForState(state: PartialState // If there is no full screen route in the root, we want to add it. if (!fullScreenRoute) { - const matchingRootRoute = getMatchingFullScreenRouteForState(state, policyID); - // If there is a matching root route, add it to the state. - if (matchingRootRoute) { - return { - adaptedState: getRoutesWithIndex([matchingRootRoute, ...state.routes]), - }; + const focusedRoute = findFocusedRoute(state); + + if (focusedRoute) { + const matchingRootRoute = getMatchingFullScreenRouteForRoute(focusedRoute, policyID); + // If there is a matching root route, add it to the state. + if (matchingRootRoute) { + return { + adaptedState: getRoutesWithIndex([matchingRootRoute, ...state.routes]), + }; + } } const reportSplitParams = policyID ? {policyID} : undefined; @@ -207,3 +210,4 @@ const getAdaptedStateFromPath: GetAdaptedStateFromPath = (path, options, shouldR }; export default getAdaptedStateFromPath; +export {getMatchingFullScreenRouteForRoute, isFullScreenRoute}; From 0612b545b10e374fad76d1c29fd021055ea4151c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 21 Oct 2024 07:18:18 +0200 Subject: [PATCH 111/257] Fix displaying active tab when search is opened --- .../createCustomBottomTabNavigator/BottomTabBar.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 26776764a7f9..a4212a8d467e 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -138,7 +138,7 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { @@ -148,7 +148,7 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { styles.textSmall, styles.textAlignCenter, styles.mt1Half, - selectedTab === SCREENS.SEARCH.BOTTOM_TAB ? styles.textBold : styles.textSupporting, + selectedTab === SCREENS.SEARCH.CENTRAL_PANE ? styles.textBold : styles.textSupporting, styles.bottomTabBarLabel, ]} > From dcdf021b79e228fcb8a0cc1f76c42d0bd167d884 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 21 Oct 2024 09:39:04 +0200 Subject: [PATCH 112/257] Refactor isSplitNavigatorRoute and isFullScreenRoute --- .../Navigators/ReportsSplitNavigator.tsx | 6 +++--- .../createCustomStackNavigator/index.tsx | 5 ++--- src/libs/Navigation/Navigation.ts | 7 +++---- src/libs/Navigation/linkTo/index.ts | 5 ++--- .../linkingConfig/customGetPathFromState.ts | 6 +++--- .../linkingConfig/getAdaptedStateFromPath.ts | 8 ++++---- src/libs/NavigationUtils.ts | 16 ++++++++-------- src/pages/AddPersonalBankAccountPage.tsx | 7 +++---- 8 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index 28d5cc0c05f6..daaabf1094b4 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -8,8 +8,8 @@ import memoize from '@libs/memoize'; import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; import getCurrentUrl from '@libs/Navigation/currentUrl'; import shouldOpenOnAdminRoom from '@libs/Navigation/shouldOpenOnAdminRoom'; -import type {NavigationPartialRoute, ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; -import {isFullScreenRoute} from '@libs/NavigationUtils'; +import type {ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; +import {isFullScreenName} from '@libs/NavigationUtils'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import SCREENS from '@src/SCREENS'; @@ -64,7 +64,7 @@ function ReportsSplitNavigator() { } const shouldFreeze = useNavigationState((state) => { - const lastFullScreenRoute = state.routes.findLast((route) => isFullScreenRoute(route as NavigationPartialRoute)); + const lastFullScreenRoute = state.routes.findLast((route) => isFullScreenName(route.name)); return lastFullScreenRoute?.key !== currentRoute.key; }); diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx index 4e33a0251552..ab15dc49bd14 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx @@ -3,13 +3,12 @@ import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/na import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; import {StackView} from '@react-navigation/stack'; import React, {useMemo} from 'react'; -import {isFullScreenRoute} from '@libs/NavigationUtils'; +import {isFullScreenName} from '@libs/NavigationUtils'; import CustomRouter from './CustomRouter'; import type {ResponsiveStackNavigatorProps, ResponsiveStackNavigatorRouterOptions} from './types'; function getStateToRender(state: StackNavigationState): StackNavigationState { - // @ts-expect-error TODO: Fix this utility function types. - const lastSplitIndex = state.routes.findLastIndex((route) => isFullScreenRoute(route)); + const lastSplitIndex = state.routes.findLastIndex((route) => isFullScreenName(route.name)); const routes = state.routes.slice(Math.max(0, lastSplitIndex - 1), state.routes.length); return { diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index afa83d65fd43..09cbec81b47d 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -5,7 +5,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {Writable} from 'type-fest'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import Log from '@libs/Log'; -import {isSplitNavigatorRoute} from '@libs/NavigationUtils'; +import {isSplitNavigatorName} from '@libs/NavigationUtils'; import {shallowCompare} from '@libs/ObjectUtils'; import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils'; import * as ReportConnection from '@libs/ReportConnection'; @@ -301,9 +301,8 @@ function goBack(fallbackRoute?: Route, shouldPopToTop = false) { const canGoBack = navigationRef.current?.canGoBack(); - if (!canGoBack && isSplitNavigatorRoute(lastRoute as NavigationPartialRoute) && lastRoute?.state?.routes?.length === 1) { - const splitNavigatorName = lastRoute?.name as keyof SplitNavigatorParamListType; - const name = SPLIT_NAVIGATOR_TO_SIDEBAR_MAP[splitNavigatorName]; + if (!canGoBack && isSplitNavigatorName(lastRoute?.name) && lastRoute?.state?.routes?.length === 1) { + const name = SPLIT_NAVIGATOR_TO_SIDEBAR_MAP[lastRoute.name]; const params = getSidebarScreenParams(lastRoute); navigationRef.dispatch({ type: 'REPLACE', diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index deca187af2fe..24004fe9caf5 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -1,7 +1,7 @@ import {getActionFromState} from '@react-navigation/core'; import type {NavigationContainerRef, NavigationState, PartialState, StackActionType} from '@react-navigation/native'; import {findFocusedRoute, StackActions} from '@react-navigation/native'; -import {getMatchingFullScreenRouteForRoute, isFullScreenRoute} from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; +import {getMatchingFullScreenRouteForRoute, isFullScreenName} from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; import {shallowCompare} from '@libs/ObjectUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import getStateFromPath from '@navigation/getStateFromPath'; @@ -96,8 +96,7 @@ export default function linkTo(navigation: NavigationContainerRef isFullScreenName(route.name)); if (matchingFullScreenRoute && lastFullScreenRoute && matchingFullScreenRoute.name !== lastFullScreenRoute.name) { const additionalAction = StackActions.push(matchingFullScreenRoute.name, {screen: matchingFullScreenRoute.state?.routes?.at(-1)?.name}); navigation.dispatch(additionalAction); diff --git a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts index 8d0134360d7d..9ffdcae2224b 100644 --- a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts +++ b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts @@ -1,13 +1,13 @@ import {getPathFromState} from '@react-navigation/native'; -import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; -import {isFullScreenRoute, removePolicyIDParamFromState} from '@libs/NavigationUtils'; +import type {RootStackParamList, State} from '@libs/Navigation/types'; +import {isFullScreenName, removePolicyIDParamFromState} from '@libs/NavigationUtils'; import NAVIGATORS from '@src/NAVIGATORS'; const customGetPathFromState: typeof getPathFromState = (state, options) => { // For the Home page we should remove policyID from the params, because on small screens it's displayed twice in the URL const stateWithoutPolicyID = removePolicyIDParamFromState(state as State); const path = getPathFromState(stateWithoutPolicyID, options); - const fullScreenRoute = state.routes.findLast((route) => isFullScreenRoute(route as NavigationPartialRoute)); + const fullScreenRoute = state.routes.findLast((route) => isFullScreenName(route.name)); const shouldAddPolicyID = fullScreenRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index a63e39489d9f..8b82f04dafd6 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -3,7 +3,7 @@ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import pick from 'lodash/pick'; import {isAnonymousUser} from '@libs/actions/Session'; import type {NavigationPartialRoute, RootStackParamList, SettingsSplitNavigatorParamList, WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; -import {isFullScreenRoute} from '@libs/NavigationUtils'; +import {isFullScreenName} from '@libs/NavigationUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; @@ -46,7 +46,7 @@ function getMatchingFullScreenRouteForRoute(route: NavigationPartialRoute, polic return undefined; } - const isLastRouteFullScreen = isFullScreenRoute(lastRoute); + const isLastRouteFullScreen = isFullScreenName(lastRoute.name); // If the state for back to last route is a full screen route, we can use it if (isLastRouteFullScreen) { @@ -143,7 +143,7 @@ function getMatchingFullScreenRouteForRoute(route: NavigationPartialRoute, polic } function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { - const fullScreenRoute = state.routes.find(isFullScreenRoute); + const fullScreenRoute = state.routes.find((route) => isFullScreenName(route.name)); const reportsSplitNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); // If policyID is defined, it should be passed to the reportNavigator params. @@ -210,4 +210,4 @@ const getAdaptedStateFromPath: GetAdaptedStateFromPath = (path, options, shouldR }; export default getAdaptedStateFromPath; -export {getMatchingFullScreenRouteForRoute, isFullScreenRoute}; +export {getMatchingFullScreenRouteForRoute, isFullScreenName}; diff --git a/src/libs/NavigationUtils.ts b/src/libs/NavigationUtils.ts index b75e814761b4..baacf9881c36 100644 --- a/src/libs/NavigationUtils.ts +++ b/src/libs/NavigationUtils.ts @@ -2,7 +2,7 @@ import cloneDeep from 'lodash/cloneDeep'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import getTopmostBottomTabRoute from './Navigation/getTopmostBottomTabRoute'; -import type {CentralPaneName, FullScreenName, NavigationPartialRoute, OnboardingFlowName, RootStackParamList, SplitNavigatorName, State} from './Navigation/types'; +import type {CentralPaneName, FullScreenName, OnboardingFlowName, RootStackParamList, SplitNavigatorName, State} from './Navigation/types'; const SPLIT_NAVIGATORS = [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]; @@ -56,20 +56,20 @@ function isOnboardingFlowName(screen: string | undefined): screen is OnboardingF return ONBOARDING_SCREEN_NAMES.has(screen as OnboardingFlowName); } -function isSplitNavigatorRoute(route: NavigationPartialRoute | undefined): route is NavigationPartialRoute { - if (!route?.name) { +function isSplitNavigatorName(screen: string | undefined): screen is SplitNavigatorName { + if (!screen) { return false; } - return SPLIT_NAVIGATORS_SET.has(route.name as SplitNavigatorName); + return SPLIT_NAVIGATORS_SET.has(screen as SplitNavigatorName); } -function isFullScreenRoute(route: NavigationPartialRoute | undefined): route is NavigationPartialRoute { - if (!route?.name) { +function isFullScreenName(screen: string | undefined): screen is FullScreenName { + if (!screen) { return false; } - return FULL_SCREEN_ROUTES_SET.has(route.name as FullScreenName); + return FULL_SCREEN_ROUTES_SET.has(screen as FullScreenName); } -export {isCentralPaneName, removePolicyIDParamFromState, isOnboardingFlowName, isFullScreenRoute, isSplitNavigatorRoute}; +export {isCentralPaneName, isFullScreenName, isOnboardingFlowName, isSplitNavigatorName, removePolicyIDParamFromState}; diff --git a/src/pages/AddPersonalBankAccountPage.tsx b/src/pages/AddPersonalBankAccountPage.tsx index bcc8073a6568..cd8d3817c927 100644 --- a/src/pages/AddPersonalBankAccountPage.tsx +++ b/src/pages/AddPersonalBankAccountPage.tsx @@ -11,8 +11,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import getPlaidOAuthReceivedRedirectURI from '@libs/getPlaidOAuthReceivedRedirectURI'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; -import type {NavigationPartialRoute} from '@libs/Navigation/types'; -import {isFullScreenRoute} from '@libs/NavigationUtils'; +import {isFullScreenName} from '@libs/NavigationUtils'; import * as BankAccounts from '@userActions/BankAccounts'; import * as PaymentMethods from '@userActions/PaymentMethods'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -28,9 +27,9 @@ function AddPersonalBankAccountPage() { const [personalBankAccount] = useOnyx(ONYXKEYS.PERSONAL_BANK_ACCOUNT); const [plaidData] = useOnyx(ONYXKEYS.PLAID_DATA); const shouldShowSuccess = personalBankAccount?.shouldShowSuccess ?? false; - const topmostFullScreenRoute = navigationRef.current?.getRootState().routes.findLast((route) => isFullScreenRoute(route as NavigationPartialRoute)); + const topmostFullScreenRoute = navigationRef.current?.getRootState().routes.findLast((route) => isFullScreenName(route.name)); - // @TODO: Verify if this methods works correctly + // @TODO: Verify if this method works correctly const goBack = useCallback(() => { switch (topmostFullScreenRoute?.name) { case NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR: From 9efb031253114d319d1e63cdeaebe041af4484dd Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 21 Oct 2024 10:21:05 +0200 Subject: [PATCH 113/257] Fix navigating to previously opened settings tab --- src/pages/home/sidebar/BottomTabAvatar.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index 31072694b0a9..6a2685553cad 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -8,6 +8,7 @@ import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; +import {getPreservedSplitNavigatorState} from '@libs/Navigation/AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import CONST from '@src/CONST'; @@ -53,7 +54,8 @@ function BottomTabAvatar({isSelected = false}: BottomTabAvatarProps) { // If there is a workspace navigator route, then we should open the workspace initial screen as it should be "remembered". if (lastSettingsOrWorkspaceNavigatorRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - const params = lastSettingsOrWorkspaceNavigatorRoute.state?.routes.at(0)?.params as WorkspaceSplitNavigatorParamList[typeof SCREENS.WORKSPACE.INITIAL]; + const state = lastSettingsOrWorkspaceNavigatorRoute.state ?? getPreservedSplitNavigatorState(lastSettingsOrWorkspaceNavigatorRoute.key); + const params = state?.routes.at(0)?.params as WorkspaceSplitNavigatorParamList[typeof SCREENS.WORKSPACE.INITIAL]; // Screens of this navigator should always have policyID if (params.policyID) { Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(params.policyID)); From 4881e68b454eefff678ca5eac16586e89ab37fb7 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 21 Oct 2024 11:04:09 +0200 Subject: [PATCH 114/257] Remove getTopMostCentralPaneRouteFromRootState from Navigation.ts --- src/libs/Navigation/Navigation.ts | 5 ----- src/libs/ReportUtils.ts | 9 +++++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 09cbec81b47d..d030f5e37482 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -435,10 +435,6 @@ function waitForProtectedRoutes() { }); } -function getTopMostCentralPaneRouteFromRootState() { - return getTopmostCentralPaneRoute(navigationRef.getRootState() as State); -} - function switchPolicyID(policyID?: string) { navigationRef.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID, payload: {policyID}}); } @@ -517,7 +513,6 @@ export default { resetToHome, closeRHPFlow, setNavigationActionToMicrotaskQueue, - getTopMostCentralPaneRouteFromRootState, navigateToReportWithPolicyCheck, goUp, }; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b49d721d1350..8bb89b5dfcdb 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -74,7 +74,7 @@ import Log from './Log'; import {isEmailPublicDomain} from './LoginUtils'; import ModifiedExpenseMessage from './ModifiedExpenseMessage'; import linkingConfig from './Navigation/linkingConfig'; -import Navigation from './Navigation/Navigation'; +import Navigation, {navigationRef} from './Navigation/Navigation'; import * as NumberUtils from './NumberUtils'; import Parser from './Parser'; import Permissions from './Permissions'; @@ -4096,9 +4096,10 @@ function navigateBackAfterDeleteTransaction(backRoute: Route | undefined, isFrom if (!backRoute) { return; } - // @TODO: Refactor this method - const topmostCentralPaneRoute = Navigation.getTopMostCentralPaneRouteFromRootState(); - if (topmostCentralPaneRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { + // @TODO: Verify if this method works correctly + const rootState = navigationRef.current?.getRootState(); + const topmostRoute = rootState?.routes.at(-1); + if (topmostRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { Navigation.dismissModal(); return; } From 31069c1fc63b3f05045dde00146634644de693e0 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Mon, 21 Oct 2024 13:37:12 +0200 Subject: [PATCH 115/257] fix getRouteParamsToCompare --- src/libs/Navigation/Navigation.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 09cbec81b47d..bb3c1613a112 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -1,6 +1,8 @@ import {getActionFromState} from '@react-navigation/core'; import type {EventArg, NavigationAction, NavigationContainerEventMap} from '@react-navigation/native'; import {CommonActions, getPathFromState, StackActions} from '@react-navigation/native'; +// eslint-disable-next-line you-dont-need-lodash-underscore/omit +import omit from 'lodash/omit'; import type {OnyxEntry} from 'react-native-onyx'; import type {Writable} from 'type-fest'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; @@ -208,9 +210,11 @@ function navigate(route: Route = ROUTES.HOME, type?: string) { linkTo(navigationRef.current, route, type); } +const routeParamsIgnore = ['path', 'initial', 'params', 'state', 'screen', 'policyID']; + +// If we use destructuring, we will get an error if any of the ignored properties are not present in the object. function getRouteParamsToCompare(routeParams: Record) { - const {path, initial, params, state, screen, policyID, ...routeParamsToCompare} = routeParams; - return routeParamsToCompare; + return omit(routeParams, routeParamsIgnore); } function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | NavigationPartialRoute, minimalAction: Writable) { From 75c4b80c27e79ba7a24c0408e6d1843c24992af2 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Mon, 21 Oct 2024 13:38:05 +0200 Subject: [PATCH 116/257] fix goUp on WorkspaceListPage --- src/pages/workspace/WorkspacesListPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 76abe6e5b3d7..ec2839aef4c8 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -383,7 +383,7 @@ function WorkspacesListPage() { title={translate('common.workspaces')} shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter - onBackButtonPress={() => Navigation.goBack()} + onBackButtonPress={() => Navigation.goUp(ROUTES.SETTINGS)} icon={Illustrations.BigRocket} > {!shouldUseNarrowLayout && getHeaderButton()} @@ -420,7 +420,7 @@ function WorkspacesListPage() { title={translate('common.workspaces')} shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter - onBackButtonPress={() => Navigation.goBack()} + onBackButtonPress={() => Navigation.goUp(ROUTES.SETTINGS)} icon={Illustrations.BigRocket} > {!shouldUseNarrowLayout && getHeaderButton()} From e69c349477cf79ac5f3430f8ec56dbc5b5611553 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Mon, 21 Oct 2024 13:39:38 +0200 Subject: [PATCH 117/257] fix animation for navigating to WorkspadceListPage --- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 6a42f4b365c3..65d6d730704d 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -250,7 +250,8 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie return screenOptions.fullScreen; } - const animationEnabled = !Object.keys(SIDEBAR_TO_SPLIT).includes(screenName); + // SETTINGS.WORKSPACES has bottom tab bar so we have to disable animations for it as well. + const animationEnabled = !Object.keys(SIDEBAR_TO_SPLIT).includes(screenName) && screenName !== SCREENS.SETTINGS.WORKSPACES; return { ...screenOptions.fullScreen, From d6f3322e3fc0ebeb0f0d68c9ff8ba75362a8c0a3 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Mon, 21 Oct 2024 13:40:37 +0200 Subject: [PATCH 118/257] remove unused code --- .../Navigation/AppNavigator/AuthScreens.tsx | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 65d6d730704d..55dd91eacc87 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -567,24 +567,6 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie options={screenOptions.fullScreen} component={ConnectionCompletePage} /> - {/* {Object.entries(CENTRAL_PANE_SCREENS).map(([screenName, componentGetter]) => { - const centralPaneName = screenName as CentralPaneName; - const options = {...CentralPaneScreenOptions}; - - if (centralPaneName === SCREENS.SETTINGS.WORKSPACES) { - options.animationEnabled = false; - } - - return ( - - ); - })} */} From 03bd743964d89d4120d47a0865165201c91cf608 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Mon, 21 Oct 2024 15:25:51 +0200 Subject: [PATCH 119/257] fix animation for navigating to Sidebar screens --- .../usePrepareSplitStackNavigatorChildren.ts | 2 +- .../Navigation/AppNavigator/getRootNavigatorScreenOptions.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts index 3637cdeded3b..9609fa3ec994 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts @@ -20,7 +20,7 @@ export default function usePrepareSplitStackNavigatorChildren(screensNode: React ...screen, props: { ...screenProps, - options: sidebarScreenOptions, + options: {...sidebarScreenOptions, ...screenProps.options}, }, }; } diff --git a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts index a59a339c0c6a..1d4c821de1dc 100644 --- a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts +++ b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts @@ -84,6 +84,7 @@ const getRootNavigatorScreenOptions: GetRootNavigatorScreenOptions = (isSmallScr homeScreen: { title: CONFIG.SITE_TITLE, ...commonScreenOptions, + animationEnabled: false, cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, false, props), cardStyle: { From e56bdaa16815da9b9415279c754fb4b072247cd7 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 22 Oct 2024 13:09:57 +0200 Subject: [PATCH 120/257] Revert "Migrate FloatingActionButton to useOnyx and add small cleanups" This reverts commit 45dd97a8fd4f1c862cbd3dc977ff2585790280a1. --- src/libs/actions/Policy/Policy.ts | 3 +- src/pages/home/sidebar/BottomTabAvatar.tsx | 12 +- .../FloatingActionButtonAndPopover.tsx | 138 +++++++++++++----- 3 files changed, 115 insertions(+), 38 deletions(-) diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 1a1503fe59a8..c517439aeda2 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -76,6 +76,7 @@ import * as ReportActionsConnection from '@libs/ReportActionsConnection'; import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; +import type {PolicySelector} from '@pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover'; import * as PaymentMethods from '@userActions/PaymentMethods'; import * as PersistedRequests from '@userActions/PersistedRequests'; import CONST from '@src/CONST'; @@ -100,8 +101,6 @@ import type {OnyxData} from '@src/types/onyx/Request'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import {buildOptimisticPolicyCategories} from './Category'; -type PolicySelector = Pick; - type ReportCreationData = Record< string, { diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index 6a2685553cad..d3f9a9fb76fa 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -21,11 +21,14 @@ import AvatarWithOptionalStatus from './AvatarWithOptionalStatus'; import ProfileAvatarWithIndicator from './ProfileAvatarWithIndicator'; type BottomTabAvatarProps = { + /** Whether the create menu is open or not */ + isCreateMenuOpen?: boolean; + /** Whether the avatar is selected */ isSelected?: boolean; }; -function BottomTabAvatar({isSelected = false}: BottomTabAvatarProps) { +function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomTabAvatarProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const [account] = useOnyx(ONYXKEYS.ACCOUNT); @@ -36,6 +39,11 @@ function BottomTabAvatar({isSelected = false}: BottomTabAvatarProps) { const {shouldUseNarrowLayout} = useResponsiveLayout(); const showSettingsPage = useCallback(() => { + if (isCreateMenuOpen) { + // Prevent opening Settings page when click profile avatar quickly after clicking FAB icon + return; + } + if (route.name === SCREENS.SETTINGS.WORKSPACES && shouldUseNarrowLayout) { Navigation.goUp(ROUTES.SETTINGS); return; @@ -77,7 +85,7 @@ function BottomTabAvatar({isSelected = false}: BottomTabAvatarProps) { // This case also covers if there is no route to remember. Navigation.navigate(ROUTES.SETTINGS); }); - }, [shouldUseNarrowLayout, route.name]); + }, [isCreateMenuOpen, shouldUseNarrowLayout, route.name]); let children; diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx index c51df3c46329..a49b474b185e 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx @@ -1,9 +1,10 @@ import {useIsFocused as useIsFocusedOriginal, useNavigationState} from '@react-navigation/native'; import type {ImageContentFit} from 'expo-image'; -import type {ForwardedRef} from 'react'; +import type {ForwardedRef, RefAttributes} from 'react'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import {useOnyx, withOnyx} from 'react-native-onyx'; import type {SvgProps} from 'react-native-svg'; import FloatingActionButton from '@components/FloatingActionButton'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -35,6 +36,7 @@ import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; +import type * as OnyxTypes from '@src/types/onyx'; import type {QuickActionName} from '@src/types/onyx/QuickAction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -47,7 +49,35 @@ const useIsFocused = () => { return isFocused || (topmostCentralPane?.name === SCREENS.SEARCH.CENTRAL_PANE && shouldUseNarrowLayout); }; -type FloatingActionButtonAndPopoverProps = { +type PolicySelector = Pick; + +type FloatingActionButtonAndPopoverOnyxProps = { + /** The list of policies the user has access to. */ + allPolicies: OnyxCollection; + + /** Whether app is in loading state */ + isLoading: OnyxEntry; + + /** Information on the last taken action to display as Quick Action */ + quickAction: OnyxEntry; + + /** The report data of the quick action */ + quickActionReport: OnyxEntry; + + /** The policy data of the quick action */ + quickActionPolicy: OnyxEntry; + + /** The current session */ + session: OnyxEntry; + + /** Personal details of all the users */ + personalDetails: OnyxEntry; + + /** Has user seen track expense training interstitial */ + hasSeenTrackTraining: OnyxEntry; +}; + +type FloatingActionButtonAndPopoverProps = FloatingActionButtonAndPopoverOnyxProps & { /* Callback function when the menu is shown */ onShowCreateMenu?: () => void; @@ -59,6 +89,18 @@ type FloatingActionButtonAndPopoverRef = { hideCreateMenu: () => void; }; +const policySelector = (policy: OnyxEntry): PolicySelector => + (policy && { + type: policy.type, + role: policy.role, + id: policy.id, + isPolicyExpenseChatEnabled: policy.isPolicyExpenseChatEnabled, + pendingAction: policy.pendingAction, + avatarURL: policy.avatarURL, + name: policy.name, + areInvoicesEnabled: policy.areInvoicesEnabled, + }) as PolicySelector; + const getQuickActionIcon = (action: QuickActionName): React.FC => { switch (action) { case CONST.QUICK_ACTIONS.REQUEST_MANUAL: @@ -119,9 +161,24 @@ const getQuickActionTitle = (action: QuickActionName): TranslationPaths => { * Responsible for rendering the {@link PopoverMenu}, and the accompanying * FAB that can open or close the menu. */ -function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: FloatingActionButtonAndPopoverProps, ref: ForwardedRef) { +function FloatingActionButtonAndPopover( + { + onHideCreateMenu, + onShowCreateMenu, + isLoading = false, + allPolicies, + quickAction, + quickActionReport, + quickActionPolicy, + session, + personalDetails, + hasSeenTrackTraining, + }: FloatingActionButtonAndPopoverProps, + ref: ForwardedRef, +) { const styles = useThemeStyles(); const {translate} = useLocalize(); + const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${quickActionReport?.reportID ?? -1}`); const [isCreateMenuActive, setIsCreateMenuActive] = useState(false); const fabRef = useRef(null); const {windowHeight} = useWindowDimensions(); @@ -129,33 +186,19 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl const isFocused = useIsFocused(); const prevIsFocused = usePrevious(isFocused); const {isOffline} = useNetwork(); - const {canUseSpotnanaTravel, canUseCombinedTrackSubmit} = usePermissions(); - const [isLoading] = useOnyx(ONYXKEYS.IS_LOADING_APP); - const [policies = {}] = useOnyx(ONYXKEYS.COLLECTION.POLICY); - const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); - const [session] = useOnyx(ONYXKEYS.SESSION); - const [hasSeenTrackTraining] = useOnyx(ONYXKEYS.NVP_HAS_SEEN_TRACK_TRAINING); - const [quickAction = {}] = useOnyx(ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE); - const [quickActionReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${quickAction?.chatReportID}`); - const [reportNameValuePairs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${quickActionReport?.reportID ?? -1}`); - const [quickActionPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${quickActionReport?.policyID}`); - - const sessionEmail = session?.email; - const sessionAccountID = session?.accountID; - const canSendInvoice = useMemo(() => PolicyUtils.canSendInvoice(policies, sessionEmail), [policies, sessionEmail]); - - const quickActionName = quickAction.action; + const {canUseSpotnanaTravel, canUseCombinedTrackSubmit} = usePermissions(); + const canSendInvoice = useMemo(() => PolicyUtils.canSendInvoice(allPolicies as OnyxCollection, session?.email), [allPolicies, session?.email]); const quickActionAvatars = useMemo(() => { if (quickActionReport) { const avatars = ReportUtils.getIcons(quickActionReport, personalDetails); - return avatars.length <= 1 || ReportUtils.isPolicyExpenseChat(quickActionReport) ? avatars : avatars.filter((avatar) => avatar.id !== sessionAccountID); + return avatars.length <= 1 || ReportUtils.isPolicyExpenseChat(quickActionReport) ? avatars : avatars.filter((avatar) => avatar.id !== session?.accountID); } return []; // Policy is needed as a dependency in order to update the shortcut details when the workspace changes // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, [personalDetails, sessionAccountID, quickActionReport, quickActionPolicy]); + }, [personalDetails, session?.accountID, quickActionReport, quickActionPolicy]); const renderQuickActionTooltip = useCallback( () => ( @@ -171,14 +214,13 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl if (isEmptyObject(quickActionReport)) { return ''; } - - if (quickActionName === CONST.QUICK_ACTIONS.SEND_MONEY && quickActionAvatars.length > 0) { - const name = ReportUtils.getDisplayNameForParticipant(+(quickActionAvatars.at(0)?.id ?? -1), true) ?? ''; + if (quickAction?.action === CONST.QUICK_ACTIONS.SEND_MONEY && quickActionAvatars.length > 0) { + const name: string = ReportUtils.getDisplayNameForParticipant(+(quickActionAvatars.at(0)?.id ?? -1), true) ?? ''; return translate('quickAction.paySomeone', {name}); } - const titleKey = getQuickActionTitle(quickActionName ?? ('' as QuickActionName)); + const titleKey = getQuickActionTitle(quickAction?.action ?? ('' as QuickActionName)); return titleKey ? translate(titleKey) : ''; - }, [quickActionName, translate, quickActionAvatars, quickActionReport]); + }, [quickAction, translate, quickActionAvatars, quickActionReport]); const hideQABSubtitle = useMemo(() => { if (isEmptyObject(quickActionReport)) { @@ -188,8 +230,8 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl return false; } const displayName = personalDetails?.[quickActionAvatars.at(0)?.id ?? -1]?.firstName ?? ''; - return quickActionName === CONST.QUICK_ACTIONS.SEND_MONEY && displayName.length === 0; - }, [personalDetails, quickActionReport, quickActionName, quickActionAvatars]); + return quickAction?.action === CONST.QUICK_ACTIONS.SEND_MONEY && displayName.length === 0; + }, [personalDetails, quickActionReport, quickAction?.action, quickActionAvatars]); const navigateToQuickAction = () => { const selectOption = (onSelected: () => void, shouldRestrictAction: boolean) => { @@ -204,7 +246,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl const isValidReport = !(isEmptyObject(quickActionReport) || ReportUtils.isArchivedRoom(quickActionReport, reportNameValuePairs)); const quickActionReportID = isValidReport ? quickActionReport?.reportID ?? '-1' : ReportUtils.generateReportID(); - switch (quickActionName) { + switch (quickAction?.action) { case CONST.QUICK_ACTIONS.REQUEST_MANUAL: selectOption(() => IOU.startMoneyRequest(CONST.IOU.TYPE.SUBMIT, quickActionReportID, CONST.IOU.REQUEST_TYPE.MANUAL, true), true); return; @@ -412,7 +454,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl }, ] : []), - ...(!isLoading && !Policy.hasActiveChatEnabledPolicies(policies) + ...(!isLoading && !Policy.hasActiveChatEnabledPolicies(allPolicies) ? [ { displayInDefaultIconColor: true, @@ -426,10 +468,10 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl }, ] : []), - ...(quickActionName + ...(quickAction?.action ? [ { - icon: getQuickActionIcon(quickActionName), + icon: getQuickActionIcon(quickAction?.action), text: quickActionTitle, label: translate('quickAction.header'), isLabelHoverable: false, @@ -468,4 +510,32 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl FloatingActionButtonAndPopover.displayName = 'FloatingActionButtonAndPopover'; -export default forwardRef(FloatingActionButtonAndPopover); +export default withOnyx, FloatingActionButtonAndPopoverOnyxProps>({ + allPolicies: { + key: ONYXKEYS.COLLECTION.POLICY, + selector: policySelector, + }, + isLoading: { + key: ONYXKEYS.IS_LOADING_APP, + }, + quickAction: { + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + }, + quickActionReport: { + key: ({quickAction}) => `${ONYXKEYS.COLLECTION.REPORT}${quickAction?.chatReportID}`, + }, + quickActionPolicy: { + key: ({quickActionReport}) => `${ONYXKEYS.COLLECTION.POLICY}${quickActionReport?.policyID}`, + }, + personalDetails: { + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + }, + session: { + key: ONYXKEYS.SESSION, + }, + hasSeenTrackTraining: { + key: ONYXKEYS.NVP_HAS_SEEN_TRACK_TRAINING, + }, +})(forwardRef(FloatingActionButtonAndPopover)); + +export type {PolicySelector}; From b16a7ca0fb7da077104b134d5e6dcd7a8cdf6e23 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 22 Oct 2024 13:41:53 +0200 Subject: [PATCH 121/257] fix SETTINGS_TO_RHP --- src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts index 824fc072d686..f89495cf772c 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts @@ -6,7 +6,6 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Record = { SCREENS.SETTINGS.PROFILE.DISPLAY_NAME, SCREENS.SETTINGS.PROFILE.CONTACT_METHODS, SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS, - SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_VALIDATE_ACTION, SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD, SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER, SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_DATE, @@ -44,7 +43,6 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Record = { SCREENS.SETTINGS.DELEGATE.ADD_DELEGATE, SCREENS.SETTINGS.DELEGATE.DELEGATE_ROLE, SCREENS.SETTINGS.DELEGATE.DELEGATE_CONFIRM, - SCREENS.SETTINGS.DELEGATE.DELEGATE_MAGIC_CODE, ], [SCREENS.SETTINGS.ABOUT]: [SCREENS.SETTINGS.APP_DOWNLOAD_LINKS], [SCREENS.SETTINGS.SAVE_THE_WORLD]: [SCREENS.I_KNOW_A_TEACHER, SCREENS.INTRO_SCHOOL_PRINCIPAL, SCREENS.I_AM_A_TEACHER], From 9132ffd2fe05663d1c65ea9bf8f6522872851d02 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 22 Oct 2024 14:37:37 +0200 Subject: [PATCH 122/257] fix perf tests --- tests/perf-test/SidebarLinks.perf-test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/perf-test/SidebarLinks.perf-test.tsx b/tests/perf-test/SidebarLinks.perf-test.tsx index d1942522af38..bb1e865156a4 100644 --- a/tests/perf-test/SidebarLinks.perf-test.tsx +++ b/tests/perf-test/SidebarLinks.perf-test.tsx @@ -11,7 +11,7 @@ import wrapInAct from '../utils/wrapInActHelper'; import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; jest.mock('@libs/Permissions'); -jest.mock('@src/hooks/useActiveWorkspaceFromNavigationState'); +jest.mock('@src/hooks/useActiveWorkspace'); jest.mock('../../src/libs/Navigation/Navigation', () => ({ navigate: jest.fn(), isActiveRoute: jest.fn(), From 0fc9470838da8ea7949943f12d36c49ae0670b8f Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 22 Oct 2024 16:51:36 +0200 Subject: [PATCH 123/257] fix perf tests v2 --- tests/perf-test/SidebarLinks.perf-test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/perf-test/SidebarLinks.perf-test.tsx b/tests/perf-test/SidebarLinks.perf-test.tsx index bb1e865156a4..afe29951f15e 100644 --- a/tests/perf-test/SidebarLinks.perf-test.tsx +++ b/tests/perf-test/SidebarLinks.perf-test.tsx @@ -11,7 +11,7 @@ import wrapInAct from '../utils/wrapInActHelper'; import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; jest.mock('@libs/Permissions'); -jest.mock('@src/hooks/useActiveWorkspace'); +jest.mock('@src/hooks/useActiveWorkspace', () => jest.fn(() => ({activeWorkspaceID: undefined}))); jest.mock('../../src/libs/Navigation/Navigation', () => ({ navigate: jest.fn(), isActiveRoute: jest.fn(), From b23a3f1c3d8052c066b1af326df81b00b9daf088 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 23 Oct 2024 10:40:31 +0200 Subject: [PATCH 124/257] Fix bottom tab width in InitialSettingsPage --- src/pages/settings/InitialSettingsPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 1c398cfdae1c..d982b5f295e6 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -405,7 +405,6 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr return ( From a95797c4a9cc30fc36114c07cb3e22eddfe9688c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 23 Oct 2024 17:11:15 +0200 Subject: [PATCH 125/257] Remove some todo comments --- .../ActiveWorkspaceProvider/index.tsx | 10 ---- .../createSplitStackNavigator/index.tsx | 2 - src/libs/Navigation/Navigation.ts | 55 ------------------- 3 files changed, 67 deletions(-) diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index d306226a85c2..ec0a257fd14f 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -43,16 +43,6 @@ function ActiveWorkspaceContextProvider({children}: ChildrenProps) { [activeWorkspaceID, setActiveWorkspaceID], ); - // @TODO Remember to handle saving activeWorkspaceID in the session storage - // const setActiveWorkspaceID = useCallback((workspaceID: string | undefined) => { - // updateActiveWorkspaceID(workspaceID); - // if (workspaceID && sessionStorage) { - // sessionStorage?.setItem(CONST.SESSION_STORAGE_KEYS.ACTIVE_WORKSPACE_ID, workspaceID); - // } else { - // sessionStorage?.removeItem(CONST.SESSION_STORAGE_KEYS.ACTIVE_WORKSPACE_ID); - // } - // }, []); - return {children}; } diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index e11df72993cc..2ea0faf5921c 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -54,8 +54,6 @@ function SplitStackNavigator(props: SplitStackN initialRouteName: props.initialRouteName, sidebarScreen: props.sidebarScreen, defaultCentralScreen: props.defaultCentralScreen, - - // @TODO figure out if we can end in a situation where the state and route are not in sync. If so, we may need to figure out a getter. parentRoute: route, }); diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 851aa401ac5b..7052fba090f5 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -81,33 +81,6 @@ const getTopmostReportActionId = (state = navigationRef.getState()) => originalG // Re-exporting the closeRHPFlow here to fill in default value for navigationRef. The closeRHPFlow isn't defined in this file to avoid cyclic dependencies. const closeRHPFlow = (ref = navigationRef) => originalCloseRHPFlow(ref); -// Re-exporting the dismissModalWithReport here to fill in default value for navigationRef. The dismissModalWithReport isn't defined in this file to avoid cyclic dependencies. -// This method is needed because it allows to dismiss the modal and then open the report. Within this method is checked whether the report belongs to a specific workspace. Sometimes the report we want to check, hasn't been added to the Onyx yet. -// Then we can pass the report as a param without getting it from the Onyx. - -// @TODO: Check if it's still needed -/** Method for finding on which index in stack we are. */ -// function getActiveRouteIndex(stateOrRoute: StateOrRoute, index?: number): number | undefined { -// if ('routes' in stateOrRoute && stateOrRoute.routes) { -// const childActiveRoute = stateOrRoute.routes[stateOrRoute.index ?? 0]; -// return getActiveRouteIndex(childActiveRoute, stateOrRoute.index ?? 0); -// } - -// if ('state' in stateOrRoute && stateOrRoute.state?.routes) { -// const childActiveRoute = stateOrRoute.state.routes[stateOrRoute.state.index ?? 0]; -// return getActiveRouteIndex(childActiveRoute, stateOrRoute.state.index ?? 0); -// } - -// if ( -// 'name' in stateOrRoute && -// (stateOrRoute.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR || stateOrRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) -// ) { -// return 0; -// } - -// return index; -// } - /** * Function that generates dynamic urls from paths passed from OldDot */ @@ -125,34 +98,6 @@ function parseHybridAppUrl(url: HybridAppRoute | Route): Route { } } -// @TODO: Check if it's still needed -// /** -// * Gets distance from the path in root navigator. In other words how much screen you have to pop to get to the route with this path. -// * The search is limited to 5 screens from the top for performance reasons. -// * @param path - Path that you are looking for. -// * @return - Returns distance to path or -1 if the path is not found in root navigator. -// */ -// function getDistanceFromPathInRootNavigator(state: State, path?: string): number { -// let currentState = {...state}; - -// for (let index = 0; index < 5; index++) { -// if (!currentState.routes.length) { -// break; -// } - -// // When comparing path and pathFromState, the policyID parameter isn't included in the comparison -// const currentStateWithoutPolicyID = removePolicyIDParamFromState(currentState as State); -// const pathFromState = getPathFromState(currentStateWithoutPolicyID, linkingConfig.config); -// if (path === pathFromState.substring(1)) { -// return index; -// } - -// currentState = {...currentState, routes: currentState.routes.slice(0, -1), index: currentState.index - 1}; -// } - -// return -1; -// } - /** Returns the current active route */ function getActiveRoute(): string { const currentRoute = navigationRef.current && navigationRef.current.getCurrentRoute(); From 052d352a48001e50a5a5fbdb123f0dcced1deae0 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 23 Oct 2024 17:11:57 +0200 Subject: [PATCH 126/257] Fix getting previousSelectedCentralScreen in adaptStateIfNecessary --- .../createSplitStackNavigator/SplitStackRouter.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts index 8ff509cd5269..6dd910985b41 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts @@ -60,11 +60,12 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc if (state.routes.length === 1 && state.routes[0].name === sidebarScreen) { const rootState = navigationRef.getRootState(); - // @TODO: If we have optimization for not rendering all split navigators, then last selected option won't be in the state. - // @TODO: Do we want to use previous selected screen if the policyID is different. - const previousSameNavigator = rootState?.routes.findLast((route) => route.name === parentRoute.name && route.state !== undefined); + const previousSameNavigator = rootState?.routes.filter((route) => route.name === parentRoute.name).at(-2); + + // If we have optimization for not rendering all split navigators, then last selected option may not be in the state. In this case state has to be read from the preserved state. + const previousSameNavigatorState = previousSameNavigator?.state ?? (previousSameNavigator?.key ? getPreservedSplitNavigatorState(previousSameNavigator.key) : undefined); const previousSelectedCentralScreen = - previousSameNavigator?.state?.routes && previousSameNavigator.state.routes.length > 1 ? previousSameNavigator.state.routes.at(-1)?.name : undefined; + previousSameNavigatorState?.routes && previousSameNavigatorState.routes.length > 1 ? previousSameNavigatorState.routes.at(-1)?.name : undefined; // @ts-expect-error Updating read only property // noinspection JSConstantReassignment From 6701e9fa34a27b361c2b8a358ad4c08b9a549f94 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 24 Oct 2024 14:27:41 +0200 Subject: [PATCH 127/257] Remove money request rhp screens from SIDEBAR_TO_RHP --- src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts index 1b46b68a1ef2..d6ace93cd1e6 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts @@ -1,8 +1,6 @@ -import CONST from '@src/CONST'; import SCREENS from '@src/SCREENS'; const SIDEBAR_TO_RHP: Record = { - [SCREENS.HOME]: [SCREENS.MONEY_REQUEST.CREATE, CONST.TAB_REQUEST.DISTANCE, CONST.TAB_REQUEST.MANUAL, CONST.TAB_REQUEST.SCAN], [SCREENS.SETTINGS.ROOT]: [ SCREENS.SETTINGS.SHARE_CODE, SCREENS.SETTINGS.PROFILE.STATUS, From a3063c834ac4ca7c9b35407176a752090f076157 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 24 Oct 2024 16:50:12 +0200 Subject: [PATCH 128/257] Fix issue: Expense - App does not open destination report after submitting expense --- src/libs/Navigation/Navigation.ts | 10 +++------ .../Navigation/isSearchTopmostCentralPane.ts | 22 ------------------- src/libs/Navigation/isSearchTopmostRoute.ts | 15 +++++++++++++ src/libs/actions/IOU.ts | 20 ++++++++--------- src/pages/EditReportFieldPage.tsx | 6 ++--- tests/actions/IOUTest.ts | 2 +- 6 files changed, 32 insertions(+), 43 deletions(-) delete mode 100644 src/libs/Navigation/isSearchTopmostCentralPane.ts create mode 100644 src/libs/Navigation/isSearchTopmostRoute.ts diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 7052fba090f5..8409101633c3 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -390,22 +390,18 @@ function switchPolicyID(policyID?: string) { type NavigateToReportWithPolicyCheckPayload = {report?: OnyxEntry; reportID?: string; reportActionID?: string; referrer?: string; policyIDToCheck?: string}; function navigateToReportWithPolicyCheck({report, reportID, reportActionID, referrer, policyIDToCheck}: NavigateToReportWithPolicyCheckPayload, ref = navigationRef) { - const targetReport = reportID ? ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] : report; - if (!targetReport) { - return; - } - + const targetReport = reportID ? {reportID, ...ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]} : report; const policyID = policyIDToCheck ?? getPolicyIDFromState(navigationRef.getRootState() as State); const policyMemberAccountIDs = getPolicyEmployeeAccountIDs(policyID); const shouldOpenAllWorkspace = isEmptyObject(targetReport) ? true : !ReportUtils.doesReportBelongToWorkspace(targetReport, policyMemberAccountIDs, policyID); if ((shouldOpenAllWorkspace && !policyID) || !shouldOpenAllWorkspace) { - linkTo(ref.current, ROUTES.REPORT_WITH_ID.getRoute(targetReport.reportID, reportActionID, referrer)); + linkTo(ref.current, ROUTES.REPORT_WITH_ID.getRoute(targetReport?.reportID ?? '-1', reportActionID, referrer)); return; } const params: Record = { - reportID: targetReport.reportID, + reportID: targetReport?.reportID ?? '-1', }; if (reportActionID) { diff --git a/src/libs/Navigation/isSearchTopmostCentralPane.ts b/src/libs/Navigation/isSearchTopmostCentralPane.ts deleted file mode 100644 index 3c315116bb00..000000000000 --- a/src/libs/Navigation/isSearchTopmostCentralPane.ts +++ /dev/null @@ -1,22 +0,0 @@ -import SCREENS from '@src/SCREENS'; -import getTopmostCentralPaneRoute from './getTopmostCentralPaneRoute'; -import {navigationRef} from './Navigation'; -import type {RootStackParamList, State} from './types'; - -const isSearchTopmostCentralPane = (): boolean => { - const rootState = navigationRef.getRootState() as State; - - if (!rootState) { - return false; - } - - const topmostCentralPaneRoute = getTopmostCentralPaneRoute(rootState); - - if (topmostCentralPaneRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { - return true; - } - - return false; -}; - -export default isSearchTopmostCentralPane; diff --git a/src/libs/Navigation/isSearchTopmostRoute.ts b/src/libs/Navigation/isSearchTopmostRoute.ts new file mode 100644 index 000000000000..41969d894635 --- /dev/null +++ b/src/libs/Navigation/isSearchTopmostRoute.ts @@ -0,0 +1,15 @@ +import SCREENS from '@src/SCREENS'; +import {navigationRef} from './Navigation'; +import type {RootStackParamList, State} from './types'; + +const isSearchTopmostRoute = (): boolean => { + const rootState = navigationRef.getRootState() as State; + + if (!rootState) { + return false; + } + + return rootState.routes.at(-1)?.name === SCREENS.SEARCH.CENTRAL_PANE; +}; + +export default isSearchTopmostRoute; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 0d9a4887bd1d..f5d06718d593 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -39,7 +39,7 @@ import * as FileUtils from '@libs/fileDownload/FileUtils'; import * as IOUUtils from '@libs/IOUUtils'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; import * as Localize from '@libs/Localize'; -import isSearchTopmostCentralPane from '@libs/Navigation/isSearchTopmostCentralPane'; +import isSearchTopmostRoute from '@libs/Navigation/isSearchTopmostRoute'; import Navigation from '@libs/Navigation/Navigation'; import * as NextStepUtils from '@libs/NextStepUtils'; import {rand64} from '@libs/NumberUtils'; @@ -3648,7 +3648,7 @@ function requestMoney( } } - Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : activeReportID); + Navigation.dismissModal(isSearchTopmostRoute() ? undefined : activeReportID); if (activeReportID) { Report.notifyNewAction(activeReportID, payeeAccountID); } @@ -3705,7 +3705,7 @@ function sendInvoice( API.write(WRITE_COMMANDS.SEND_INVOICE, parameters, onyxData); - if (isSearchTopmostCentralPane()) { + if (isSearchTopmostRoute()) { Navigation.dismissModal(); } else { Navigation.dismissModalWithReport(invoiceRoom); @@ -3897,7 +3897,7 @@ function trackExpense( API.write(WRITE_COMMANDS.TRACK_EXPENSE, parameters, onyxData); } } - Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : activeReportID); + Navigation.dismissModal(isSearchTopmostRoute() ? undefined : activeReportID); if (action === CONST.IOU.ACTION.SHARE) { Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.navigate(ROUTES.ROOM_INVITE.getRoute(activeReportID ?? '-1', CONST.IOU.SHARE.ROLE.ACCOUNTANT))); @@ -4466,7 +4466,7 @@ function splitBill({ API.write(WRITE_COMMANDS.SPLIT_BILL, parameters, onyxData); - Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : existingSplitChatReportID); + Navigation.dismissModal(isSearchTopmostRoute() ? undefined : existingSplitChatReportID); Report.notifyNewAction(splitData.chatReportID, currentUserAccountID); } @@ -4533,7 +4533,7 @@ function splitBillAndOpenReport({ API.write(WRITE_COMMANDS.SPLIT_BILL_AND_OPEN_REPORT, parameters, onyxData); - Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : splitData.chatReportID); + Navigation.dismissModal(isSearchTopmostRoute() ? undefined : splitData.chatReportID); Report.notifyNewAction(splitData.chatReportID, currentUserAccountID); } @@ -5101,7 +5101,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA }; API.write(WRITE_COMMANDS.COMPLETE_SPLIT_BILL, parameters, {optimisticData, successData, failureData}); - Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : chatReportID); + Navigation.dismissModal(isSearchTopmostRoute() ? undefined : chatReportID); Report.notifyNewAction(chatReportID, sessionAccountID); } @@ -5271,7 +5271,7 @@ function createDistanceRequest( API.write(WRITE_COMMANDS.CREATE_DISTANCE_REQUEST, parameters, onyxData); const activeReportID = isMoneyRequestReport ? report?.reportID ?? '-1' : parameters.chatReportID; - Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : activeReportID); + Navigation.dismissModal(isSearchTopmostRoute() ? undefined : activeReportID); Report.notifyNewAction(activeReportID, userAccountID); } @@ -6952,7 +6952,7 @@ function sendMoneyElsewhere(report: OnyxEntry, amount: number, API.write(WRITE_COMMANDS.SEND_MONEY_ELSEWHERE, params, {optimisticData, successData, failureData}); - Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : params.chatReportID); + Navigation.dismissModal(isSearchTopmostRoute() ? undefined : params.chatReportID); Report.notifyNewAction(params.chatReportID, managerID); } @@ -6965,7 +6965,7 @@ function sendMoneyWithWallet(report: OnyxEntry, amount: number API.write(WRITE_COMMANDS.SEND_MONEY_WITH_WALLET, params, {optimisticData, successData, failureData}); - Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : params.chatReportID); + Navigation.dismissModal(isSearchTopmostRoute() ? undefined : params.chatReportID); Report.notifyNewAction(params.chatReportID, managerID); } diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index d7d359d289f4..b63885679e66 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -12,7 +12,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import isSearchTopmostCentralPane from '@libs/Navigation/isSearchTopmostCentralPane'; +import isSearchTopmostRoute from '@libs/Navigation/isSearchTopmostRoute'; import Navigation from '@libs/Navigation/Navigation'; import type {EditRequestNavigatorParamList} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; @@ -69,14 +69,14 @@ function EditReportFieldPage({route}: EditReportFieldPageProps) { goBack(); } else { ReportActions.updateReportField(report.reportID, {...reportField, value: value === '' ? null : value}, reportField); - Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : report?.reportID); + Navigation.dismissModal(isSearchTopmostRoute() ? undefined : report?.reportID); } }; const handleReportFieldDelete = () => { ReportActions.deleteReportField(report.reportID, reportField); setIsDeleteModalVisible(false); - Navigation.dismissModal(isSearchTopmostCentralPane() ? undefined : report?.reportID); + Navigation.dismissModal(isSearchTopmostRoute() ? undefined : report?.reportID); }; const fieldValue = isReportFieldTitle ? report.reportName ?? '' : reportField.value ?? reportField.defaultValue; diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 6a3f0fb9cf12..61cc569eb5f6 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -34,7 +34,7 @@ jest.mock('@src/libs/Navigation/Navigation', () => ({ goBack: jest.fn(), })); -jest.mock('@src/libs/Navigation/isSearchTopmostCentralPane', () => jest.fn()); +jest.mock('@src/libs/Navigation/isSearchTopmostRoute', () => jest.fn()); const CARLOS_EMAIL = 'cmartins@expensifail.com'; const CARLOS_ACCOUNT_ID = 1; From d0a1b6900f43b317e1beb92f3f2685525494a7d0 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Thu, 24 Oct 2024 17:22:35 +0200 Subject: [PATCH 129/257] fix: Attachment - New attachment window is opened when switching between images --- src/libs/Navigation/linkTo/index.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 24004fe9caf5..a4d799635010 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -10,6 +10,7 @@ import type {RootStackParamList, StackNavigationAction} from '@navigation/types' import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import type {Route} from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; import getMinimalAction from './getMinimalAction'; function createActionWithPolicyID(action: StackActionType, policyID: string): StackActionType | undefined { @@ -47,6 +48,10 @@ function shouldCheckFullScreenRouteMatching(action: StackNavigationAction): acti return action !== undefined && action.type === 'PUSH' && action.payload.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR; } +function isNavigatingToAttachmentScreen(focusedRouteName?: string) { + return focusedRouteName === SCREENS.ATTACHMENTS; +} + export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string) { if (!navigation) { throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); @@ -59,6 +64,7 @@ export default function linkTo(navigation: NavigationContainerRef>; + const focusedRouteFromPath = findFocusedRoute(stateFromPath); const currentState = navigation.getRootState() as NavigationState; const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); @@ -75,7 +81,9 @@ export default function linkTo(navigation: NavigationContainerRef Date: Fri, 25 Oct 2024 08:39:09 +0200 Subject: [PATCH 130/257] Fix issue: Android - No animation when navigating in and out of workspace page --- src/pages/workspace/WorkspacesListPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index ec2839aef4c8..388b75e5286e 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -405,6 +405,7 @@ function WorkspacesListPage() { /> + {shouldUseNarrowLayout && } ); } From f4dd1bf6a41d355009812b0f40c15754380c1ec9 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 25 Oct 2024 09:21:47 +0200 Subject: [PATCH 131/257] Fix issue: Web - Hold - App flickers after entering reason and saving it when holding expense --- src/pages/iou/HoldReasonPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/HoldReasonPage.tsx b/src/pages/iou/HoldReasonPage.tsx index 7523a0932c42..b86c53439e36 100644 --- a/src/pages/iou/HoldReasonPage.tsx +++ b/src/pages/iou/HoldReasonPage.tsx @@ -54,7 +54,7 @@ function HoldReasonPage({route}: HoldReasonPageProps) { } IOU.putOnHold(transactionID, values.comment, reportID, searchHash); - Navigation.navigate(backTo); + Navigation.goBack(backTo); }; const validate = useCallback( From 927c68baaaf49268d0a62eb77e695859af8ea8ef Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 25 Oct 2024 09:42:06 +0200 Subject: [PATCH 132/257] Fix issue: Group - App returns to group settings page after saving group name --- src/pages/GroupChatNameEditPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/GroupChatNameEditPage.tsx b/src/pages/GroupChatNameEditPage.tsx index 425e8a421cb2..5eacb05038a9 100644 --- a/src/pages/GroupChatNameEditPage.tsx +++ b/src/pages/GroupChatNameEditPage.tsx @@ -69,7 +69,7 @@ function GroupChatNameEditPage({groupChatDraft, report}: GroupChatNameEditPagePr if (values[INPUT_IDS.NEW_CHAT_NAME] !== currentChatName) { Report.updateGroupChatName(reportID, values[INPUT_IDS.NEW_CHAT_NAME] ?? ''); } - Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(reportID)); + Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(reportID)); return; } if (values[INPUT_IDS.NEW_CHAT_NAME] !== currentChatName) { From 8cd6ade7b8a3035d7afc738658aaeeeebfd19085 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 25 Oct 2024 11:01:43 +0200 Subject: [PATCH 133/257] Adjust getTopmostReportActionID and cleanup getTopmostReportID --- .../Navigation/getTopmostReportActionID.ts | 25 ++++++------------- src/libs/Navigation/getTopmostReportId.ts | 15 ----------- 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/src/libs/Navigation/getTopmostReportActionID.ts b/src/libs/Navigation/getTopmostReportActionID.ts index d3c6e41887d8..b789d45cc9a6 100644 --- a/src/libs/Navigation/getTopmostReportActionID.ts +++ b/src/libs/Navigation/getTopmostReportActionID.ts @@ -1,5 +1,5 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; -import {isCentralPaneName} from '@libs/NavigationUtils'; +import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import type {RootStackParamList} from './types'; @@ -16,33 +16,24 @@ function getTopmostReportActionID(state: NavigationState | NavigationState isCentralPaneName(route.name)).at(-1); - if (!topmostCentralPane) { + const topmostReportsSplitNavigator = state.routes.filter((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR).at(-1); + if (!topmostReportsSplitNavigator?.state) { return; } - const directReportParams = topmostCentralPane.params; - const directReportActionIDParam = directReportParams && 'reportActionID' in directReportParams && directReportParams?.reportActionID; + const topmostReport = topmostReportsSplitNavigator.state?.routes.filter((route) => route.name === SCREENS.REPORT).at(-1); - if (!topmostCentralPane.state && !directReportActionIDParam) { + if (!topmostReport || !topmostReport?.params) { return; } - if (directReportActionIDParam) { - return directReportActionIDParam; - } - - const topmostReport = topmostCentralPane.state?.routes.filter((route) => route.name === SCREENS.REPORT).at(-1); - if (!topmostReport) { - return; - } + const reportActionID = 'reportActionID' in topmostReport.params && topmostReport.params.reportActionID; - const topmostReportActionID = topmostReport.params && 'reportActionID' in topmostReport.params && topmostReport.params?.reportActionID; - if (typeof topmostReportActionID !== 'string') { + if (typeof reportActionID !== 'string') { return; } - return topmostReportActionID; + return reportActionID; } export default getTopmostReportActionID; diff --git a/src/libs/Navigation/getTopmostReportId.ts b/src/libs/Navigation/getTopmostReportId.ts index d1d8bf2eacfc..0969f46b6b5d 100644 --- a/src/libs/Navigation/getTopmostReportId.ts +++ b/src/libs/Navigation/getTopmostReportId.ts @@ -28,21 +28,6 @@ function getTopmostReportId(state: NavigationState | NavigationState Date: Fri, 25 Oct 2024 13:41:23 +0200 Subject: [PATCH 134/257] Fix issue: QBO - Preferred exporter/Export date tab do not auto-close after value selected --- contributingGuides/NAVIGATION.md | 13 ++++++++++++- src/libs/Navigation/Navigation.ts | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index c04696b7ad1d..9362e6b4026a 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -342,4 +342,15 @@ Linked issue: https://github.com/Expensify/App/pull/44138 2. If there are no messages in the chat, send a message. 3. Press reply in thread. 4. Press the "From" link in the displayed header. -5. Verify if the link correctly redirects to the chat opened in the first step. \ No newline at end of file +5. Verify if the link correctly redirects to the chat opened in the first step. + +#### QBO - Preferred exporter/Export date tab do not auto-close after value selected + +Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2433342220 + +Precondition: Workspace with QBO integration connected. + +1. Go to Workspace > Accounting. +2. Click on Export > Preferred exporter (or Export date). +3. Click on value. +4. Verify if the value chosen in the third step is selected and the app redirects to the Export page. \ No newline at end of file diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 8409101633c3..14aa9ed80a31 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -218,7 +218,7 @@ function goUp(fallbackRoute: Route) { return; } - const distanceToPop = targetState.routes.length - indexOfFallbackRoute - 1; + const distanceToPop = targetState.routes.length - indexOfFallbackRoute; navigationRef.current.dispatch({...StackActions.pop(distanceToPop), target: targetState.key}); } From 2d307714ed4761dc8838c6f942876b9bd9c38cb3 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 25 Oct 2024 14:19:04 +0200 Subject: [PATCH 135/257] Add test steps for issues related to split navigators --- contributingGuides/NAVIGATION.md | 37 +++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index 9362e6b4026a..8910d6ea1b2f 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -344,6 +344,15 @@ Linked issue: https://github.com/Expensify/App/pull/44138 4. Press the "From" link in the displayed header. 5. Verify if the link correctly redirects to the chat opened in the first step. +#### Expense - App does not open destination report after submitting expense + +Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2432400819 + +1. Launch the app. +2. Open FAB > Submit expense > Manual. +3. Submit a manual expense to any user (as long as the user is not the currrently opened report and the receiver is not workspace chat). +4. Verify if the destination report is opened after submitting expense. + #### QBO - Preferred exporter/Export date tab do not auto-close after value selected Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2433342220 @@ -353,4 +362,30 @@ Precondition: Workspace with QBO integration connected. 1. Go to Workspace > Accounting. 2. Click on Export > Preferred exporter (or Export date). 3. Click on value. -4. Verify if the value chosen in the third step is selected and the app redirects to the Export page. \ No newline at end of file +4. Verify if the value chosen in the third step is selected and the app redirects to the Export page. + +#### Web - Hold - App flickers after entering reason and saving it when holding expense + +Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2433389682 + +1. Launch the app. +2. Open DM with any user. +3. Submit two expenses to them. +4. Click on the expense preview to go to expense report. +5. Click on any preview to go to transaction thread. +6. Go back to expense report. +7. Right click on the expense preview in Step 5 > Hold. +8. Enter a reason and save it. +9. Verify if the app does not flicker after entering reason and saving it. + +#### Group - App returns to group settings page after saving group name + +Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2433381800 + +1. Launch the app. +2. Create a group chat. +3. Go to group chat. +4. Click on the group chat header. +5. Click Group name field. +6. Click Save. +7. Verify if the app returs to group details RHP after saving group name. From fac8f6fad7de852f1ee3cd94c9ac24e956ad9ea7 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 25 Oct 2024 15:13:27 +0200 Subject: [PATCH 136/257] fix: Book travel - Unable to select country in company address page --- contributingGuides/NAVIGATION.md | 10 ++++++ src/libs/Navigation/Navigation.ts | 31 +++++++++++++++++-- src/libs/Navigation/linkTo/index.ts | 6 ++-- .../Navigation/linkingConfig/normalizePath.ts | 6 ++++ .../PersonalDetails/CountrySelectionPage.tsx | 17 +++++----- 5 files changed, 55 insertions(+), 15 deletions(-) create mode 100644 src/libs/Navigation/linkingConfig/normalizePath.ts diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index 8910d6ea1b2f..26719aeaca0b 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -389,3 +389,13 @@ Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-243338180 5. Click Group name field. 6. Click Save. 7. Verify if the app returs to group details RHP after saving group name. +#### Going up to a screen with any params + +Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2432694948 + +1. Press the FAB. +2. Select "Book travel". +3. Press "Book travel" in the new RHP pane. +4. Press "Country". +5. Select any country. +6. Verify that the country you selected is actually visible in the form. diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 14aa9ed80a31..601494363a0a 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -161,7 +161,7 @@ function getRouteParamsToCompare(routeParams: Record return omit(routeParams, routeParamsIgnore); } -function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | NavigationPartialRoute, minimalAction: Writable) { +function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | NavigationPartialRoute, minimalAction: Writable, compareParams: boolean) { if (!minimalAction.payload) { return false; } @@ -176,6 +176,10 @@ function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | Navi return false; } + if (!compareParams) { + return true; + } + if (!('params' in minimalAction.payload)) { return false; } @@ -186,7 +190,21 @@ function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | Navi return shallowCompare(routeParams, minimalActionParams); } -function goUp(fallbackRoute: Route) { +type GoUpOptions = { + /** If we should compare params when searching for a route in state to go up to. + * There are situations where we want to compare params when going up e.g. goUp to a specific report. + * Sometimes we want to go up and update params of screen e.g. country picker. + * In that case we want to goUp to a country picker with any params so we don't compare them. */ + compareParams?: boolean; +}; + +const defaultGoUpOptions: Required = { + compareParams: true, +}; + +function goUp(fallbackRoute: Route, options?: GoUpOptions) { + const compareParams = options?.compareParams ?? defaultGoUpOptions.compareParams; + if (!canNavigate('goBack')) { return; } @@ -210,7 +228,7 @@ function goUp(fallbackRoute: Route) { return; } - const indexOfFallbackRoute = targetState.routes.findLastIndex((route) => doesRouteMatchToMinimalActionPayload(route, minimalAction)); + const indexOfFallbackRoute = targetState.routes.findLastIndex((route) => doesRouteMatchToMinimalActionPayload(route, minimalAction, compareParams)); if (indexOfFallbackRoute === -1) { const replaceAction = {...minimalAction, type: 'REPLACE'} as NavigationAction; @@ -218,6 +236,13 @@ function goUp(fallbackRoute: Route) { return; } + // If we are not comparing params, we want to use navigate action because it will replace params in the route already existing in the state if necessary. + // This part will need refactor after migrating to react-navigation 7. We will use popTo instead. + if (!compareParams) { + navigationRef.current.dispatch(minimalAction); + return; + } + const distanceToPop = targetState.routes.length - indexOfFallbackRoute; navigationRef.current.dispatch({...StackActions.pop(distanceToPop), target: targetState.key}); } diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index a4d799635010..669a844a1443 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -2,6 +2,7 @@ import {getActionFromState} from '@react-navigation/core'; import type {NavigationContainerRef, NavigationState, PartialState, StackActionType} from '@react-navigation/native'; import {findFocusedRoute, StackActions} from '@react-navigation/native'; import {getMatchingFullScreenRouteForRoute, isFullScreenName} from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; +import normalizePath from '@libs/Navigation/linkingConfig/normalizePath'; import {shallowCompare} from '@libs/ObjectUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import getStateFromPath from '@navigation/getStateFromPath'; @@ -57,8 +58,9 @@ export default function linkTo(navigation: NavigationContainerRef; -function CountrySelectionPage({route, navigation}: CountrySelectionPageProps) { +function CountrySelectionPage({route}: CountrySelectionPageProps) { const [searchValue, setSearchValue] = useState(''); const {translate} = useLocalize(); const currentCountry = route.params.country; @@ -44,19 +44,16 @@ function CountrySelectionPage({route, navigation}: CountrySelectionPageProps) { const selectCountry = useCallback( (option: CountryData) => { const backTo = route.params.backTo ?? ''; - // Check the navigation state and "backTo" parameter to decide navigation behavior - if (navigation.getState().routes.length === 1 && !backTo) { - // If there is only one route and "backTo" is empty, go back in navigation + + // Check the "backTo" parameter to decide navigation behavior + if (!backTo) { Navigation.goBack(); - } else if (!!backTo && navigation.getState().routes.length === 1) { - // If "backTo" is not empty and there is only one route, go back to the specific route defined in "backTo" with a country parameter - Navigation.goBack(appendParam(backTo, 'country', option.value)); } else { - // Otherwise, navigate to the specific route defined in "backTo" with a country parameter - Navigation.navigate(appendParam(backTo, 'country', option.value)); + // Set compareParams to false because we want to goUp to this particular screen and update params (country). + Navigation.goUp(appendParam(backTo, 'country', option.value), {compareParams: false}); } }, - [route, navigation], + [route], ); return ( From eb8c8825b4f819942543a030a6f77b5039d7b3bd Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 25 Oct 2024 15:18:32 +0200 Subject: [PATCH 137/257] add tests for: Attachment - New attachment window is opened when switching between images --- contributingGuides/NAVIGATION.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index 26719aeaca0b..09039c874a65 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -399,3 +399,14 @@ Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-243269494 4. Press "Country". 5. Select any country. 6. Verify that the country you selected is actually visible in the form. + +### Change params of existing attachments screens instead of pushing new screen on the stack + +Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2432360626 + +1. Open any chat. +2. Send at least two images. +3. Open attachment by pressing on image. +4. Press arrow on the side of attachment modal to navigate to the second image. +5. Close the modal with X in the corner. +6. Verify that the modal is now fully closed. From ec4a01e74ba402b2aa782fb5d3759cde7058e39a Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Mon, 28 Oct 2024 12:00:33 +0100 Subject: [PATCH 138/257] Web - Thread - Highlighted message is not dismissed after clicking on the same chat in LHN --- src/libs/Navigation/linkTo/index.ts | 52 +++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 669a844a1443..3354942aa661 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -7,7 +7,7 @@ import {shallowCompare} from '@libs/ObjectUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import getStateFromPath from '@navigation/getStateFromPath'; import linkingConfig from '@navigation/linkingConfig'; -import type {RootStackParamList, StackNavigationAction} from '@navigation/types'; +import type {NavigationPartialRoute, ReportsSplitNavigatorParamList, RootStackParamList, StackNavigationAction} from '@navigation/types'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import type {Route} from '@src/ROUTES'; @@ -31,18 +31,14 @@ function createActionWithPolicyID(action: StackActionType, policyID: string): St }; } -function shouldDispatchAction(currentState: NavigationState, stateFromPath: PartialState>) { +function areNamesAndParamsEqual(currentState: NavigationState, stateFromPath: PartialState>) { const currentFocusedRoute = findFocusedRoute(currentState); const targetFocusedRoute = findFocusedRoute(stateFromPath); const areNamesEqual = currentFocusedRoute?.name === targetFocusedRoute?.name; const areParamsEqual = shallowCompare(currentFocusedRoute?.params as Record | undefined, targetFocusedRoute?.params as Record | undefined); - if (areNamesEqual && areParamsEqual) { - return false; - } - - return true; + return areNamesEqual && areParamsEqual; } function shouldCheckFullScreenRouteMatching(action: StackNavigationAction): action is StackNavigationAction & {type: 'PUSH'; payload: {name: typeof NAVIGATORS.RIGHT_MODAL_NAVIGATOR}} { @@ -53,6 +49,17 @@ function isNavigatingToAttachmentScreen(focusedRouteName?: string) { return focusedRouteName === SCREENS.ATTACHMENTS; } +function isNavigatingToReportWithSameReportID(currentRoute: NavigationPartialRoute, newRoute: NavigationPartialRoute) { + if (currentRoute.name !== SCREENS.REPORT || newRoute.name !== SCREENS.REPORT) { + return false; + } + + const currentParams = currentRoute.params as ReportsSplitNavigatorParamList[typeof SCREENS.REPORT]; + const newParams = newRoute?.params as ReportsSplitNavigatorParamList[typeof SCREENS.REPORT]; + + return currentParams.reportID === newParams.reportID; +} + export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string) { if (!navigation) { throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); @@ -66,30 +73,47 @@ export default function linkTo(navigation: NavigationContainerRef>; - const focusedRouteFromPath = findFocusedRoute(stateFromPath); const currentState = navigation.getRootState() as NavigationState; - const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); - // We don't want to dispatch action to push/replace with exactly the same route that is already focused. - if (!shouldDispatchAction(currentState, stateFromPath)) { + const focusedRouteFromPath = findFocusedRoute(stateFromPath); + const currentFocusedRoute = findFocusedRoute(currentState); + + // For type safety. It shouldn't every happen. + if (!focusedRouteFromPath || !currentFocusedRoute) { return; } + const action: StackNavigationAction = getActionFromState(stateFromPath, linkingConfig.config); + // If there is no action, just reset the whole state. if (!action) { navigation.resetRoot(stateFromPath); return; } + // We don't want to dispatch action to push/replace with exactly the same route that is already focused. + if (areNamesAndParamsEqual(currentState, stateFromPath)) { + return; + } + if (type === CONST.NAVIGATION.ACTION_TYPE.REPLACE) { action.type = CONST.NAVIGATION.ACTION_TYPE.REPLACE; } - // Attachments screen is a special case where we want to navigate to it without adding it to the browser history. - else if (action.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE && !isNavigatingToAttachmentScreen(focusedRouteFromPath?.name)) { + + // Attachment screen - This is a special case. We want to navigate to it instead of push. If there is no screen on the stack, it will be pushed. + // If not, it will be replaced. This way, navigating between one attachment screen and another won't be added to the browser history. + // Report screen - Also a special case. If we are navigating to the report with same reportID we want to replace it (navigate will do that). + // This covers the case when we open a specific message in report (reportActionID). + else if ( + action.type === CONST.NAVIGATION.ACTION_TYPE.NAVIGATE && + !isNavigatingToAttachmentScreen(focusedRouteFromPath?.name) && + !isNavigatingToReportWithSameReportID(currentFocusedRoute, focusedRouteFromPath) + ) { // We want to PUSH by default to add entries to the browser history. action.type = CONST.NAVIGATION.ACTION_TYPE.PUSH; } + // Handle deep links including policyID as /w/:policyID. if (extractedPolicyID) { const actionWithPolicyID = createActionWithPolicyID(action as StackActionType, extractedPolicyID); if (!actionWithPolicyID) { @@ -100,7 +124,7 @@ export default function linkTo(navigation: NavigationContainerRef Date: Mon, 28 Oct 2024 12:27:12 +0100 Subject: [PATCH 139/257] fix typo --- src/libs/Navigation/linkTo/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 3354942aa661..b0fae536186f 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -78,7 +78,7 @@ export default function linkTo(navigation: NavigationContainerRef Date: Mon, 28 Oct 2024 12:38:09 +0100 Subject: [PATCH 140/257] add test --- contributingGuides/NAVIGATION.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index 09039c874a65..8079bb41f5b1 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -410,3 +410,17 @@ Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-243236062 4. Press arrow on the side of attachment modal to navigate to the second image. 5. Close the modal with X in the corner. 6. Verify that the modal is now fully closed. + +### Navigate instead of push for reports with same reportID + +Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2433351709 + +1. Open app on wide layout web. +2. Go to report A (any report). +3. Go to report B (any report with message). +4. Press reply in thread. +5. Press on header subtitle. +6. Press on the report B in the sidebar. +7. Verify that the message you replied to is no longer highlighted. +8. Press the browsers back button. +9. Verify that you are on the A report. \ No newline at end of file From 868b3052e930ae19f9bd7ccac7f85ca07ff98353 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 28 Oct 2024 14:50:48 +0100 Subject: [PATCH 141/257] Fix issue: BA - Back button on connect bank account modal opens incorporation state modal --- src/components/StateSelector.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/StateSelector.tsx b/src/components/StateSelector.tsx index e2be9281d0bb..5248af98cfac 100644 --- a/src/components/StateSelector.tsx +++ b/src/components/StateSelector.tsx @@ -91,7 +91,7 @@ function StateSelector( onPress={() => { const activeRoute = Navigation.getActiveRoute(); didOpenStateSelector.current = true; - Navigation.navigate(stateSelectorRoute.getRoute(stateCode, activeRoute, label)); + Navigation.goUp(stateSelectorRoute.getRoute(stateCode, activeRoute, label), {compareParams: false}); }} wrapperStyle={wrapperStyle} /> From fb326c3b2680e3f0b9cd4ce4207aa710eb01cb6e Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Mon, 28 Oct 2024 14:50:50 +0100 Subject: [PATCH 142/257] fix passing params from rhp in adapted state --- .../linkingConfig/getAdaptedStateFromPath.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 933dd1b2c594..76301f904878 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -67,7 +67,7 @@ function getMatchingFullScreenRouteForRoute(route: NavigationPartialRoute, polic return { name: SCREENS.SEARCH.CENTRAL_PANE, - params: pick(route.params, paramsFromRoute), + params: paramsFromRoute.length > 0 ? pick(route.params, paramsFromRoute) : undefined, }; } @@ -84,23 +84,22 @@ function getMatchingFullScreenRouteForRoute(route: NavigationPartialRoute, polic // @TODO We can think about handling it in one condition. if (RELATIONS.RHP_TO_WORKSPACE[route.name]) { - const paramsFromRoute = getParamsFromRoute(SCREENS.SEARCH.CENTRAL_PANE); + const paramsFromRoute = getParamsFromRoute(RELATIONS.RHP_TO_WORKSPACE[route.name]); return createSplitNavigator( { name: SCREENS.WORKSPACE.INITIAL, + params: paramsFromRoute.length > 0 ? pick(route.params, paramsFromRoute) : undefined, }, { name: RELATIONS.RHP_TO_WORKSPACE[route.name] as keyof WorkspaceSplitNavigatorParamList, - params: { - ...pick(route.params, paramsFromRoute), - }, + params: paramsFromRoute.length > 0 ? pick(route.params, paramsFromRoute) : undefined, }, ); } if (RELATIONS.RHP_TO_SETTINGS[route.name]) { - const paramsFromRoute = getParamsFromRoute(SCREENS.SEARCH.CENTRAL_PANE); + const paramsFromRoute = getParamsFromRoute(RELATIONS.RHP_TO_SETTINGS[route.name]); return createSplitNavigator( { @@ -108,9 +107,7 @@ function getMatchingFullScreenRouteForRoute(route: NavigationPartialRoute, polic }, { name: RELATIONS.RHP_TO_SETTINGS[route.name] as keyof SettingsSplitNavigatorParamList, - params: { - ...pick(route.params, paramsFromRoute), - }, + params: paramsFromRoute.length > 0 ? pick(route.params, paramsFromRoute) : undefined, }, ); } @@ -205,7 +202,6 @@ const getAdaptedStateFromPath: GetAdaptedStateFromPath = (path, options, shouldR // On SCREENS.SEARCH.CENTRAL_PANE policyID is stored differently inside search query ("q" param), so we're handling this case const focusedRoute = findFocusedRoute(state); const policyIDFromQuery = extractPolicyIDFromQuery(focusedRoute); - return getAdaptedState(state, policyID ?? policyIDFromQuery); }; From b9a1119950a01094915ec8ce5ed8f0572c5b3fe9 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Mon, 28 Oct 2024 17:46:52 +0100 Subject: [PATCH 143/257] fix Search - App returns to Inbox after deleting expense from report RHP in Search --- src/libs/ReportUtils.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 9570e9c131bc..b6d07df578e7 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -75,6 +75,7 @@ import {isEmailPublicDomain} from './LoginUtils'; import ModifiedExpenseMessage from './ModifiedExpenseMessage'; import linkingConfig from './Navigation/linkingConfig'; import Navigation, {navigationRef} from './Navigation/Navigation'; +import {isFullScreenName} from './NavigationUtils'; import * as NumberUtils from './NumberUtils'; import Parser from './Parser'; import Permissions from './Permissions'; @@ -4115,10 +4116,10 @@ function navigateBackAfterDeleteTransaction(backRoute: Route | undefined, isFrom if (!backRoute) { return; } - // @TODO: Verify if this method works correctly + const rootState = navigationRef.current?.getRootState(); - const topmostRoute = rootState?.routes.at(-1); - if (topmostRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { + const lastFullScreenRoute = rootState?.routes.findLast((route) => isFullScreenName(route.name)); + if (lastFullScreenRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { Navigation.dismissModal(); return; } From 30c974815a43d9fcd1edbc16f8a67f7bece63a81 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 29 Oct 2024 13:41:40 +0100 Subject: [PATCH 144/257] add comments to RELATIONS files --- .../linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts | 1 + .../linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts | 1 + .../Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts | 1 + src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts | 1 + src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts | 2 +- src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts | 2 ++ src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT.ts | 1 + .../linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts | 1 + .../linkingConfig/RELATIONS/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts | 1 + src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts | 1 + 10 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts index a9dabb1cb903..97818be80de5 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts @@ -1,3 +1,4 @@ +// @TODO: Remove this file before merging to the main. import type {SplitNavigatorScreenName} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; import WORKSPACE_SCREEN_TO_RHP_MAPPING from './WORKSPACE_SCREEN_TO_RHP_MAPPING'; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts index 963f8e1a1712..2871d34adaf8 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts @@ -1,3 +1,4 @@ +// @TODO remove this file before merging to the main. import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts index 86dbdbf1d253..48422f90a7bc 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts @@ -1,3 +1,4 @@ +// @TODO Remove this file before merging to the main. import SCREENS from '@src/SCREENS'; const SEARCH_RHP_SCREENS: string[] = [ diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts index 9d50f1735d94..3b9018f36ae3 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_TO_RHP.ts @@ -1,5 +1,6 @@ import SCREENS from '@src/SCREENS'; +// This file is used to define RHP screens that are in relation to the search screen. const SEARCH_TO_RHP: string[] = [ SCREENS.SEARCH.REPORT_RHP, SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP, diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts index f89495cf772c..b4afc15366d3 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts @@ -1,6 +1,6 @@ import SCREENS from '@src/SCREENS'; -// const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = { +// This file is used to define relation between settings split navigator's central screens and RHP screens. const CENTRAL_PANE_TO_RHP_MAPPING: Record = { [SCREENS.SETTINGS.PROFILE.ROOT]: [ SCREENS.SETTINGS.PROFILE.DISPLAY_NAME, diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts index d6ace93cd1e6..246c9d29a664 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts @@ -1,5 +1,7 @@ import SCREENS from '@src/SCREENS'; +// This file is used to define the relationship between the sidebar (LHN) and the right hand pane (RHP) screen. +// Those screens doesn't care about the split navigator's central screen and are in relation directly to the sidebar. const SIDEBAR_TO_RHP: Record = { [SCREENS.SETTINGS.ROOT]: [ SCREENS.SETTINGS.SHARE_CODE, diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT.ts index 597f6dcd4ccb..c4d18632ca68 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT.ts @@ -1,6 +1,7 @@ import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; +// This file is used to define the relationship between the sidebar (LHN) and the parent split navigator. const SIDEBAR_TO_SPLIT = { [SCREENS.SETTINGS.ROOT]: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, [SCREENS.HOME]: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts index c5f624bb5587..943552f929b8 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts @@ -1,3 +1,4 @@ +// @TODO Remove this file before merging to the main. import type {SplitNavigatorLHNScreen, SplitNavigatorScreenName} from '@navigation/types'; import SCREENS from '@src/SCREENS'; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts index b49edd0e649e..73306c55dcab 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts @@ -1,3 +1,4 @@ +// @TODO: Remove this file after before merging to the main import type {WorkspaceScreenName} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts index 37119bb64fdb..39062de76510 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts @@ -1,5 +1,6 @@ import SCREENS from '@src/SCREENS'; +// This file is used to define relation between workspace split navigator's central screens and RHP screens. const WORKSPACE_TO_RHP: Record = { [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.ADDRESS, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE], [SCREENS.WORKSPACE.MEMBERS]: [ From 8fcd73cf02dbb0b5661af1524610e042bc5ce986 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 29 Oct 2024 13:42:51 +0100 Subject: [PATCH 145/257] fix Submitting expense flow from tabs different than inbox --- .../linkingConfig/getAdaptedStateFromPath.ts | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 76301f904878..2d36797d0a59 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -34,8 +34,6 @@ function isRouteWithReportID(route: NavigationPartialRoute): route is Route>, policyID?: string): GetAdaptedStateReturnType { @@ -169,11 +175,11 @@ function getAdaptedState(state: PartialState } } - const reportSplitParams = policyID ? {policyID} : undefined; + const defaultFullScreenRoute = getDefaultFullScreenRouteForRoute(focusedRoute, policyID); // If not, add the default full screen route. return { - adaptedState: getRoutesWithIndex([{name: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, params: reportSplitParams}, ...state.routes]), + adaptedState: getRoutesWithIndex([defaultFullScreenRoute, ...state.routes]), }; } From 84f15437a3f93fa27106cf55d19ab7504de41e52 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 29 Oct 2024 13:47:19 +0100 Subject: [PATCH 146/257] remove forRoute suffix --- src/libs/Navigation/linkTo/index.ts | 4 ++-- .../linkingConfig/getAdaptedStateFromPath.ts | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index b0fae536186f..9925980d37b8 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -1,7 +1,7 @@ import {getActionFromState} from '@react-navigation/core'; import type {NavigationContainerRef, NavigationState, PartialState, StackActionType} from '@react-navigation/native'; import {findFocusedRoute, StackActions} from '@react-navigation/native'; -import {getMatchingFullScreenRouteForRoute, isFullScreenName} from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; +import {getMatchingFullScreenRoute, isFullScreenName} from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; import normalizePath from '@libs/Navigation/linkingConfig/normalizePath'; import {shallowCompare} from '@libs/ObjectUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; @@ -128,7 +128,7 @@ export default function linkTo(navigation: NavigationContainerRef isFullScreenName(route.name)); if (matchingFullScreenRoute && lastFullScreenRoute && matchingFullScreenRoute.name !== lastFullScreenRoute.name) { diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 2d36797d0a59..d3116eb15e8d 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -33,7 +33,7 @@ function isRouteWithReportID(route: NavigationPartialRoute): route is Route const focusedRoute = findFocusedRoute(state); if (focusedRoute) { - const matchingRootRoute = getMatchingFullScreenRouteForRoute(focusedRoute, policyID); + const matchingRootRoute = getMatchingFullScreenRoute(focusedRoute, policyID); // If there is a matching root route, add it to the state. if (matchingRootRoute) { return { @@ -175,7 +175,7 @@ function getAdaptedState(state: PartialState } } - const defaultFullScreenRoute = getDefaultFullScreenRouteForRoute(focusedRoute, policyID); + const defaultFullScreenRoute = getDefaultFullScreenRoute(focusedRoute, policyID); // If not, add the default full screen route. return { @@ -212,4 +212,4 @@ const getAdaptedStateFromPath: GetAdaptedStateFromPath = (path, options, shouldR }; export default getAdaptedStateFromPath; -export {getMatchingFullScreenRouteForRoute, isFullScreenName}; +export {getMatchingFullScreenRoute, isFullScreenName}; From 21e1863af999e4e52c0c4b2302519fc7984a524a Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Tue, 29 Oct 2024 13:53:06 +0100 Subject: [PATCH 147/257] add tests --- contributingGuides/NAVIGATION.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index 8079bb41f5b1..7805934961a1 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -423,4 +423,12 @@ Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-243335170 6. Press on the report B in the sidebar. 7. Verify that the message you replied to is no longer highlighted. 8. Press the browsers back button. -9. Verify that you are on the A report. \ No newline at end of file +9. Verify that you are on the A report. + + +### Don't push the default full screen route if not necessary. + +1. Open app on wide layout web. +2. Open search tab. +3. Press track expense. +4. Verify that the split navigator hasn't changed under the overlay. \ No newline at end of file From 92e47ac39c88488cf4d0c0f01d0466f110478bb3 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 29 Oct 2024 15:16:10 +0100 Subject: [PATCH 148/257] Fix issue: Android - Offline indicator is below the app navigation bar --- src/components/ScreenWrapper.tsx | 5 +++++ src/pages/Search/SearchPageBottomTab.tsx | 2 +- src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx | 2 +- src/pages/settings/InitialSettingsPage.tsx | 2 +- src/pages/workspace/WorkspaceInitialPage.tsx | 2 +- src/pages/workspace/WorkspacesListPage.tsx | 4 ++-- 6 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/components/ScreenWrapper.tsx b/src/components/ScreenWrapper.tsx index 152a14fc3eb7..90641e97221f 100644 --- a/src/components/ScreenWrapper.tsx +++ b/src/components/ScreenWrapper.tsx @@ -41,6 +41,9 @@ type ScreenWrapperProps = { /** Returns a function as a child to pass insets to or a node to render without insets */ children: ReactNode | React.FC; + /** Content to display under the offline indicator */ + bottomContent?: ReactNode; + /** A unique ID to find the screen wrapper in tests */ testID: string; @@ -132,6 +135,7 @@ function ScreenWrapper( shouldShowOfflineIndicatorInWideScreen = false, shouldUseCachedViewportHeight = false, focusTrapSettings, + bottomContent, }: ScreenWrapperProps, ref: ForwardedRef, ) { @@ -306,6 +310,7 @@ function ScreenWrapper( )} + {bottomContent} diff --git a/src/pages/Search/SearchPageBottomTab.tsx b/src/pages/Search/SearchPageBottomTab.tsx index ee73a1b5f8aa..e0f1124a39d1 100644 --- a/src/pages/Search/SearchPageBottomTab.tsx +++ b/src/pages/Search/SearchPageBottomTab.tsx @@ -89,6 +89,7 @@ function SearchPageBottomTab({queryJSON, policyID, searchName}: SearchPageBottom } > {!selectionMode?.isEnabled ? ( <> @@ -121,7 +122,6 @@ function SearchPageBottomTab({queryJSON, policyID, searchName}: SearchPageBottom onSearchListScroll={scrollHandler} contentContainerStyle={!selectionMode?.isEnabled ? [styles.searchListContentContainerStyles] : undefined} /> - ); } diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx index 0dbd5b418c34..6a97c3a66612 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx @@ -50,6 +50,7 @@ function BaseSidebarScreen() { shouldEnableKeyboardAvoidingView={false} style={[styles.sidebar, Browser.isMobile() ? styles.userSelectNone : {}]} testID={BaseSidebarScreen.displayName} + bottomContent={} > {({insets}) => ( <> @@ -64,7 +65,6 @@ function BaseSidebarScreen() { insets={insets} /> - )} diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 71603aed283f..a6f1660a2271 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -408,6 +408,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr } > {headerContent} toggleSignoutConfirmModal(false)} /> - ); } diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 2aaa7941b5e8..7792d0412d8a 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -367,6 +367,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac } > - ); diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 388b75e5286e..e47436ab5a8a 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -378,6 +378,7 @@ function WorkspacesListPage() { shouldEnableMaxHeight testID={WorkspacesListPage.displayName} shouldShowOfflineIndicatorInWideScreen + bottomContent={shouldUseNarrowLayout && } > - {shouldUseNarrowLayout && } ); } @@ -415,6 +415,7 @@ function WorkspacesListPage() { shouldEnablePickerAvoiding={false} shouldShowOfflineIndicatorInWideScreen testID={WorkspacesListPage.displayName} + bottomContent={shouldUseNarrowLayout && } > - {shouldUseNarrowLayout && } ); } From f4d7f2e4e1998aa4101f348435dbbf7cdd7c5e63 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 30 Oct 2024 10:27:34 +0100 Subject: [PATCH 149/257] Fix issue: Expensify Card - App crashes when opening fields in Card details page when opened from WS chat --- src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx b/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx index ddaec5c1e131..12a98f7b25f9 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceCardsListLabel.tsx @@ -1,6 +1,6 @@ import type {RouteProp} from '@react-navigation/native'; import {useRoute} from '@react-navigation/native'; -import {useEffect, useMemo, useRef, useState} from 'react'; +import React, {useEffect, useMemo, useRef, useState} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; From 4c7c320bbd79bdb6a753b1fc3408b42c0f62b3bc Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 30 Oct 2024 12:23:38 +0100 Subject: [PATCH 150/257] Fix issue: Expensify Card - Back button on profile returns to member selection page after issuing card --- src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx b/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx index 0170ff04ca6a..cb9e5006f76d 100644 --- a/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx +++ b/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx @@ -49,7 +49,7 @@ function ConfirmationStep({policyID, backTo}: ConfirmationStepProps) { if (!isSuccessful) { return; } - Navigation.navigate(backTo ?? ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID ?? '-1')); + Navigation.goUp(backTo ?? ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID ?? '-1')); Card.clearIssueNewCardFlow(); }, [backTo, policyID, isSuccessful]); From 6dde5fd4284c7bc72fe289ed2b7a023a4e3a91ed Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 30 Oct 2024 12:49:49 +0100 Subject: [PATCH 151/257] Fix issue: Workflow - Not here Page appears when editing first approver --- .../approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx index 9b5e00559379..9c8ee84a1da8 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx @@ -1,3 +1,4 @@ +import {useNavigationState} from '@react-navigation/native'; import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import type {SectionListData} from 'react-native'; @@ -63,6 +64,7 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa const isInitialCreationFlow = approvalWorkflow?.action === CONST.APPROVAL_WORKFLOW.ACTION.CREATE && !route.params.backTo; const defaultApprover = policy?.approver ?? policy?.owner; const firstApprover = approvalWorkflow?.approvers?.[0]?.email ?? ''; + const rhpRoutes = useNavigationState((state) => state.routes); useEffect(() => { const currentApprover = approvalWorkflow?.approvers[approverIndex]; @@ -163,9 +165,11 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa if (approvalWorkflow?.action === CONST.APPROVAL_WORKFLOW.ACTION.CREATE) { Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_NEW.getRoute(route.params.policyID)); } else { - Navigation.goBack(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_EDIT.getRoute(route.params.policyID, firstApprover)); + // If in the navigation state we have a RHP page to which we can return, then we call Navigation.goBack without any parameters + const backTo = rhpRoutes.length > 1 ? undefined : ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_EDIT.getRoute(route.params.policyID, firstApprover); + Navigation.goBack(backTo); } - }, [approvalWorkflow?.action, firstApprover, approverIndex, personalDetails, employeeList, route.params.policyID, selectedApproverEmail]); + }, [selectedApproverEmail, approvalWorkflow?.action, employeeList, personalDetails, approverIndex, route.params.policyID, rhpRoutes.length, firstApprover]); const button = useMemo(() => { let buttonText = isInitialCreationFlow ? translate('common.next') : translate('common.save'); From dfdd15d558ed539377006ef72f2892e43b371103 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 30 Oct 2024 14:48:37 +0100 Subject: [PATCH 152/257] Fix issue: Android - Expensify card - Directed to connect bank account page briefly before navigating to company info --- src/components/StateSelector.tsx | 2 +- .../PersonalDetails/StateSelectionPage.tsx | 29 +++++-------------- 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/components/StateSelector.tsx b/src/components/StateSelector.tsx index 5248af98cfac..e2be9281d0bb 100644 --- a/src/components/StateSelector.tsx +++ b/src/components/StateSelector.tsx @@ -91,7 +91,7 @@ function StateSelector( onPress={() => { const activeRoute = Navigation.getActiveRoute(); didOpenStateSelector.current = true; - Navigation.goUp(stateSelectorRoute.getRoute(stateCode, activeRoute, label), {compareParams: false}); + Navigation.navigate(stateSelectorRoute.getRoute(stateCode, activeRoute, label)); }} wrapperStyle={wrapperStyle} /> diff --git a/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx b/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx index 2a42f1922bf8..6771820d7ace 100644 --- a/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx @@ -1,6 +1,5 @@ -import {useNavigation, useRoute} from '@react-navigation/native'; +import {useRoute} from '@react-navigation/native'; import {CONST as COMMON_CONST} from 'expensify-common'; -import isEmpty from 'lodash/isEmpty'; import React, {useCallback, useMemo, useState} from 'react'; import {View} from 'react-native'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -9,8 +8,8 @@ import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; import Navigation from '@libs/Navigation/Navigation'; -import searchCountryOptions from '@libs/searchCountryOptions'; import type {CountryData} from '@libs/searchCountryOptions'; +import searchCountryOptions from '@libs/searchCountryOptions'; import StringUtils from '@libs/StringUtils'; import {appendParam} from '@libs/Url'; import type {Route} from '@src/ROUTES'; @@ -25,7 +24,6 @@ type RouteParams = { function StateSelectionPage() { const route = useRoute(); - const navigation = useNavigation(); const {translate} = useLocalize(); const [searchValue, setSearchValue] = useState(''); @@ -57,26 +55,15 @@ function StateSelectionPage() { (option: CountryData) => { const backTo = params?.backTo ?? ''; - // Determine navigation action based on "backTo" presence and route stack length. - if (navigation.getState()?.routes.length === 1) { - // If this is the only page in the navigation stack (examples include direct navigation to this page via URL or page reload). - if (isEmpty(backTo)) { - // No "backTo": default back navigation. - Navigation.goBack(); - } else { - // "backTo" provided: navigate back to "backTo" with state parameter. - Navigation.goBack(appendParam(backTo, 'state', option.value)); - } - } else if (!isEmpty(backTo)) { - // Most common case: Navigation stack has multiple routes and "backTo" is defined: navigate to "backTo" with state parameter. - Navigation.navigate(appendParam(backTo, 'state', option.value)); - } else { - // This is a fallback block and should never execute if StateSelector is correctly appending the "backTo" route. - // Navigation stack has multiple routes but no "backTo" defined: default back navigation. + // Check the "backTo" parameter to decide navigation behavior + if (!backTo) { Navigation.goBack(); + } else { + // Set compareParams to false because we want to goUp to this particular screen and update params (state). + Navigation.goUp(appendParam(backTo, 'state', option.value), {compareParams: false}); } }, - [navigation, params?.backTo], + [params?.backTo], ); return ( From 27a356d1bbf83df1fab38bcda8f5f8cb28054d55 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 30 Oct 2024 15:08:18 +0100 Subject: [PATCH 153/257] Add a test for bank account flow --- contributingGuides/NAVIGATION.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index 7805934961a1..0fcb2b5de756 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -389,6 +389,7 @@ Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-243338180 5. Click Group name field. 6. Click Save. 7. Verify if the app returs to group details RHP after saving group name. + #### Going up to a screen with any params Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2432694948 @@ -400,7 +401,7 @@ Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-243269494 5. Select any country. 6. Verify that the country you selected is actually visible in the form. -### Change params of existing attachments screens instead of pushing new screen on the stack +#### Change params of existing attachments screens instead of pushing new screen on the stack Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2432360626 @@ -411,7 +412,7 @@ Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-243236062 5. Close the modal with X in the corner. 6. Verify that the modal is now fully closed. -### Navigate instead of push for reports with same reportID +#### Navigate instead of push for reports with same reportID Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2433351709 @@ -426,9 +427,24 @@ Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-243335170 9. Verify that you are on the A report. -### Don't push the default full screen route if not necessary. +#### Don't push the default full screen route if not necessary. 1. Open app on wide layout web. 2. Open search tab. 3. Press track expense. -4. Verify that the split navigator hasn't changed under the overlay. \ No newline at end of file +4. Verify that the split navigator hasn't changed under the overlay. + +#### BA - Back button on connect bank account modal opens incorporation state modal + +Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2433261611 + +Precondition: Use staging server (it can be set in Settings >> Troubleshoot) + +1. Launch the app. +2. Navigate to Settings >> Workspaces >> Workspace >> Workflows. +3. Select Connect with Plaid option. +4. Go through the Plaid flow (Added Wells Fargo details). +5. Complete the Personal info, Company info & agreements section. +6. Note user redirected to page with the header Connect bank account and the option to disconnect your now set up bank account. +7. Tap back button on connect bank account modal. +8. Verify if the connect bank account modal is closed and the Workflows page is opened with the bank account added. \ No newline at end of file From 8fa61a2739e040e41c14b1b12842b33ea921e694 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 30 Oct 2024 18:24:14 +0100 Subject: [PATCH 154/257] Fix issue: App opens room details page when tapping RHP back button after saving Private notes in DM --- contributingGuides/NAVIGATION.md | 14 +++++++++++++- src/pages/PrivateNotes/PrivateNotesListPage.tsx | 11 ++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index 0fcb2b5de756..9828601c8559 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -447,4 +447,16 @@ Precondition: Use staging server (it can be set in Settings >> Troubleshoot) 5. Complete the Personal info, Company info & agreements section. 6. Note user redirected to page with the header Connect bank account and the option to disconnect your now set up bank account. 7. Tap back button on connect bank account modal. -8. Verify if the connect bank account modal is closed and the Workflows page is opened with the bank account added. \ No newline at end of file +8. Verify if the connect bank account modal is closed and the Workflows page is opened with the bank account added. + +#### App opens room details page when tapping RHP back button after saving Private notes in DM + +Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-2433321607 + +1. Launch the app. +2. Open DM with any user that does not have content in Private notes. +3. Click on the chat header. +4. Click Private notes. +5. Enter anything and click Save. +6. Click on the RHP back button. +7. Verify if the Profile RHP Page is opened (URL in the format /a/:accountID). \ No newline at end of file diff --git a/src/pages/PrivateNotes/PrivateNotesListPage.tsx b/src/pages/PrivateNotes/PrivateNotesListPage.tsx index 474075d928f8..7800fa942700 100644 --- a/src/pages/PrivateNotes/PrivateNotesListPage.tsx +++ b/src/pages/PrivateNotes/PrivateNotesListPage.tsx @@ -13,6 +13,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import type {PrivateNotesNavigatorParamList} from '@libs/Navigation/types'; +import * as ReportUtils from '@libs/ReportUtils'; import type {WithReportAndPrivateNotesOrNotFoundProps} from '@pages/home/report/withReportAndPrivateNotesOrNotFound'; import withReportAndPrivateNotesOrNotFound from '@pages/home/report/withReportAndPrivateNotesOrNotFound'; import CONST from '@src/CONST'; @@ -93,7 +94,15 @@ function PrivateNotesListPage({report, accountID: sessionAccountID}: PrivateNote Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID, backTo))} + onBackButtonPress={() => { + if (ReportUtils.isOneOnOneChat(report)) { + const participantAccountIDs = ReportUtils.getParticipantsAccountIDsForDisplay(report); + Navigation.goBack(ROUTES.PROFILE.getRoute(participantAccountIDs.at(0), backTo)); + return; + } + + Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID, backTo)); + }} onCloseButtonPress={() => Navigation.dismissModal()} /> Date: Thu, 31 Oct 2024 12:22:09 +0100 Subject: [PATCH 155/257] Fix counting distanceToPop in goBack --- src/libs/Navigation/Navigation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 601494363a0a..1579fe4f5238 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -243,7 +243,7 @@ function goUp(fallbackRoute: Route, options?: GoUpOptions) { return; } - const distanceToPop = targetState.routes.length - indexOfFallbackRoute; + const distanceToPop = targetState.routes.length - indexOfFallbackRoute - 1; navigationRef.current.dispatch({...StackActions.pop(distanceToPop), target: targetState.key}); } From 75c3f1851aa10b2d6454236e97c0e290524cd228 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 31 Oct 2024 12:34:25 +0100 Subject: [PATCH 156/257] Fix fallbackRoute in selectExportDate in QuickbooksExportDateSelectPage --- .../accounting/qbo/export/QuickbooksExportDateSelectPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/accounting/qbo/export/QuickbooksExportDateSelectPage.tsx b/src/pages/workspace/accounting/qbo/export/QuickbooksExportDateSelectPage.tsx index e094fe355218..b7ed81954af6 100644 --- a/src/pages/workspace/accounting/qbo/export/QuickbooksExportDateSelectPage.tsx +++ b/src/pages/workspace/accounting/qbo/export/QuickbooksExportDateSelectPage.tsx @@ -39,7 +39,7 @@ function QuickbooksExportDateSelectPage({policy}: WithPolicyConnectionsProps) { if (row.value !== exportDate) { QuickbooksOnline.updateQuickbooksOnlineExportDate(policyID, row.value, exportDate); } - Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT.getRoute(policyID)); + Navigation.goBack(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_EXPORT.getRoute(policyID)); }, [policyID, exportDate], ); From 8e44d8764e7703e18942c76452c128e8189949b2 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 31 Oct 2024 16:44:04 +0100 Subject: [PATCH 157/257] Adjust goUp to handle navigating back when targetState is rootState --- src/libs/Navigation/Navigation.ts | 10 ++++++++-- src/pages/home/sidebar/BottomTabAvatar.tsx | 5 ++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 1579fe4f5238..6b6c2d780cb0 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -202,6 +202,10 @@ const defaultGoUpOptions: Required = { compareParams: true, }; +function isRootNavigatorState(state: State): state is State { + return state.key === navigationRef.current?.getRootState().key; +} + function goUp(fallbackRoute: Route, options?: GoUpOptions) { const compareParams = options?.compareParams ?? defaultGoUpOptions.compareParams; @@ -230,7 +234,10 @@ function goUp(fallbackRoute: Route, options?: GoUpOptions) { const indexOfFallbackRoute = targetState.routes.findLastIndex((route) => doesRouteMatchToMinimalActionPayload(route, minimalAction, compareParams)); - if (indexOfFallbackRoute === -1) { + const distanceToPop = targetState.routes.length - indexOfFallbackRoute - 1; + + // If we need to pop more than one route from rootState, we replace the current route to not lose visited routes from the navigation state + if (indexOfFallbackRoute === -1 || (isRootNavigatorState(targetState) && distanceToPop > 1)) { const replaceAction = {...minimalAction, type: 'REPLACE'} as NavigationAction; navigationRef.current.dispatch(replaceAction); return; @@ -243,7 +250,6 @@ function goUp(fallbackRoute: Route, options?: GoUpOptions) { return; } - const distanceToPop = targetState.routes.length - indexOfFallbackRoute - 1; navigationRef.current.dispatch({...StackActions.pop(distanceToPop), target: targetState.key}); } diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index d3f9a9fb76fa..631287f544a8 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -50,7 +50,10 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT } if (route.name === SCREENS.WORKSPACE.INITIAL) { - Navigation.goUp(ROUTES.SETTINGS_WORKSPACES); + Navigation.goUp(ROUTES.SETTINGS); + if (shouldUseNarrowLayout) { + Navigation.navigate(ROUTES.SETTINGS, CONST.NAVIGATION.ACTION_TYPE.REPLACE); + } return; } From 4c2c1804fb96cdaa27a19e835a11b8971684eb14 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 4 Nov 2024 13:57:07 +0100 Subject: [PATCH 158/257] Fix issue: Track expense - Member list opens again after clicking back button on member list --- src/pages/iou/request/step/IOURequestStepConfirmation.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index aa3a432a0e5a..7448ad0afb0f 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -195,7 +195,7 @@ function IOURequestStepConfirmation({ // back to the participants step if (!transaction?.participantsAutoAssigned && participantsAutoAssignedFromRoute !== 'true') { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, transaction?.reportID || reportID, undefined, action)); + Navigation.goUp(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, transaction?.reportID || reportID, undefined, action), {compareParams: false}); return; } IOUUtils.navigateToStartMoneyRequestStep(requestType, iouType, transactionID, reportID, action); From 65b6c89630e60bc59c2b65fe03fa98378a0c971a Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 4 Nov 2024 13:58:03 +0100 Subject: [PATCH 159/257] Adjust getAdaptedState to handle OnboardingModalNavigator --- .../linkingConfig/getAdaptedStateFromPath.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index d3116eb15e8d..c86635fb18bd 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -145,9 +145,26 @@ function getDefaultFullScreenRoute(route?: NavigationPartialRoute, policyID?: st return fallbackRoute; } +function getOnboardingAdaptedState(state: PartialState): PartialState { + const onboardingRoute = state.routes.at(0); + if (!onboardingRoute || onboardingRoute.name === SCREENS.ONBOARDING.PURPOSE) { + return state; + } + + const routes = []; + routes.push({name: SCREENS.ONBOARDING.PURPOSE}); + if (onboardingRoute.name === SCREENS.ONBOARDING.ACCOUNTING) { + routes.push({name: SCREENS.ONBOARDING.EMPLOYEES}); + } + routes.push(onboardingRoute); + + return getRoutesWithIndex(routes); +} + function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { const fullScreenRoute = state.routes.find((route) => isFullScreenName(route.name)); const reportsSplitNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + const onboardingNavigator = state.routes.find((route) => route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR); // If policyID is defined, it should be passed to the reportNavigator params. if (reportsSplitNavigator && policyID) { @@ -177,6 +194,17 @@ function getAdaptedState(state: PartialState const defaultFullScreenRoute = getDefaultFullScreenRoute(focusedRoute, policyID); + if (onboardingNavigator?.state) { + const adaptedOnboardingNavigator = { + ...onboardingNavigator, + state: getOnboardingAdaptedState(onboardingNavigator.state), + }; + + return { + adaptedState: getRoutesWithIndex([defaultFullScreenRoute, adaptedOnboardingNavigator]), + }; + } + // If not, add the default full screen route. return { adaptedState: getRoutesWithIndex([defaultFullScreenRoute, ...state.routes]), From 6f65c7c84d08735f1631e79cb06f483bbdd9f908 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 5 Nov 2024 14:22:23 +0100 Subject: [PATCH 160/257] Fix issue: Group chat - Default group chat name when created offline is Chat Report --- src/libs/Navigation/Navigation.ts | 4 ++-- src/libs/actions/Report.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 6b6c2d780cb0..3e89ac55aafe 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -459,11 +459,11 @@ const dismissModal = (reportID?: string, ref = navigationRef) => { if (!reportID) { return; } - navigateToReportWithPolicyCheck({reportID}); + isNavigationReady().then(() => navigateToReportWithPolicyCheck({reportID})); }; const dismissModalWithReport = (report: OnyxEntry) => { dismissModal(); - navigateToReportWithPolicyCheck({report}); + isNavigationReady().then(() => navigateToReportWithPolicyCheck({report})); }; export default { diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 049ebbc0ef63..e4429bb4335a 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1039,7 +1039,8 @@ function navigateToAndOpenReport( // We want to pass newChat here because if anything is passed in that param (even an existing chat), we will try to create a chat on the server openReport(report?.reportID ?? '', '', userLogins, newChat, undefined, undefined, undefined, avatarFile); if (shouldDismissModal) { - Navigation.dismissModal(); + Navigation.dismissModalWithReport(report); + return; } Navigation.navigateToReportWithPolicyCheck({report}); } From b213f93f26a6e736b4386de223dca9c72289a392 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 5 Nov 2024 14:39:38 +0100 Subject: [PATCH 161/257] Add test steps for the issue: Opening particular onboarding pages from a link and going back --- contributingGuides/NAVIGATION.md | 21 ++++++++++++++++++- .../linkingConfig/getAdaptedStateFromPath.ts | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index 9828601c8559..2f45b4c450a0 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -459,4 +459,23 @@ Linked issue: https://github.com/Expensify/App/pull/49539#issuecomment-243332160 4. Click Private notes. 5. Enter anything and click Save. 6. Click on the RHP back button. -7. Verify if the Profile RHP Page is opened (URL in the format /a/:accountID). \ No newline at end of file +7. Verify if the Profile RHP Page is opened (URL in the format /a/:accountID). + +#### Opening particular onboarding pages from a link and going back + +Linked issue: https://github.com/Expensify/App/issues/50177 + +1. Sign in as a new user. +2. Select Something else from the onboarding flow. +3. Reopen/refresh the app. +4. Verify the Personal detail step is shown. +5. Go back. +6. Verify you are navigated back to the Purpose step. +7. Select Manage my team. +8. Choose the employee size. +9. Reopen/refresh the app. +10. Verify the connection integration step is shown. +11. Go back. +12. Verify you are navigated back to the employee size step. +13. Go back. +14. Verify you are navigated back to the Purpose step. \ No newline at end of file diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index c86635fb18bd..d7728f35ba5f 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -194,6 +194,7 @@ function getAdaptedState(state: PartialState const defaultFullScreenRoute = getDefaultFullScreenRoute(focusedRoute, policyID); + // The onboarding flow consists of several screens. If we open any of the screens, the previous screens from that flow should be in the state. if (onboardingNavigator?.state) { const adaptedOnboardingNavigator = { ...onboardingNavigator, From 44bde7672ee8a59f70f4b9949f48a9baf0405911 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 6 Nov 2024 14:27:13 +0100 Subject: [PATCH 162/257] Fix issue: Expense - Report details RHP opens after deleting receipt --- src/components/AttachmentModal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index 0bc233812ca7..e99074cd0748 100644 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -287,8 +287,8 @@ function AttachmentModal({ const deleteAndCloseModal = useCallback(() => { IOU.detachReceipt(transaction?.transactionID ?? '-1'); setIsDeleteReceiptConfirmModalVisible(false); - Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report?.reportID ?? '-1')); - }, [transaction, report]); + Navigation.goBack(); + }, [transaction]); const isValidFile = useCallback( (fileObject: FileObject) => From 6fc9f27cebf2abdef0595b1954be4011fb0bd100 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 8 Nov 2024 17:04:03 +0100 Subject: [PATCH 163/257] adjust navigation patch for new screens and navigators --- .../@react-navigation+stack+6.3.29+002+dontDetachScreen.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/patches/@react-navigation+stack+6.3.29+002+dontDetachScreen.patch b/patches/@react-navigation+stack+6.3.29+002+dontDetachScreen.patch index 529e9aab0221..8cd2a1c2f7f6 100644 --- a/patches/@react-navigation+stack+6.3.29+002+dontDetachScreen.patch +++ b/patches/@react-navigation+stack+6.3.29+002+dontDetachScreen.patch @@ -43,7 +43,7 @@ index 7558eb3..b7bb75e 100644 }) : STATE_TRANSITIONING_OR_BELOW_TOP; } + -+ const isHomeScreenAndNotOnTop = (route.name === 'BottomTabNavigator' || route.name === 'Workspace_Initial' || route.name === 'Home' || route.name === 'Search_Bottom_Tab' || route.name === 'Settings_Root') && isScreenActive !== STATE_ON_TOP; ++ const isHomeScreenAndNotOnTop = (route.name === 'BottomTabNavigator' || route.name === 'Workspace_Initial' || route.name === 'Home' || route.name === 'Search_Bottom_Tab' || route.name === 'Settings_Root' || route.name === 'ReportsSplitNavigator' || route.name === 'Search_Central_Pane') && isScreenActive !== STATE_ON_TOP; + const { headerShown = true, From c52cbaa7c7756d9c88dfff47a6f20eb327a61e56 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 8 Nov 2024 17:04:14 +0100 Subject: [PATCH 164/257] implement new freeze wrapper --- .../FreezeWrapper/getIsScreenBlurred.ts | 9 +++++ .../FreezeWrapper/index.native.tsx | 28 +++++++++++++++ .../AppNavigator/FreezeWrapper/index.tsx | 35 +++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred.ts create mode 100644 src/libs/Navigation/AppNavigator/FreezeWrapper/index.native.tsx create mode 100644 src/libs/Navigation/AppNavigator/FreezeWrapper/index.tsx diff --git a/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred.ts b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred.ts new file mode 100644 index 000000000000..beae98460c1a --- /dev/null +++ b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred.ts @@ -0,0 +1,9 @@ +import type {NavigationState} from '@react-navigation/native'; +import {isFullScreenName} from '@libs/NavigationUtils'; + +function getIsScreenBlurred(state: NavigationState, currentRouteKey: string) { + const lastFullScreenRoute = state.routes.findLast((route) => isFullScreenName(route.name)); + return lastFullScreenRoute?.key !== currentRouteKey; +} + +export default getIsScreenBlurred; diff --git a/src/libs/Navigation/AppNavigator/FreezeWrapper/index.native.tsx b/src/libs/Navigation/AppNavigator/FreezeWrapper/index.native.tsx new file mode 100644 index 000000000000..bb8b070f4545 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/FreezeWrapper/index.native.tsx @@ -0,0 +1,28 @@ +import {useNavigation, useRoute} from '@react-navigation/native'; +import React, {useEffect, useState} from 'react'; +import {Freeze} from 'react-freeze'; +import type ChildrenProps from '@src/types/utils/ChildrenProps'; +import getIsScreenBlurred from './getIsScreenBlurred'; + +type FreezeWrapperProps = ChildrenProps & { + /** Prop to disable freeze */ + keepVisible?: boolean; +}; + +function FreezeWrapper({keepVisible = false, children}: FreezeWrapperProps) { + const navigation = useNavigation(); + const currentRoute = useRoute(); + + const [isScreenBlurred, setIsScreenBlurred] = useState(false); + + useEffect(() => { + const unsubscribe = navigation.addListener('state', (e) => setIsScreenBlurred(getIsScreenBlurred(e.data.state, currentRoute.key))); + return () => unsubscribe(); + }, [currentRoute.key, navigation]); + + return {children}; +} + +FreezeWrapper.displayName = 'FreezeWrapper'; + +export default FreezeWrapper; diff --git a/src/libs/Navigation/AppNavigator/FreezeWrapper/index.tsx b/src/libs/Navigation/AppNavigator/FreezeWrapper/index.tsx new file mode 100644 index 000000000000..98133c3f7796 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/FreezeWrapper/index.tsx @@ -0,0 +1,35 @@ +import {useNavigation, useRoute} from '@react-navigation/native'; +import React, {useEffect, useLayoutEffect, useState} from 'react'; +import {Freeze} from 'react-freeze'; +import type ChildrenProps from '@src/types/utils/ChildrenProps'; +import getIsScreenBlurred from './getIsScreenBlurred'; + +type FreezeWrapperProps = ChildrenProps & { + /** Prop to disable freeze */ + keepVisible?: boolean; +}; + +function FreezeWrapper({keepVisible = false, children}: FreezeWrapperProps) { + const navigation = useNavigation(); + const currentRoute = useRoute(); + + const [isScreenBlurred, setIsScreenBlurred] = useState(false); + const [freezed, setFreezed] = useState(false); + + useEffect(() => { + const unsubscribe = navigation.addListener('state', (e) => setIsScreenBlurred(getIsScreenBlurred(e.data.state, currentRoute.key))); + return () => unsubscribe(); + }, [currentRoute.key, navigation]); + + // Decouple the Suspense render task so it won't be interrupted by React's concurrent mode + // and stuck in an infinite loop + useLayoutEffect(() => { + setFreezed(isScreenBlurred && !keepVisible); + }, [isScreenBlurred, keepVisible]); + + return {children}; +} + +FreezeWrapper.displayName = 'FreezeWrapper'; + +export default FreezeWrapper; From dab0ad43204a02538a451ceb027a58495c75c07b Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 8 Nov 2024 17:04:30 +0100 Subject: [PATCH 165/257] use new freeze wrapper --- .../Navigators/ReportsSplitNavigator.tsx | 45 ++------- src/pages/Search/SearchPage.tsx | 93 ++++++++++--------- 2 files changed, 56 insertions(+), 82 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index daaabf1094b4..c83816a21b5d 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -1,42 +1,19 @@ -import {useNavigationState, useRoute} from '@react-navigation/native'; import React, {useRef} from 'react'; -import {Freeze} from 'react-freeze'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import usePermissions from '@hooks/usePermissions'; -import memoize from '@libs/memoize'; import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; +import FreezeWrapper from '@libs/Navigation/AppNavigator/FreezeWrapper'; import getCurrentUrl from '@libs/Navigation/currentUrl'; import shouldOpenOnAdminRoom from '@libs/Navigation/shouldOpenOnAdminRoom'; import type {ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; -import {isFullScreenName} from '@libs/NavigationUtils'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; -function FrozenScreen(WrappedComponent: React.ComponentType, freeze: boolean) { - return (props: TProps) => ( - - - - ); -} - -function freezeScreenWithLazyLoading(lazyComponent: () => React.ComponentType, freeze: boolean) { - return memoize( - () => { - const Component = lazyComponent(); - return FrozenScreen(Component, freeze); - }, - {monitoringName: 'freezeScreenWithLazyLoading'}, - ); -} - const loadReportScreen = () => require('../../../../pages/home/ReportScreen').default; +const loadSidebarScreen = () => require('@pages/home/sidebar/SidebarScreen').default; const Stack = createSplitStackNavigator(); @@ -47,8 +24,8 @@ function ReportsSplitNavigator() { let initialReportID: string | undefined; const isInitialRender = useRef(true); - const currentRoute = useRoute(); - + // TODO: Figure out if compiler affects this code. + // eslint-disable-next-line react-compiler/react-compiler if (isInitialRender.current) { const currentURL = getCurrentUrl(); if (currentURL) { @@ -60,18 +37,12 @@ function ReportsSplitNavigator() { initialReportID = initialReport?.reportID ?? ''; } + // eslint-disable-next-line react-compiler/react-compiler isInitialRender.current = false; } - const shouldFreeze = useNavigationState((state) => { - const lastFullScreenRoute = state.routes.findLast((route) => isFullScreenName(route.name)); - return lastFullScreenRoute?.key !== currentRoute.key; - }); - - const getSidebarScreen = freezeScreenWithLazyLoading(() => require('@pages/home/sidebar/SidebarScreen').default, shouldFreeze); - return ( - + - + ); } diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 11c7a45f33b3..df425c23562f 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -15,6 +15,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import TopBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar'; +import FreezeWrapper from '@libs/Navigation/AppNavigator/FreezeWrapper'; import Navigation from '@libs/Navigation/Navigation'; import type {AuthScreensParamList} from '@libs/Navigation/types'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; @@ -58,54 +59,56 @@ function SearchPage({route}: SearchPageProps) { } return ( - - {!!queryJSON && ( - - - {/* {!selectionMode?.isEnabled && queryJSON ? ( */} - {queryJSON ? ( - - + + {!!queryJSON && ( + + + {/* {!selectionMode?.isEnabled && queryJSON ? ( */} + {queryJSON ? ( + + + + + ) : ( + { + clearSelectedTransactions(); + turnOffMobileSelectionMode(); + }} /> - - - ) : ( - { - clearSelectedTransactions(); - turnOffMobileSelectionMode(); - }} + )} + + + + - )} - + + + - - - - - - - )} - + )} + + ); } From f6084ec1a0b63641e826b362aa3df31399692812 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 12 Nov 2024 16:59:05 +0100 Subject: [PATCH 166/257] Adjust getIsScreenBlurred to native platforms --- .../FreezeWrapper/getIsScreenBlurred/index.native.ts | 11 +++++++++++ .../index.ts} | 0 2 files changed, 11 insertions(+) create mode 100644 src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.native.ts rename src/libs/Navigation/AppNavigator/FreezeWrapper/{getIsScreenBlurred.ts => getIsScreenBlurred/index.ts} (100%) diff --git a/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.native.ts b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.native.ts new file mode 100644 index 000000000000..9b1cbd94dced --- /dev/null +++ b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.native.ts @@ -0,0 +1,11 @@ +import type {NavigationState} from '@react-navigation/native'; +import {isFullScreenName} from '@libs/NavigationUtils'; + +function getIsScreenBlurred(state: NavigationState, currentRouteKey: string) { + // If the screen is one of the last two fullscreen routes in the stack, it is not freezed on native platforms. + // One screen below the main one should not be freezed to allow users to return by swiping left. + const lastTwoFullScreenRoutes = state.routes.filter((route) => isFullScreenName(route.name)).slice(-2); + return !lastTwoFullScreenRoutes.some((route) => route.key === currentRouteKey); +} + +export default getIsScreenBlurred; diff --git a/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred.ts b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred.ts rename to src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.ts From 43f48d38ff6d3274f921326fa95f997248bb3883 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 14 Nov 2024 11:25:00 +0100 Subject: [PATCH 167/257] Make ReportsSplitNavigator public --- .../Navigation/AppNavigator/PublicScreens.tsx | 4 ++-- src/libs/Navigation/NavigationRoot.tsx | 19 +++++++++++++++++++ src/libs/Navigation/types.ts | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.tsx b/src/libs/Navigation/AppNavigator/PublicScreens.tsx index cfd41a4b1fa0..92b169c95b40 100644 --- a/src/libs/Navigation/AppNavigator/PublicScreens.tsx +++ b/src/libs/Navigation/AppNavigator/PublicScreens.tsx @@ -20,9 +20,9 @@ const RootStack = createStackNavigator(); function PublicScreens() { return ( - {/* The structure for the HOME route has to be the same in public and auth screens. That's why the name for SignInPage is BOTTOM_TAB_NAVIGATOR. */} + {/* The structure for the HOME route has to be the same in public and auth screens. That's why the name for SignInPage is REPORTS_SPLIT_NAVIGATOR. */} diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 34f24cffdd09..1718eb8097ff 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -5,6 +5,7 @@ import {NativeModules} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import {ScrollOffsetContext} from '@components/ScrollOffsetContextProvider'; import useCurrentReportID from '@hooks/useCurrentReportID'; +import usePrevious from '@hooks/usePrevious'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import Firebase from '@libs/Firebase'; @@ -92,6 +93,8 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh selector: hasCompletedGuidedSetupFlowSelector, }); + const previousAuthenticated = usePrevious(authenticated); + const initialState = useMemo(() => { if (!user || user.isFromPublicDomain) { return; @@ -152,6 +155,22 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh Navigation.setShouldPopAllStateOnUP(!shouldUseNarrowLayout); }, [shouldUseNarrowLayout]); + useEffect(() => { + // Since NAVIGATORS.REPORTS_SPLIT_NAVIGATOR is public, + // we should leave only one ReportsSplitNavigator in the navigation stack after logout. + const hasUserLoggedOut = !authenticated && !!previousAuthenticated; + if (!hasUserLoggedOut) { + return; + } + + const rootState = navigationRef.getRootState(); + const lastRoute = rootState.routes.at(-1); + if (!lastRoute) { + return; + } + navigationRef.reset({...rootState, index: 0, routes: [{...lastRoute, params: {}}]}); + }, [authenticated, previousAuthenticated]); + const handleStateChange = (state: NavigationState | undefined) => { if (!state) { return; diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index c23d649f1a15..956910a497e5 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1544,7 +1544,7 @@ type BottomTabNavigatorParamList = { }; type SharedScreensParamList = { - [NAVIGATORS.BOTTOM_TAB_NAVIGATOR]: NavigatorScreenParams; + [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: NavigatorScreenParams; [SCREENS.TRANSITION_BETWEEN_APPS]: { email?: string; accountID?: number; From b5eb92b1d760f6118ad1effecc8a4c9e9e417b17 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 14 Nov 2024 11:53:14 +0100 Subject: [PATCH 168/257] Refactor the comment about state reset after logout --- src/libs/Navigation/NavigationRoot.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 1718eb8097ff..01bca3a47d67 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -156,8 +156,8 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh }, [shouldUseNarrowLayout]); useEffect(() => { - // Since NAVIGATORS.REPORTS_SPLIT_NAVIGATOR is public, - // we should leave only one ReportsSplitNavigator in the navigation stack after logout. + // Since the NAVIGATORS.REPORTS_SPLIT_NAVIGATOR url is "/" and it has to be used as an URL for SignInPage, + // this navigator should be the only one in the navigation state after logout. const hasUserLoggedOut = !authenticated && !!previousAuthenticated; if (!hasUserLoggedOut) { return; From 34d64035a939d776350b57ff03fd746b1ca2b418 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 14 Nov 2024 15:12:23 +0100 Subject: [PATCH 169/257] Cleanup ActiveWorkspaceProvider --- .../ActiveWorkspaceProvider/index.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index a0decb667504..b9e5f34d5389 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -22,17 +22,19 @@ function ActiveWorkspaceContextProvider({children}: ChildrenProps) { return; } - if (queryFromRouteParam) { - const queryJSON = SearchQueryUtils.buildSearchQueryJSON(queryFromRouteParam); - if (!queryJSON) { - setActiveWorkspaceID(undefined); - return; - } - setActiveWorkspaceID(SearchQueryUtils.getPolicyIDFromSearchQuery(queryJSON)); + if (!queryFromRouteParam) { + setActiveWorkspaceID(undefined); return; } - setActiveWorkspaceID(undefined); + const queryJSON = SearchQueryUtils.buildSearchQueryJSON(queryFromRouteParam); + + if (!queryJSON) { + setActiveWorkspaceID(undefined); + return; + } + + setActiveWorkspaceID(SearchQueryUtils.getPolicyIDFromSearchQuery(queryJSON)); }, [policyIDFromRouteParam, queryFromRouteParam, setActiveWorkspaceID]); const value = useMemo( From 0cd11da6abb58d10d76c5dfed251e722c7c0bdcf Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 15 Nov 2024 11:15:14 +0100 Subject: [PATCH 170/257] Fix animationTypeForReplace for RHP screens --- .../AppNavigator/ModalStackNavigators/useModalScreenOptions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalScreenOptions.ts b/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalScreenOptions.ts index 2193dcb2bf6b..64457fa5a42e 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalScreenOptions.ts +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalScreenOptions.ts @@ -25,6 +25,7 @@ function useModalScreenOptions(getScreenOptions?: (styles: ThemeStyles) => Stack cardStyle: styles.navigationScreenCardStyle, headerShown: false, cardStyleInterpolator, + animationTypeForReplace: 'pop', }), [styles, cardStyleInterpolator], ); From 5d978e3e6d8d2a9bf2e50d55c27d6acc23e2ac89 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 15 Nov 2024 15:03:14 +0100 Subject: [PATCH 171/257] Add GetStateForActionHandlers --- src/CONST.ts | 3 + .../CustomRouter.ts | 166 ++++-------------- .../GetStateForActionHandlers.ts | 155 ++++++++++++++++ .../createCustomStackNavigator/types.ts | 35 +++- src/libs/Navigation/Navigation.ts | 4 +- 5 files changed, 228 insertions(+), 135 deletions(-) create mode 100644 src/libs/Navigation/AppNavigator/createCustomStackNavigator/GetStateForActionHandlers.ts diff --git a/src/CONST.ts b/src/CONST.ts index f41eab6318e4..3df06347cd97 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -4538,7 +4538,10 @@ const CONST = { REPLACE: 'REPLACE', PUSH: 'PUSH', NAVIGATE: 'NAVIGATE', + + /** These action types are custom for RootNavigator */ SWITCH_POLICY_ID: 'SWITCH_POLICY_ID', + DISMISS_MODAL: 'DISMISS_MODAL', }, }, TIME_PERIOD: { diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 4b1882747e20..bec622f1a953 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -1,35 +1,36 @@ import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; -import {findFocusedRoute, StackActions, StackRouter} from '@react-navigation/native'; +import {findFocusedRoute, StackRouter} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/routers'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import * as Localize from '@libs/Localize'; -import Log from '@libs/Log'; -import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; import isSideModalNavigator from '@libs/Navigation/isSideModalNavigator'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; import {isOnboardingFlowName} from '@libs/NavigationUtils'; -import * as SearchQueryUtils from '@libs/SearchQueryUtils'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; +import * as GetStateForActionHandlers from './GetStateForActionHandlers'; import syncBrowserHistory from './syncBrowserHistory'; -import type {ResponsiveStackNavigatorRouterOptions} from './types'; - -const MODAL_ROUTES_TO_DISMISS: string[] = [ - NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, - NAVIGATORS.LEFT_MODAL_NAVIGATOR, - NAVIGATORS.RIGHT_MODAL_NAVIGATOR, - NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR, - NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR, - SCREENS.NOT_FOUND, - SCREENS.ATTACHMENTS, - SCREENS.TRANSACTION_RECEIPT, - SCREENS.PROFILE_AVATAR, - SCREENS.WORKSPACE_AVATAR, - SCREENS.REPORT_AVATAR, - SCREENS.CONCIERGE, -]; +import type { + CustomRouterActionType, + CustomRouterAction, + DismissModalActionType, + PushActionType, + SwitchPolicyIdActionType, + ResponsiveStackNavigatorRouterOptions, +} from './types'; + +function isSwitchPolicyIdAction(action: CustomRouterAction): action is SwitchPolicyIdActionType { + return action.type === CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID; +} + +function isPushAction(action: CustomRouterAction): action is PushActionType { + return action.type === CONST.NAVIGATION.ACTION_TYPE.PUSH; +} + +function isDismissModalAction(action: CustomRouterAction): action is DismissModalActionType { + return action.type === CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL; +} function shouldPreventReset(state: StackNavigationState, action: CommonActions.Action | StackActionType) { if (action.type !== CONST.NAVIGATION_ACTIONS.RESET || !action?.payload) { @@ -59,19 +60,9 @@ function shouldDismissSideModalNavigator(state: StackNavigationState, action: CommonActions.Action | StackActionType | CustomRootStackActionType, configOptions: RouterConfigOptions) { - if (action.type === CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID) { - const lastRoute = state.routes.at(-1); - if (lastRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { - const currentParams = lastRoute.params as RootStackParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; - const queryJSON = SearchQueryUtils.buildSearchQueryJSON(currentParams.q); - if (!queryJSON) { - return null; - } - - if (action.payload.policyID) { - queryJSON.policyID = action.payload.policyID; - } else { - delete queryJSON.policyID; - } - - const newAction = StackActions.push(SCREENS.SEARCH.CENTRAL_PANE, { - ...currentParams, - q: SearchQueryUtils.buildSearchQueryString(queryJSON), - }); - - setActiveWorkspaceID(action.payload.policyID); - return stackRouter.getStateForAction(state, newAction, configOptions); - } - if (lastRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { - const newAction = StackActions.push(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, {policyID: action.payload.policyID}); - - setActiveWorkspaceID(action.payload.policyID); - return stackRouter.getStateForAction(state, newAction, configOptions); - } - - // We don't have other navigators that should handle switch policy action. - return null; + getStateForAction(state: StackNavigationState, action: CustomRouterAction, configOptions: RouterConfigOptions) { + if (isSwitchPolicyIdAction(action)) { + return GetStateForActionHandlers.handleSwitchPolicyID(state, action, configOptions, stackRouter, setActiveWorkspaceID); } - if (action.type === 'DISMISS_MODAL') { - const lastRoute = state.routes.at(-1); - const newAction = StackActions.pop(); + if (isDismissModalAction(action)) { + return GetStateForActionHandlers.handleDismissModalAction(state, action, configOptions, stackRouter); + } - if (!lastRoute?.name || !MODAL_ROUTES_TO_DISMISS.includes(lastRoute?.name)) { - Log.hmmm('[Navigation] dismissModal failed because there is no modal stack to dismiss'); - return null; + if (isPushAction(action)) { + if (action.payload.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { + return GetStateForActionHandlers.handlePushReportAction(state, action, configOptions, stackRouter, setActiveWorkspaceID); } - return stackRouter.getStateForAction(state, newAction, configOptions); + if (action.payload.name === SCREENS.SEARCH.CENTRAL_PANE) { + return GetStateForActionHandlers.handlePushSearchPageAction(state, action, configOptions, stackRouter, setActiveWorkspaceID); + } } // Don't let the user navigate back to a non-onboarding screen if they are currently on an onboarding screen and it's not finished. @@ -132,65 +95,6 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { return state; } - if (action.type === 'PUSH' && action.payload.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { - const haveParamsPolicyID = action.payload.params && 'policyID' in action.payload.params; - let policyID; - - if (haveParamsPolicyID) { - policyID = (action.payload.params as Record)?.policyID; - setActiveWorkspaceID(policyID); - } else { - policyID = getPolicyIDFromState(state as State); - } - - const modifiedAction = { - ...action, - payload: { - ...action.payload, - params: { - ...action.payload.params, - policyID, - }, - }, - }; - - return stackRouter.getStateForAction(state, modifiedAction, configOptions); - } - - if (action.type === 'PUSH' && action.payload.name === SCREENS.SEARCH.CENTRAL_PANE) { - const currentParams = action.payload.params as RootStackParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; - const queryJSON = SearchQueryUtils.buildSearchQueryJSON(currentParams.q); - - if (!queryJSON) { - return null; - } - - if (!queryJSON.policyID) { - const policyID = getPolicyIDFromState(state as State); - - if (policyID) { - queryJSON.policyID = policyID; - } else { - delete queryJSON.policyID; - } - } else { - setActiveWorkspaceID(queryJSON.policyID); - } - - const modifiedAction = { - ...action, - payload: { - ...action.payload, - params: { - ...action.payload.params, - q: SearchQueryUtils.buildSearchQueryString(queryJSON), - }, - }, - }; - - return stackRouter.getStateForAction(state, modifiedAction, configOptions); - } - if (shouldDismissSideModalNavigator(state, action)) { const modifiedState = {...state, routes: state.routes.slice(0, -1), index: state.index !== 0 ? state.index - 1 : 0}; return stackRouter.getStateForAction(modifiedState, action, configOptions); @@ -202,4 +106,4 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { } export default CustomRouter; -export type {CustomRootStackActionType}; +export type {CustomRouterActionType}; diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/GetStateForActionHandlers.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/GetStateForActionHandlers.ts new file mode 100644 index 000000000000..54542819b569 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/GetStateForActionHandlers.ts @@ -0,0 +1,155 @@ +import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; +import {StackActions} from '@react-navigation/native'; +import type {ParamListBase, Router} from '@react-navigation/routers'; +import Log from '@libs/Log'; +import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; +import type {RootStackParamList, State} from '@libs/Navigation/types'; +import * as SearchQueryUtils from '@libs/SearchQueryUtils'; +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; +import type {DismissModalActionType, PushActionType, SwitchPolicyIdActionType} from './types'; + +const MODAL_ROUTES_TO_DISMISS: string[] = [ + NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, + NAVIGATORS.LEFT_MODAL_NAVIGATOR, + NAVIGATORS.RIGHT_MODAL_NAVIGATOR, + NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR, + NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR, + SCREENS.NOT_FOUND, + SCREENS.ATTACHMENTS, + SCREENS.TRANSACTION_RECEIPT, + SCREENS.PROFILE_AVATAR, + SCREENS.WORKSPACE_AVATAR, + SCREENS.REPORT_AVATAR, + SCREENS.CONCIERGE, +]; + +function handleSwitchPolicyID( + state: StackNavigationState, + action: SwitchPolicyIdActionType, + configOptions: RouterConfigOptions, + stackRouter: Router, CommonActions.Action | StackActionType>, + setActiveWorkspaceID: (workspaceID: string | undefined) => void, +) { + const lastRoute = state.routes.at(-1); + if (lastRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { + const currentParams = lastRoute.params as RootStackParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; + const queryJSON = SearchQueryUtils.buildSearchQueryJSON(currentParams.q); + if (!queryJSON) { + return null; + } + + if (action.payload.policyID) { + queryJSON.policyID = action.payload.policyID; + } else { + delete queryJSON.policyID; + } + + const newAction = StackActions.push(SCREENS.SEARCH.CENTRAL_PANE, { + ...currentParams, + q: SearchQueryUtils.buildSearchQueryString(queryJSON), + }); + + setActiveWorkspaceID(action.payload.policyID); + return stackRouter.getStateForAction(state, newAction, configOptions); + } + if (lastRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { + const newAction = StackActions.push(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, {policyID: action.payload.policyID}); + + setActiveWorkspaceID(action.payload.policyID); + return stackRouter.getStateForAction(state, newAction, configOptions); + } + + // We don't have other navigators that should handle switch policy action. + return null; +} + +function handlePushReportAction( + state: StackNavigationState, + action: PushActionType, + configOptions: RouterConfigOptions, + stackRouter: Router, CommonActions.Action | StackActionType>, + setActiveWorkspaceID: (workspaceID: string | undefined) => void, +) { + const haveParamsPolicyID = action.payload.params && 'policyID' in action.payload.params; + let policyID; + + if (haveParamsPolicyID) { + policyID = (action.payload.params as Record)?.policyID; + setActiveWorkspaceID(policyID); + } else { + policyID = getPolicyIDFromState(state as State); + } + + const modifiedAction = { + ...action, + payload: { + ...action.payload, + params: { + ...action.payload.params, + policyID, + }, + }, + }; + + return stackRouter.getStateForAction(state, modifiedAction, configOptions); +} + +function handlePushSearchPageAction( + state: StackNavigationState, + action: PushActionType, + configOptions: RouterConfigOptions, + stackRouter: Router, CommonActions.Action | StackActionType>, + setActiveWorkspaceID: (workspaceID: string | undefined) => void, +) { + const currentParams = action.payload.params as RootStackParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; + const queryJSON = SearchQueryUtils.buildSearchQueryJSON(currentParams.q); + + if (!queryJSON) { + return null; + } + + if (!queryJSON.policyID) { + const policyID = getPolicyIDFromState(state as State); + + if (policyID) { + queryJSON.policyID = policyID; + } else { + delete queryJSON.policyID; + } + } else { + setActiveWorkspaceID(queryJSON.policyID); + } + + const modifiedAction = { + ...action, + payload: { + ...action.payload, + params: { + ...action.payload.params, + q: SearchQueryUtils.buildSearchQueryString(queryJSON), + }, + }, + }; + + return stackRouter.getStateForAction(state, modifiedAction, configOptions); +} + +function handleDismissModalAction( + state: StackNavigationState, + action: DismissModalActionType, + configOptions: RouterConfigOptions, + stackRouter: Router, CommonActions.Action | StackActionType>, +) { + const lastRoute = state.routes.at(-1); + const newAction = StackActions.pop(); + action; + if (!lastRoute?.name || !MODAL_ROUTES_TO_DISMISS.includes(lastRoute?.name)) { + Log.hmmm('[Navigation] dismissModal failed because there is no modal stack to dismiss'); + return null; + } + + return stackRouter.getStateForAction(state, newAction, configOptions); +} + +export {handleDismissModalAction, handlePushReportAction, handlePushSearchPageAction, handleSwitchPolicyID}; diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts index 09d35e2a1680..9f19ede081cd 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts @@ -1,5 +1,25 @@ -import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; +import type {CommonActions, DefaultNavigatorOptions, ParamListBase, StackActionType, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; +import type CONST from '@src/CONST'; + +type CustomRouterActionType = + | { + type: typeof CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID; + payload: { + policyID: string; + }; + } + | {type: typeof CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL}; + +type SwitchPolicyIdActionType = CustomRouterActionType & { + type: typeof CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID; +}; + +type PushActionType = StackActionType & {type: typeof CONST.NAVIGATION.ACTION_TYPE.PUSH}; + +type DismissModalActionType = CustomRouterActionType & { + type: typeof CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL; +}; type ResponsiveStackNavigatorConfig = { isSmallScreenWidth: boolean; @@ -10,4 +30,15 @@ type ResponsiveStackNavigatorRouterOptions = StackRouterOptions; type ResponsiveStackNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> & ResponsiveStackNavigatorConfig; -export type {ResponsiveStackNavigatorRouterOptions, ResponsiveStackNavigatorProps, ResponsiveStackNavigatorConfig}; +type CustomRouterAction = CommonActions.Action | StackActionType | CustomRouterActionType; + +export type { + SwitchPolicyIdActionType, + PushActionType, + DismissModalActionType, + CustomRouterAction, + CustomRouterActionType, + ResponsiveStackNavigatorRouterOptions, + ResponsiveStackNavigatorProps, + ResponsiveStackNavigatorConfig, +}; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 99ccf6d91bd1..f816085f5325 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -239,7 +239,7 @@ function goUp(fallbackRoute: Route, options?: GoUpOptions) { // If we need to pop more than one route from rootState, we replace the current route to not lose visited routes from the navigation state if (indexOfFallbackRoute === -1 || (isRootNavigatorState(targetState) && distanceToPop > 1)) { - const replaceAction = {...minimalAction, type: 'REPLACE'} as NavigationAction; + const replaceAction = {...minimalAction, type: CONST.NAVIGATION.ACTION_TYPE.REPLACE} as NavigationAction; navigationRef.current.dispatch(replaceAction); return; } @@ -456,7 +456,7 @@ function navigateToReportWithPolicyCheck({report, reportID, reportActionID, refe // @TODO In places where we use dismissModal with report arg we should do dismiss modal and then navigate to the report. // We left it here to limit the number of changed files. const dismissModal = (reportID?: string, ref = navigationRef) => { - ref.dispatch({type: 'DISMISS_MODAL'}); + ref.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL}); if (!reportID) { return; } From 99166deda2859b6815e45fe7e77f5a16c00ee710 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 18 Nov 2024 08:29:59 +0100 Subject: [PATCH 172/257] Fix ParamList in WorkspacePerDiemPage --- src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx b/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx index 9430cfd911b5..d0106a8a17b7 100644 --- a/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx +++ b/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx @@ -32,7 +32,7 @@ import * as CurrencyUtils from '@libs/CurrencyUtils'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import localeCompare from '@libs/LocaleCompare'; import Navigation from '@libs/Navigation/Navigation'; -import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import {getPerDiemCustomUnit} from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import * as Link from '@userActions/Link'; @@ -104,7 +104,7 @@ function generateSingleSubRateData(customUnitRates: Rate[], rateID: string, subR }; } -type WorkspacePerDiemPageProps = StackScreenProps; +type WorkspacePerDiemPageProps = StackScreenProps; function WorkspacePerDiemPage({route}: WorkspacePerDiemPageProps) { const {shouldUseNarrowLayout} = useResponsiveLayout(); From 061f2cae805912d80859bf26bf04a1754b88ed35 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 18 Nov 2024 11:36:11 +0100 Subject: [PATCH 173/257] Fix types in RELATIONS and getAdaptedStateFromPath --- .../Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts | 3 ++- .../Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts | 5 +++-- .../Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts | 3 ++- src/libs/Navigation/linkingConfig/RELATIONS/index.ts | 3 +-- .../Navigation/linkingConfig/getAdaptedStateFromPath.ts | 7 +++---- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts index b4afc15366d3..6e7c15ce3a16 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts @@ -1,7 +1,8 @@ +import type {SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; // This file is used to define relation between settings split navigator's central screens and RHP screens. -const CENTRAL_PANE_TO_RHP_MAPPING: Record = { +const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = { [SCREENS.SETTINGS.PROFILE.ROOT]: [ SCREENS.SETTINGS.PROFILE.DISPLAY_NAME, SCREENS.SETTINGS.PROFILE.CONTACT_METHODS, diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts index 246c9d29a664..a07ef3b8b9ac 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts @@ -1,8 +1,9 @@ +import type {SplitNavigatorLHNScreen} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; // This file is used to define the relationship between the sidebar (LHN) and the right hand pane (RHP) screen. -// Those screens doesn't care about the split navigator's central screen and are in relation directly to the sidebar. -const SIDEBAR_TO_RHP: Record = { +// These screens don't care about the split navigator's central screen and are in relation directly to the sidebar. +const SIDEBAR_TO_RHP: Partial> = { [SCREENS.SETTINGS.ROOT]: [ SCREENS.SETTINGS.SHARE_CODE, SCREENS.SETTINGS.PROFILE.STATUS, diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts index 39062de76510..fd492cd85800 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts @@ -1,7 +1,8 @@ +import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; // This file is used to define relation between workspace split navigator's central screens and RHP screens. -const WORKSPACE_TO_RHP: Record = { +const WORKSPACE_TO_RHP: Partial> = { [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.ADDRESS, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE], [SCREENS.WORKSPACE.MEMBERS]: [ SCREENS.WORKSPACE.INVITE, diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/index.ts b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts index 4e3e6d7543e2..90865784f68c 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/index.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts @@ -4,8 +4,7 @@ import SIDEBAR_TO_RHP from './SIDEBAR_TO_RHP'; import SIDEBAR_TO_SPLIT from './SIDEBAR_TO_SPLIT'; import WORKSPACE_TO_RHP from './WORKSPACE_TO_RHP'; -// @TODO: fix types -function createInverseRelation(relations: Record): Record { +function createInverseRelation(relations: Partial>): Record { const reversedRelations = {} as Record; Object.entries(relations).forEach(([key, values]) => { diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index d7728f35ba5f..1f9c6e83876d 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -70,10 +70,9 @@ function getMatchingFullScreenRoute(route: NavigationPartialRoute, policyID?: st } if (RELATIONS.RHP_TO_SIDEBAR[route.name]) { - // @TODO: Figure out better types for this. return createSplitNavigator( { - name: RELATIONS.RHP_TO_SIDEBAR[route.name] as typeof SCREENS.HOME, + name: RELATIONS.RHP_TO_SIDEBAR[route.name], }, undefined, policyID ? {policyID} : undefined, @@ -90,7 +89,7 @@ function getMatchingFullScreenRoute(route: NavigationPartialRoute, policyID?: st params: paramsFromRoute.length > 0 ? pick(route.params, paramsFromRoute) : undefined, }, { - name: RELATIONS.RHP_TO_WORKSPACE[route.name] as keyof WorkspaceSplitNavigatorParamList, + name: RELATIONS.RHP_TO_WORKSPACE[route.name], params: paramsFromRoute.length > 0 ? pick(route.params, paramsFromRoute) : undefined, }, ); @@ -104,7 +103,7 @@ function getMatchingFullScreenRoute(route: NavigationPartialRoute, policyID?: st name: SCREENS.SETTINGS.ROOT, }, { - name: RELATIONS.RHP_TO_SETTINGS[route.name] as keyof SettingsSplitNavigatorParamList, + name: RELATIONS.RHP_TO_SETTINGS[route.name], params: paramsFromRoute.length > 0 ? pick(route.params, paramsFromRoute) : undefined, }, ); From 3659ad019a679d58f648c8f16e11164675491729 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 18 Nov 2024 11:51:37 +0100 Subject: [PATCH 174/257] Remove @todo comment from getAdaptedStateFromPath --- src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 1f9c6e83876d..decb1ae483d3 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -79,7 +79,6 @@ function getMatchingFullScreenRoute(route: NavigationPartialRoute, policyID?: st ); } - // @TODO We can think about handling it in one condition. if (RELATIONS.RHP_TO_WORKSPACE[route.name]) { const paramsFromRoute = getParamsFromRoute(RELATIONS.RHP_TO_WORKSPACE[route.name]); From 62b1cda0cfee44f661f7a880e5a9fee3600f66df Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 18 Nov 2024 12:39:35 +0100 Subject: [PATCH 175/257] Remove NAVIGATION.TYPE.UP --- src/CONST.ts | 3 --- src/libs/actions/Report.ts | 4 ++-- src/pages/EnablePayments/EnablePaymentsPage.tsx | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 3df06347cd97..370cf5bd8977 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -4531,9 +4531,6 @@ const CONST = { SF_COORDINATES: [-122.4194, 37.7749], NAVIGATION: { - TYPE: { - UP: 'UP', - }, ACTION_TYPE: { REPLACE: 'REPLACE', PUSH: 'PUSH', diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 1673a84cde51..c139f7e37826 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1391,7 +1391,7 @@ function handleReportChanged(report: OnyxEntry) { const currCallback = callback; callback = () => { currCallback(); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(report.preexistingReportID ?? '-1'), CONST.NAVIGATION.TYPE.UP); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(report.preexistingReportID ?? '-1'), CONST.NAVIGATION.ACTION_TYPE.REPLACE); }; // The report screen will listen to this event and transfer the draft comment to the existing report @@ -2795,7 +2795,7 @@ function navigateToMostRecentReport(currentReport: OnyxEntry) { Navigation.goBack(); } - navigateToConciergeChat(false, () => true, CONST.NAVIGATION.TYPE.UP); + navigateToConciergeChat(false, () => true, CONST.NAVIGATION.ACTION_TYPE.REPLACE); } } diff --git a/src/pages/EnablePayments/EnablePaymentsPage.tsx b/src/pages/EnablePayments/EnablePaymentsPage.tsx index 1384875fe031..4268b4cfd575 100644 --- a/src/pages/EnablePayments/EnablePaymentsPage.tsx +++ b/src/pages/EnablePayments/EnablePaymentsPage.tsx @@ -40,7 +40,7 @@ function EnablePaymentsPage({userWallet}: EnablePaymentsPageProps) { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing if (isPendingOnfidoResult || hasFailedOnfido) { - Navigation.navigate(ROUTES.SETTINGS_WALLET, CONST.NAVIGATION.TYPE.UP); + Navigation.navigate(ROUTES.SETTINGS_WALLET, CONST.NAVIGATION.ACTION_TYPE.REPLACE); return; } From 20efb77279abb8724630baa196c201d9c510870a Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 18 Nov 2024 14:13:21 +0100 Subject: [PATCH 176/257] Remove passing CONST.NAVIGATION.ACTION_TYPE.PUSH as a type param to Navigation.navigate --- src/libs/actions/Report.ts | 2 +- .../settings/Wallet/Card/GetPhysicalCardConfirm.tsx | 9 ++++----- .../workflows/approvals/ApprovalWorkflowEditor.tsx | 9 +++------ 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index c139f7e37826..519f8429ecd6 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2761,7 +2761,7 @@ function openReportFromDeepLink(url: string) { return; } - Navigation.navigate(route as Route, CONST.NAVIGATION.ACTION_TYPE.PUSH); + Navigation.navigate(route as Route); }; // We need skip deeplinking if the user hasn't completed the guided setup flow. diff --git a/src/pages/settings/Wallet/Card/GetPhysicalCardConfirm.tsx b/src/pages/settings/Wallet/Card/GetPhysicalCardConfirm.tsx index 15354c3cdfb8..17c726ca2b10 100644 --- a/src/pages/settings/Wallet/Card/GetPhysicalCardConfirm.tsx +++ b/src/pages/settings/Wallet/Card/GetPhysicalCardConfirm.tsx @@ -1,7 +1,7 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; -import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import Text from '@components/Text'; @@ -10,7 +10,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import type {SettingsNavigatorParamList} from '@navigation/types'; -import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; @@ -18,15 +17,15 @@ import type {GetPhysicalCardForm} from '@src/types/form'; import BaseGetPhysicalCard from './BaseGetPhysicalCard'; const goToGetPhysicalCardName = (domain: string) => { - Navigation.navigate(ROUTES.SETTINGS_WALLET_CARD_GET_PHYSICAL_NAME.getRoute(domain), CONST.NAVIGATION.ACTION_TYPE.PUSH); + Navigation.navigate(ROUTES.SETTINGS_WALLET_CARD_GET_PHYSICAL_NAME.getRoute(domain)); }; const goToGetPhysicalCardPhone = (domain: string) => { - Navigation.navigate(ROUTES.SETTINGS_WALLET_CARD_GET_PHYSICAL_PHONE.getRoute(domain), CONST.NAVIGATION.ACTION_TYPE.PUSH); + Navigation.navigate(ROUTES.SETTINGS_WALLET_CARD_GET_PHYSICAL_PHONE.getRoute(domain)); }; const goToGetPhysicalCardAddress = (domain: string) => { - Navigation.navigate(ROUTES.SETTINGS_WALLET_CARD_GET_PHYSICAL_ADDRESS.getRoute(domain), CONST.NAVIGATION.ACTION_TYPE.PUSH); + Navigation.navigate(ROUTES.SETTINGS_WALLET_CARD_GET_PHYSICAL_ADDRESS.getRoute(domain)); }; type GetPhysicalCardConfirmOnyxProps = { diff --git a/src/pages/workspace/workflows/approvals/ApprovalWorkflowEditor.tsx b/src/pages/workspace/workflows/approvals/ApprovalWorkflowEditor.tsx index 5241b6671e26..1ac3f6789993 100644 --- a/src/pages/workspace/workflows/approvals/ApprovalWorkflowEditor.tsx +++ b/src/pages/workspace/workflows/approvals/ApprovalWorkflowEditor.tsx @@ -97,13 +97,13 @@ function ApprovalWorkflowEditor({approvalWorkflow, removeApprovalWorkflow, polic const editMembers = useCallback(() => { const backTo = approvalWorkflow.action === CONST.APPROVAL_WORKFLOW.ACTION.CREATE ? ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_NEW.getRoute(policyID) : undefined; - Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_EXPENSES_FROM.getRoute(policyID, backTo), CONST.NAVIGATION.ACTION_TYPE.PUSH); + Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_EXPENSES_FROM.getRoute(policyID, backTo)); }, [approvalWorkflow.action, policyID]); const editApprover = useCallback( (approverIndex: number) => { const backTo = approvalWorkflow.action === CONST.APPROVAL_WORKFLOW.ACTION.CREATE ? ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_NEW.getRoute(policyID) : undefined; - Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_APPROVER.getRoute(policyID, approverIndex, backTo), CONST.NAVIGATION.ACTION_TYPE.PUSH); + Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_APPROVER.getRoute(policyID, approverIndex, backTo)); }, [approvalWorkflow.action, policyID], ); @@ -114,10 +114,7 @@ function ApprovalWorkflowEditor({approvalWorkflow, removeApprovalWorkflow, polic Navigation.navigate(ROUTES.WORKSPACE_UPGRADE.getRoute(policyID, CONST.UPGRADE_FEATURE_INTRO_MAPPING.approvals.alias, Navigation.getActiveRoute())); return; } - Navigation.navigate( - ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_APPROVER.getRoute(policyID, approverCount, ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_NEW.getRoute(policyID)), - CONST.NAVIGATION.ACTION_TYPE.PUSH, - ); + Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_APPROVER.getRoute(policyID, approverCount, ROUTES.WORKSPACE_WORKFLOWS_APPROVALS_NEW.getRoute(policyID))); }, [approverCount, policy, policyID]); return ( From 2df2704865d7adf0922ffae796dc26f59f3fe4b6 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 18 Nov 2024 14:35:39 +0100 Subject: [PATCH 177/257] Fix lint in CustomRouter.ts --- .../createCustomStackNavigator/CustomRouter.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index bec622f1a953..31caba3b2e24 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -11,14 +11,7 @@ import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import * as GetStateForActionHandlers from './GetStateForActionHandlers'; import syncBrowserHistory from './syncBrowserHistory'; -import type { - CustomRouterActionType, - CustomRouterAction, - DismissModalActionType, - PushActionType, - SwitchPolicyIdActionType, - ResponsiveStackNavigatorRouterOptions, -} from './types'; +import type {CustomRouterAction, CustomRouterActionType, DismissModalActionType, PushActionType, ResponsiveStackNavigatorRouterOptions, SwitchPolicyIdActionType} from './types'; function isSwitchPolicyIdAction(action: CustomRouterAction): action is SwitchPolicyIdActionType { return action.type === CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID; From 4849fb70128ed515075e611b7219962f27c90999 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 18 Nov 2024 15:30:51 +0100 Subject: [PATCH 178/257] Rename shouldDismissSideModalNavigator to isNavigatingToModalFromModal --- .../AppNavigator/createCustomStackNavigator/CustomRouter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts index 31caba3b2e24..f678425e2ec5 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts @@ -41,7 +41,7 @@ function shouldPreventReset(state: StackNavigationState, action: return false; } -function shouldDismissSideModalNavigator(state: StackNavigationState, action: CommonActions.Action | StackActionType) { +function isNavigatingToModalFromModal(state: StackNavigationState, action: CommonActions.Action | StackActionType) { if (action.type !== CONST.NAVIGATION.ACTION_TYPE.PUSH) { return false; } @@ -88,7 +88,7 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { return state; } - if (shouldDismissSideModalNavigator(state, action)) { + if (isNavigatingToModalFromModal(state, action)) { const modifiedState = {...state, routes: state.routes.slice(0, -1), index: state.index !== 0 ? state.index - 1 : 0}; return stackRouter.getStateForAction(modifiedState, action, configOptions); } From e211447da4e9743a7f4c68664cec80777fea44dc Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 18 Nov 2024 15:40:08 +0100 Subject: [PATCH 179/257] Replace isSearchTopmostRoute with isSearchTopmostFullScreenRoute --- src/components/Search/index.tsx | 4 ++-- .../isSearchTopmostFullScreenRoute.ts | 16 +++++++++++++++ src/libs/Navigation/isSearchTopmostRoute.ts | 15 -------------- src/libs/actions/IOU.ts | 20 +++++++++---------- src/pages/EditReportFieldPage.tsx | 6 +++--- src/pages/home/report/ReportActionsList.tsx | 4 ++-- tests/actions/IOUTest.ts | 2 +- 7 files changed, 34 insertions(+), 33 deletions(-) create mode 100644 src/libs/Navigation/isSearchTopmostFullScreenRoute.ts delete mode 100644 src/libs/Navigation/isSearchTopmostRoute.ts diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 94e23d889991..f3bfa508963f 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -21,7 +21,7 @@ import * as SearchActions from '@libs/actions/Search'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Log from '@libs/Log'; import memoize from '@libs/memoize'; -import isSearchTopmostRoute from '@libs/Navigation/isSearchTopmostRoute'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/isSearchTopmostFullScreenRoute'; import * as ReportUtils from '@libs/ReportUtils'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; import * as SearchUIUtils from '@libs/SearchUIUtils'; @@ -267,7 +267,7 @@ function Search({queryJSON, onSearchListScroll, isSearchScreenFocused, contentCo useEffect( () => () => { - if (isSearchTopmostRoute()) { + if (isSearchTopmostFullScreenRoute()) { return; } clearSelectedTransactions(); diff --git a/src/libs/Navigation/isSearchTopmostFullScreenRoute.ts b/src/libs/Navigation/isSearchTopmostFullScreenRoute.ts new file mode 100644 index 000000000000..eaae1f807489 --- /dev/null +++ b/src/libs/Navigation/isSearchTopmostFullScreenRoute.ts @@ -0,0 +1,16 @@ +import {isFullScreenName} from '@libs/NavigationUtils'; +import SCREENS from '@src/SCREENS'; +import {navigationRef} from './Navigation'; +import type {RootStackParamList, State} from './types'; + +const isSearchTopmostFullScreenRoute = (): boolean => { + const rootState = navigationRef.getRootState() as State; + + if (!rootState) { + return false; + } + + return rootState.routes.filter((route) => isFullScreenName(route.name)).at(-1)?.name === SCREENS.SEARCH.CENTRAL_PANE; +}; + +export default isSearchTopmostFullScreenRoute; diff --git a/src/libs/Navigation/isSearchTopmostRoute.ts b/src/libs/Navigation/isSearchTopmostRoute.ts deleted file mode 100644 index 41969d894635..000000000000 --- a/src/libs/Navigation/isSearchTopmostRoute.ts +++ /dev/null @@ -1,15 +0,0 @@ -import SCREENS from '@src/SCREENS'; -import {navigationRef} from './Navigation'; -import type {RootStackParamList, State} from './types'; - -const isSearchTopmostRoute = (): boolean => { - const rootState = navigationRef.getRootState() as State; - - if (!rootState) { - return false; - } - - return rootState.routes.at(-1)?.name === SCREENS.SEARCH.CENTRAL_PANE; -}; - -export default isSearchTopmostRoute; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 7863478c4103..823e74fafe32 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -38,7 +38,7 @@ import GoogleTagManager from '@libs/GoogleTagManager'; import * as IOUUtils from '@libs/IOUUtils'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; import * as Localize from '@libs/Localize'; -import isSearchTopmostRoute from '@libs/Navigation/isSearchTopmostRoute'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import * as NextStepUtils from '@libs/NextStepUtils'; import {rand64} from '@libs/NumberUtils'; @@ -3680,7 +3680,7 @@ function requestMoney( } } - Navigation.dismissModal(isSearchTopmostRoute() ? undefined : activeReportID); + Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : activeReportID); if (activeReportID) { Report.notifyNewAction(activeReportID, payeeAccountID); } @@ -3737,7 +3737,7 @@ function sendInvoice( API.write(WRITE_COMMANDS.SEND_INVOICE, parameters, onyxData); - if (isSearchTopmostRoute()) { + if (isSearchTopmostFullScreenRoute()) { Navigation.dismissModal(); } else { Navigation.dismissModalWithReport(invoiceRoom); @@ -3931,7 +3931,7 @@ function trackExpense( API.write(WRITE_COMMANDS.TRACK_EXPENSE, parameters, onyxData); } } - Navigation.dismissModal(isSearchTopmostRoute() ? undefined : activeReportID); + Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : activeReportID); if (action === CONST.IOU.ACTION.SHARE) { Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.navigate(ROUTES.ROOM_INVITE.getRoute(activeReportID ?? '-1', CONST.IOU.SHARE.ROLE.ACCOUNTANT))); @@ -4502,7 +4502,7 @@ function splitBill({ API.write(WRITE_COMMANDS.SPLIT_BILL, parameters, onyxData); - Navigation.dismissModal(isSearchTopmostRoute() ? undefined : existingSplitChatReportID); + Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : existingSplitChatReportID); Report.notifyNewAction(splitData.chatReportID, currentUserAccountID); } @@ -4569,7 +4569,7 @@ function splitBillAndOpenReport({ API.write(WRITE_COMMANDS.SPLIT_BILL_AND_OPEN_REPORT, parameters, onyxData); - Navigation.dismissModal(isSearchTopmostRoute() ? undefined : splitData.chatReportID); + Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : splitData.chatReportID); Report.notifyNewAction(splitData.chatReportID, currentUserAccountID); } @@ -5138,7 +5138,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA }; API.write(WRITE_COMMANDS.COMPLETE_SPLIT_BILL, parameters, {optimisticData, successData, failureData}); - Navigation.dismissModal(isSearchTopmostRoute() ? undefined : chatReportID); + Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : chatReportID); Report.notifyNewAction(chatReportID, sessionAccountID); } @@ -5316,7 +5316,7 @@ function createDistanceRequest( API.write(WRITE_COMMANDS.CREATE_DISTANCE_REQUEST, parameters, onyxData); const activeReportID = isMoneyRequestReport ? report?.reportID ?? '-1' : parameters.chatReportID; - Navigation.dismissModal(isSearchTopmostRoute() ? undefined : activeReportID); + Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : activeReportID); Report.notifyNewAction(activeReportID, userAccountID); } @@ -6720,7 +6720,7 @@ function sendMoneyElsewhere(report: OnyxEntry, amount: number, API.write(WRITE_COMMANDS.SEND_MONEY_ELSEWHERE, params, {optimisticData, successData, failureData}); - Navigation.dismissModal(isSearchTopmostRoute() ? undefined : params.chatReportID); + Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : params.chatReportID); Report.notifyNewAction(params.chatReportID, managerID); } @@ -6733,7 +6733,7 @@ function sendMoneyWithWallet(report: OnyxEntry, amount: number API.write(WRITE_COMMANDS.SEND_MONEY_WITH_WALLET, params, {optimisticData, successData, failureData}); - Navigation.dismissModal(isSearchTopmostRoute() ? undefined : params.chatReportID); + Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : params.chatReportID); Report.notifyNewAction(params.chatReportID, managerID); } diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index b63885679e66..55e0207c0244 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -12,7 +12,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import isSearchTopmostRoute from '@libs/Navigation/isSearchTopmostRoute'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import type {EditRequestNavigatorParamList} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; @@ -69,14 +69,14 @@ function EditReportFieldPage({route}: EditReportFieldPageProps) { goBack(); } else { ReportActions.updateReportField(report.reportID, {...reportField, value: value === '' ? null : value}, reportField); - Navigation.dismissModal(isSearchTopmostRoute() ? undefined : report?.reportID); + Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : report?.reportID); } }; const handleReportFieldDelete = () => { ReportActions.deleteReportField(report.reportID, reportField); setIsDeleteModalVisible(false); - Navigation.dismissModal(isSearchTopmostRoute() ? undefined : report?.reportID); + Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : report?.reportID); }; const fieldValue = isReportFieldTitle ? report.reportName ?? '' : reportField.value ?? reportField.defaultValue; diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx index 6fb8a3ece231..5b454fa93ee4 100644 --- a/src/pages/home/report/ReportActionsList.tsx +++ b/src/pages/home/report/ReportActionsList.tsx @@ -20,7 +20,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import DateUtils from '@libs/DateUtils'; -import isSearchTopmostRoute from '@libs/Navigation/isSearchTopmostRoute'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -700,7 +700,7 @@ function ReportActionsList({ }, [isLoadingNewerReportActions, canShowHeader, hasLoadingNewerReportActionsError, retryLoadNewerChatsError]); const onStartReached = useCallback(() => { - if (!isSearchTopmostRoute()) { + if (!isSearchTopmostFullScreenRoute()) { loadNewerChats(false); return; } diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index 92bc544e7bd3..aa74ddf9a335 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -34,7 +34,7 @@ jest.mock('@src/libs/Navigation/Navigation', () => ({ goBack: jest.fn(), })); -jest.mock('@src/libs/Navigation/isSearchTopmostRoute', () => jest.fn()); +jest.mock('@src/libs/Navigation/isSearchTopmostFullScreenRoute', () => jest.fn()); const CARLOS_EMAIL = 'cmartins@expensifail.com'; const CARLOS_ACCOUNT_ID = 1; From a846373ef5e8a5e47d0ee2120f69ff4d35bd9208 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 22 Nov 2024 12:38:23 +0100 Subject: [PATCH 180/257] Cleanup handleDismissModalAction --- .../createCustomStackNavigator/GetStateForActionHandlers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/GetStateForActionHandlers.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/GetStateForActionHandlers.ts index 54542819b569..b2af8cd41f98 100644 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/GetStateForActionHandlers.ts +++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/GetStateForActionHandlers.ts @@ -143,7 +143,7 @@ function handleDismissModalAction( ) { const lastRoute = state.routes.at(-1); const newAction = StackActions.pop(); - action; + if (!lastRoute?.name || !MODAL_ROUTES_TO_DISMISS.includes(lastRoute?.name)) { Log.hmmm('[Navigation] dismissModal failed because there is no modal stack to dismiss'); return null; From c7c315e2deab70fab3f7307d903c39fcdacecbe4 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 2 Dec 2024 14:08:09 +0100 Subject: [PATCH 181/257] Adjust split router to native stack --- .../Navigation/AppNavigator/AuthScreens.tsx | 2 +- .../Navigators/ReportsSplitNavigator.tsx | 8 +- .../Navigators/SettingsSplitNavigator.tsx | 21 ++-- .../Navigators/WorkspaceSplitNavigator.tsx | 8 ++ .../CustomRouter.ts | 4 +- .../createResponsiveStackNavigator/index.tsx | 21 ++-- .../createSplitStackNavigator/index.tsx | 105 ++++++------------ .../AppNavigator/useRootNavigatorOptions.ts | 17 ++- .../index.native.tsx | 17 ++- .../index.tsx | 17 ++- 10 files changed, 124 insertions(+), 96 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 2c750ddbcb6b..058355f53388 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -398,7 +398,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie /> diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index c83816a21b5d..f5e90411722d 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -1,9 +1,11 @@ +import {useRoute} from '@react-navigation/native'; import React, {useRef} from 'react'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import usePermissions from '@hooks/usePermissions'; import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; import FreezeWrapper from '@libs/Navigation/AppNavigator/FreezeWrapper'; +import useRootNavigatorOptions from '@libs/Navigation/AppNavigator/useRootNavigatorOptions'; import getCurrentUrl from '@libs/Navigation/currentUrl'; import shouldOpenOnAdminRoom from '@libs/Navigation/shouldOpenOnAdminRoom'; import type {ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; @@ -20,7 +22,8 @@ const Stack = createSplitStackNavigator(); function ReportsSplitNavigator() { const {canUseDefaultRooms} = usePermissions(); const {activeWorkspaceID} = useActiveWorkspace(); - + const rootNavigatorOptions = useRootNavigatorOptions(); + const route = useRoute(); let initialReportID: string | undefined; const isInitialRender = useRef(true); @@ -47,10 +50,13 @@ function ReportsSplitNavigator() { (); function SettingsSplitNavigator() { - const styles = useThemeStyles(); - const StyleUtils = useStyleUtils(); - const {shouldUseNarrowLayout} = useResponsiveLayout(); + const screenOptions = useRootNavigatorOptions(); + const route = useRoute(); + const rootNavigatorOptions = useRootNavigatorOptions(); return ( {Object.entries(CENTRAL_PANE_SETTINGS_SCREENS).map(([screenName, componentGetter]) => { - // const options = {...screenOptions.centralPaneNavigator}; + const options = {...screenOptions.fullScreen}; - // if (screenName === SCREENS.SETTINGS.WORKSPACES) { - // options.animationEnabled = false; - // } + if (screenName === SCREENS.SETTINGS.WORKSPACES) { + options.animation = 'none'; + } return ( ); })} diff --git a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx index 9c1b6c8087ca..fd0c91757fa4 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx @@ -1,6 +1,8 @@ +import {useRoute} from '@react-navigation/native'; import React from 'react'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; +import useRootNavigatorOptions from '@libs/Navigation/AppNavigator/useRootNavigatorOptions'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; @@ -30,15 +32,21 @@ const CENTRAL_PANE_WORKSPACE_SCREENS = { const Stack = createSplitStackNavigator(); function WorkspaceNavigator() { + const route = useRoute(); + const rootNavigatorOptions = useRootNavigatorOptions(); + return ( {Object.entries(CENTRAL_PANE_WORKSPACE_SCREENS).map(([screenName, componentGetter]) => ( ('@libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter').default; + +function useCustomRouterState({state}: CustomStateHookProps) { + const lastSplitIndex = state.routes.findLastIndex((route) => isFullScreenName(route.name)); + const routesToRender = state.routes.slice(Math.max(0, lastSplitIndex - 1), state.routes.length); + + return {stateToRender: {...state, routes: routesToRender, index: routesToRender.length - 1}}; +} const ResponsiveStackNavigatorComponent = createPlatformStackNavigatorComponent('ResponsiveStackNavigator', { - createRouter: CustomRouter, + createRouter: loadCustomRouter, defaultScreenOptions: defaultPlatformStackScreenOptions, - useCustomState: useStateWithSearch, useCustomEffects: useNavigationResetOnLayoutChange, - ExtraContent: RenderSearchRoute, + useCustomState: useCustomRouterState, }); function createResponsiveStackNavigator() { diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index fe48e754893b..7071e85eb6ed 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -1,21 +1,27 @@ -import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native'; -import {createNavigatorFactory, useNavigationBuilder, useRoute} from '@react-navigation/native'; -import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; -import {StackView} from '@react-navigation/stack'; -import React, {useMemo} from 'react'; -import {View} from 'react-native'; -import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; +import type {ParamListBase} from '@react-navigation/native'; +import {createNavigatorFactory} from '@react-navigation/native'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import useStyleUtils from '@hooks/useStyleUtils'; -import useThemeStyles from '@hooks/useThemeStyles'; -import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions'; +import useNavigationResetOnLayoutChange from '@libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange'; +import createPlatformStackNavigatorComponent from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent'; +import defaultPlatformStackScreenOptions from '@libs/Navigation/PlatformStackNavigation/defaultPlatformStackScreenOptions'; +import type { + CustomEffectsHookProps, + CustomStateHookProps, + PlatformStackNavigationEventMap, + PlatformStackNavigationOptions, + PlatformStackNavigationState, +} from '@libs/Navigation/PlatformStackNavigation/types'; import SplitStackRouter from './SplitStackRouter'; -import type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions} from './types'; -import useHandleScreenResize from './useHandleScreenResize'; -import usePrepareSplitStackNavigatorChildren from './usePrepareSplitStackNavigatorChildren'; import usePreserveSplitNavigatorState from './usePreserveSplitNavigatorState'; -function getStateToRender(state: StackNavigationState, isSmallScreenWidth: boolean): StackNavigationState { +function useCustomEffects(props: CustomEffectsHookProps, route) { + useNavigationResetOnLayoutChange(props); + usePreserveSplitNavigatorState(route, props.navigation.getState()); +} + +function useCustomSplitNavigatorState({state}: CustomStateHookProps) { + const {shouldUseNarrowLayout} = useResponsiveLayout(); + const sidebarScreenRoute = state.routes.at(0); if (!sidebarScreenRoute) { @@ -23,67 +29,22 @@ function getStateToRender(state: StackNavigationState, isSmallScr } const centralScreenRoutes = state.routes.slice(1); - const routes = isSmallScreenWidth ? state.routes.slice(-2) : [sidebarScreenRoute, ...centralScreenRoutes.slice(-2)]; + const routesToRender = shouldUseNarrowLayout ? state.routes.slice(-2) : [sidebarScreenRoute, ...centralScreenRoutes.slice(-2)]; - return { - ...state, - routes, - index: routes.length - 1, - }; + return {stateToRender: {...state, routes: routesToRender, index: routesToRender.length - 1}}; } -function SplitStackNavigator(props: SplitStackNavigatorProps) { - const styles = useThemeStyles(); - const StyleUtils = useStyleUtils(); - const {shouldUseNarrowLayout} = useResponsiveLayout(); - - - // const children = usePrepareSplitStackNavigatorChildren(props.children, props.sidebarScreen, screenOptions.homeScreen); - - const route = useRoute(); +const CustomFullScreenNavigatorComponent = createPlatformStackNavigatorComponent('CustomFullScreenNavigator', { + createRouter: SplitStackRouter, + useCustomEffects, + defaultScreenOptions: defaultPlatformStackScreenOptions, + useCustomState: useCustomSplitNavigatorState, +}); - const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< - StackNavigationState, - SplitStackNavigatorRouterOptions, - StackActionHelpers, - StackNavigationOptions, - StackNavigationEventMap - >(SplitStackRouter, { - children: props.children, - // screenOptions: screenOptions.centralPaneNavigator, - initialRouteName: props.initialRouteName, - sidebarScreen: props.sidebarScreen, - defaultCentralScreen: props.defaultCentralScreen, - parentRoute: route, - }); - - // We need to copy the state to the params so that the state is preserved when the root navigator unmount this route for performance reasons. - usePreserveSplitNavigatorState(route, state); - useHandleScreenResize(navigation); - - const stateToRender = useMemo(() => getStateToRender(state, shouldUseNarrowLayout), [state, shouldUseNarrowLayout]); - - return ( - - - - - - - - ); -} - -SplitStackNavigator.displayName = 'SplitStackNavigator'; - -export default function () { - return createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, React.ComponentType>>( - SplitStackNavigator, +function createCustomFullScreenNavigator() { + return createNavigatorFactory, PlatformStackNavigationOptions, PlatformStackNavigationEventMap, typeof CustomFullScreenNavigatorComponent>( + CustomFullScreenNavigatorComponent, )(); } + +export default createCustomFullScreenNavigator; diff --git a/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts b/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts index de7971213526..32bd0dd10de6 100644 --- a/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts +++ b/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts @@ -109,7 +109,22 @@ const useRootNavigatorOptions = () => { fullScreen: { ...commonScreenOptions, // We need to turn off animation for the full screen to avoid delay when closing screens. - animation: shouldUseNarrowLayout ? Animations.SLIDE_FROM_RIGHT : Animations.NONE, + animation: Animations.NONE, + web: { + cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator({props, isFullScreenModal: true}), + cardStyle: { + ...StyleUtils.getNavigationModalCardStyle(), + + // This is necessary to cover whole screen. Including translated sidebar. + // marginLeft: shouldUseNarrowLayout ? 0 : -variables.sideBarWidth, + }, + }, + }, + + searchPage: { + ...commonScreenOptions, + // We need to turn off animation for the full screen to avoid delay when closing screens. + animation: Animations.NONE, web: { cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator({props, isFullScreenModal: true}), cardStyle: { diff --git a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.native.tsx b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.native.tsx index 35076c8ca6b6..3794ec2d3834 100644 --- a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.native.tsx +++ b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.native.tsx @@ -25,7 +25,17 @@ function createPlatformStackNavigatorComponent) { + function PlatformNavigator({ + id, + initialRouteName, + screenOptions, + screenListeners, + children, + sidebarScreen, + defaultCentralScreen, + parentRoute, + ...props + }: PlatformStackNavigatorProps) { const { navigation, state: originalState, @@ -47,6 +57,9 @@ function createPlatformStackNavigatorComponent, convertToNativeNavigationOptions, ); @@ -73,7 +86,7 @@ function createPlatformStackNavigatorComponent ( diff --git a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx index 2e3c99a6cb0d..8cd35fdab2b7 100644 --- a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx +++ b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx @@ -25,7 +25,17 @@ function createPlatformStackNavigatorComponent undefined); - function PlatformNavigator({id, initialRouteName, screenOptions, screenListeners, children, ...props}: PlatformStackNavigatorProps) { + function PlatformNavigator({ + id, + initialRouteName, + screenOptions, + screenListeners, + children, + sidebarScreen, + defaultCentralScreen, + parentRoute, + ...props + }: PlatformStackNavigatorProps) { const { navigation, state: originalState, @@ -47,6 +57,9 @@ function createPlatformStackNavigatorComponent, convertToWebNavigationOptions, ); @@ -73,7 +86,7 @@ function createPlatformStackNavigatorComponent ( From 976549982371ac2f50ed905a3c9c8fa8575958e5 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 3 Dec 2024 12:51:12 +0100 Subject: [PATCH 182/257] Adjust PlatformStackNavigator typescript and styles to SplitNavigators --- .../Navigation/AppNavigator/AuthScreens.tsx | 16 -- .../Navigators/SettingsSplitNavigator.tsx | 7 +- .../CustomRouter.ts | 102 ----------- .../createCustomStackNavigator/index.tsx | 51 ------ .../CustomRouter.ts | 161 +++++++----------- .../GetStateForActionHandlers.ts | 2 +- .../SearchRoute.tsx | 23 --- .../createResponsiveStackNavigator/index.tsx | 6 +- .../types.ts | 0 .../useStateWithSearch.ts | 80 --------- .../AppNavigator/useRootNavigatorOptions.ts | 4 +- .../types/NavigationBuilder.ts | 8 +- .../PlatformStackNavigation/types/index.ts | 7 +- .../Navigation/getTopmostBottomTabRoute.ts | 21 --- .../linkTo/getActionForBottomTabNavigator.ts | 50 ------ src/libs/NavigationUtils.ts | 9 +- .../settings/Wallet/VerifyAccountPage.tsx | 2 +- ...orkspaceWorkflowsApprovalsApproverPage.tsx | 1 + 18 files changed, 86 insertions(+), 464 deletions(-) delete mode 100644 src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts delete mode 100644 src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx delete mode 100644 src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/SearchRoute.tsx rename src/libs/Navigation/AppNavigator/{createCustomStackNavigator => createResponsiveStackNavigator}/types.ts (100%) delete mode 100644 src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/useStateWithSearch.ts delete mode 100644 src/libs/Navigation/getTopmostBottomTabRoute.ts delete mode 100644 src/libs/Navigation/linkTo/getActionForBottomTabNavigator.ts diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 058355f53388..ff31c0779f30 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -12,9 +12,7 @@ import {useSearchRouterContext} from '@components/Search/SearchRouter/SearchRout import SearchRouterModal from '@components/Search/SearchRouter/SearchRouterModal'; import TestToolsModal from '@components/TestToolsModal'; import * as TooltipManager from '@components/Tooltip/EducationalTooltip/TooltipManager'; -import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useOnboardingFlowRouter from '@hooks/useOnboardingFlow'; -import usePermissions from '@hooks/usePermissions'; import {ReportIDsContextProvider} from '@hooks/useReportIDs'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; @@ -27,14 +25,12 @@ import NavBarManager from '@libs/NavBarManager'; import getCurrentUrl from '@libs/Navigation/currentUrl'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import Presentation from '@libs/Navigation/PlatformStackNavigation/navigationOptions/presentation'; -import shouldOpenOnAdminRoom from '@libs/Navigation/shouldOpenOnAdminRoom'; import type {AuthScreensParamList} from '@libs/Navigation/types'; import {isOnboardingFlowName} from '@libs/NavigationUtils'; import NetworkConnection from '@libs/NetworkConnection'; import onyxSubscribe from '@libs/onyxSubscribe'; import * as Pusher from '@libs/Pusher/pusher'; import PusherConnectionManager from '@libs/PusherConnectionManager'; -import * as ReportUtils from '@libs/ReportUtils'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; import * as SessionUtils from '@libs/SessionUtils'; import ConnectionCompletePage from '@pages/ConnectionCompletePage'; @@ -211,23 +207,11 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie const styles = useThemeStyles(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const rootNavigatorOptions = useRootNavigatorOptions(); - const {canUseDefaultRooms} = usePermissions(); - const {activeWorkspaceID} = useActiveWorkspace(); const {toggleSearchRouter} = useSearchRouterContext(); const modal = useRef({}); const [didPusherInit, setDidPusherInit] = useState(false); const {isOnboardingCompleted} = useOnboardingFlowRouter(); - const [initialReportID] = useState(() => { - const currentURL = getCurrentUrl(); - const reportIdFromPath = currentURL && new URL(currentURL).pathname.match(CONST.REGEX.REPORT_ID_FROM_PATH)?.at(1); - if (reportIdFromPath) { - return reportIdFromPath; - } - - const initialReport = ReportUtils.findLastAccessedReport(!canUseDefaultRooms, shouldOpenOnAdminRoom(), activeWorkspaceID); - return initialReport?.reportID ?? ''; - }); useEffect(() => { NavBarManager.setButtonStyle(theme.navigationBarButtonsStyle); diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx index 5b0a0e1c407b..7972f6673c4d 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx @@ -1,11 +1,9 @@ import {useRoute} from '@react-navigation/native'; import React from 'react'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import useStyleUtils from '@hooks/useStyleUtils'; -import useThemeStyles from '@hooks/useThemeStyles'; import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; import useRootNavigatorOptions from '@libs/Navigation/AppNavigator/useRootNavigatorOptions'; +import {PlatformStackNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types'; import type {SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; @@ -29,7 +27,6 @@ const CENTRAL_PANE_SETTINGS_SCREENS = { const Stack = createSplitStackNavigator(); function SettingsSplitNavigator() { - const screenOptions = useRootNavigatorOptions(); const route = useRoute(); const rootNavigatorOptions = useRootNavigatorOptions(); @@ -47,7 +44,7 @@ function SettingsSplitNavigator() { options={rootNavigatorOptions.homeScreen} /> {Object.entries(CENTRAL_PANE_SETTINGS_SCREENS).map(([screenName, componentGetter]) => { - const options = {...screenOptions.fullScreen}; + const options: PlatformStackNavigationOptions = {animation: undefined}; if (screenName === SCREENS.SETTINGS.WORKSPACES) { options.animation = 'none'; diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts deleted file mode 100644 index 62b5b90d6658..000000000000 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts +++ /dev/null @@ -1,102 +0,0 @@ -import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; -import {findFocusedRoute, StackRouter} from '@react-navigation/native'; -import type {ParamListBase} from '@react-navigation/routers'; -import useActiveWorkspace from '@hooks/useActiveWorkspace'; -import * as Localize from '@libs/Localize'; -import * as GetStateForActionHandlers from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers'; -import syncBrowserHistory from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator/syncBrowserHistory'; -import isSideModalNavigator from '@libs/Navigation/isSideModalNavigator'; -import {isOnboardingFlowName} from '@libs/NavigationUtils'; -import * as Welcome from '@userActions/Welcome'; -import CONST from '@src/CONST'; -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; -import type {CustomRouterAction, CustomRouterActionType, DismissModalActionType, PushActionType, ResponsiveStackNavigatorRouterOptions, SwitchPolicyIdActionType} from './types'; - -function isSwitchPolicyIdAction(action: CustomRouterAction): action is SwitchPolicyIdActionType { - return action.type === CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID; -} - -function isPushAction(action: CustomRouterAction): action is PushActionType { - return action.type === CONST.NAVIGATION.ACTION_TYPE.PUSH; -} - -function isDismissModalAction(action: CustomRouterAction): action is DismissModalActionType { - return action.type === CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL; -} - -function shouldPreventReset(state: StackNavigationState, action: CommonActions.Action | StackActionType) { - if (action.type !== CONST.NAVIGATION_ACTIONS.RESET || !action?.payload) { - return false; - } - const currentFocusedRoute = findFocusedRoute(state); - const targetFocusedRoute = findFocusedRoute(action?.payload); - - // We want to prevent the user from navigating back to a non-onboarding screen if they are currently on an onboarding screen - if (isOnboardingFlowName(currentFocusedRoute?.name) && !isOnboardingFlowName(targetFocusedRoute?.name)) { - Welcome.setOnboardingErrorMessage(Localize.translateLocal('onboarding.purpose.errorBackButton')); - return true; - } - - return false; -} - -function isNavigatingToModalFromModal(state: StackNavigationState, action: CommonActions.Action | StackActionType) { - if (action.type !== CONST.NAVIGATION.ACTION_TYPE.PUSH) { - return false; - } - - const lastRoute = state.routes.at(-1); - - // If the last route is a side modal navigator and the generated minimal action want's to push a new side modal navigator that means they are different ones. - // We want to dismiss the one that is currently on the top. - if (isSideModalNavigator(lastRoute?.name) && isSideModalNavigator(action.payload.name)) { - return true; - } - return false; -} - -function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { - const stackRouter = StackRouter(options); - const {setActiveWorkspaceID} = useActiveWorkspace(); - - // @TODO: Make sure that everything works fine without compareAndAdaptState function. Probably with getMatchingFullScreenRoute. - return { - ...stackRouter, - getStateForAction(state: StackNavigationState, action: CustomRouterAction, configOptions: RouterConfigOptions) { - if (isSwitchPolicyIdAction(action)) { - return GetStateForActionHandlers.handleSwitchPolicyID(state, action, configOptions, stackRouter, setActiveWorkspaceID); - } - - if (isDismissModalAction(action)) { - return GetStateForActionHandlers.handleDismissModalAction(state, action, configOptions, stackRouter); - } - - if (isPushAction(action)) { - if (action.payload.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { - return GetStateForActionHandlers.handlePushReportAction(state, action, configOptions, stackRouter, setActiveWorkspaceID); - } - - if (action.payload.name === SCREENS.SEARCH.CENTRAL_PANE) { - return GetStateForActionHandlers.handlePushSearchPageAction(state, action, configOptions, stackRouter, setActiveWorkspaceID); - } - } - - // Don't let the user navigate back to a non-onboarding screen if they are currently on an onboarding screen and it's not finished. - if (shouldPreventReset(state, action)) { - syncBrowserHistory(state); - return state; - } - - if (isNavigatingToModalFromModal(state, action)) { - const modifiedState = {...state, routes: state.routes.slice(0, -1), index: state.index !== 0 ? state.index - 1 : 0}; - return stackRouter.getStateForAction(modifiedState, action, configOptions); - } - - return stackRouter.getStateForAction(state, action, configOptions); - }, - }; -} - -export default CustomRouter; -export type {CustomRouterActionType}; diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx deleted file mode 100644 index ab15dc49bd14..000000000000 --- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native'; -import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native'; -import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; -import {StackView} from '@react-navigation/stack'; -import React, {useMemo} from 'react'; -import {isFullScreenName} from '@libs/NavigationUtils'; -import CustomRouter from './CustomRouter'; -import type {ResponsiveStackNavigatorProps, ResponsiveStackNavigatorRouterOptions} from './types'; - -function getStateToRender(state: StackNavigationState): StackNavigationState { - const lastSplitIndex = state.routes.findLastIndex((route) => isFullScreenName(route.name)); - const routes = state.routes.slice(Math.max(0, lastSplitIndex - 1), state.routes.length); - - return { - ...state, - routes, - index: routes.length - 1, - }; -} - -function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) { - const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder< - StackNavigationState, - ResponsiveStackNavigatorRouterOptions, - StackActionHelpers, - StackNavigationOptions, - StackNavigationEventMap - >(CustomRouter, { - children: props.children, - screenOptions: props.screenOptions, - initialRouteName: props.initialRouteName, - }); - - const stateToRender = useMemo(() => getStateToRender(state), [state]); - - return ( - - - - ); -} - -ResponsiveStackNavigator.displayName = 'ResponsiveStackNavigator'; - -export default createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, typeof ResponsiveStackNavigator>(ResponsiveStackNavigator); diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts index 84f14df000b3..f678425e2ec5 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts @@ -1,104 +1,29 @@ import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; import {findFocusedRoute, StackRouter} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/routers'; +import useActiveWorkspace from '@hooks/useActiveWorkspace'; import * as Localize from '@libs/Localize'; -import type {PlatformStackRouterOptions} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {RootStackParamList} from '@libs/Navigation/types'; +import isSideModalNavigator from '@libs/Navigation/isSideModalNavigator'; import {isOnboardingFlowName} from '@libs/NavigationUtils'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; +import * as GetStateForActionHandlers from './GetStateForActionHandlers'; import syncBrowserHistory from './syncBrowserHistory'; +import type {CustomRouterAction, CustomRouterActionType, DismissModalActionType, PushActionType, ResponsiveStackNavigatorRouterOptions, SwitchPolicyIdActionType} from './types'; -// @TODO: Verify if these functions are still needed - -// function insertRootRoute(state: State, routeToInsert: NavigationPartialRoute) { -// const nonModalRoutes = state.routes.filter( -// (route) => route.name !== NAVIGATORS.RIGHT_MODAL_NAVIGATOR && route.name !== NAVIGATORS.LEFT_MODAL_NAVIGATOR && route.name !== NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR, -// ); -// const modalRoutes = state.routes.filter( -// (route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || route.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR || route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR, -// ); - -// // It's safe to modify this state before returning in getRehydratedState. - -// // @ts-expect-error Updating read only property -// // noinspection JSConstantReassignment -// state.routes = [...nonModalRoutes, routeToInsert, ...modalRoutes]; // eslint-disable-line - -// // @ts-expect-error Updating read only property -// // noinspection JSConstantReassignment -// state.index = state.routes.length - 1; // eslint-disable-line - -// // @ts-expect-error Updating read only property -// // noinspection JSConstantReassignment -// state.stale = true; // eslint-disable-line -// } - -// function compareAndAdaptState(state: StackNavigationState) { -// // If the state of the last path is not defined the getPathFromState won't work correctly. -// if (!state?.routes.at(-1)?.state) { -// return; -// } - -// // We need to be sure that the bottom tab state is defined. -// const topmostBottomTabRoute = getTopmostBottomTabRoute(state); -// const isNarrowLayout = getIsNarrowLayout(); - -// // This solutions is heuristics and will work for our cases. We may need to improve it in the future if we will have more cases to handle. -// if (topmostBottomTabRoute && !isNarrowLayout) { -// const fullScreenRoute = state.routes.find((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR); - -// // If there is fullScreenRoute we don't need to add anything. -// if (fullScreenRoute) { -// return; -// } - -// // We will generate a template state and compare the current state with it. -// // If there is a difference in the screens that should be visible under the overlay, we will add the screen from templateState to the current state. -// const pathFromCurrentState = getPathFromState(state, linkingConfig.config); -// const {adaptedState: templateState} = getAdaptedStateFromPath(pathFromCurrentState, linkingConfig.config); - -// if (!templateState) { -// return; -// } - -// const templateFullScreenRoute = templateState.routes.find((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR); - -// // If templateFullScreenRoute is defined, and full screen route is not in the state, we need to add it. -// if (templateFullScreenRoute) { -// insertRootRoute(state, templateFullScreenRoute); -// return; -// } - -// const topmostCentralPaneRoute = state.routes.filter((route) => isCentralPaneName(route.name)).at(-1); -// const templateCentralPaneRoute = templateState.routes.find((route) => isCentralPaneName(route.name)); - -// const topmostCentralPaneRouteExtracted = getTopmostCentralPaneRoute(state); -// const templateCentralPaneRouteExtracted = getTopmostCentralPaneRoute(templateState as State); - -// // If there is no templateCentralPaneRoute, we don't have anything to add. -// if (!templateCentralPaneRoute) { -// return; -// } - -// // If there is no topmostCentralPaneRoute in the state and template state has one, we need to add it. -// if (!topmostCentralPaneRoute) { -// insertRootRoute(state, templateCentralPaneRoute); -// return; -// } - -// // If there is central pane route in state and template state has one, we need to check if they are the same. -// if (topmostCentralPaneRouteExtracted && templateCentralPaneRouteExtracted && topmostCentralPaneRouteExtracted.name !== templateCentralPaneRouteExtracted.name) { -// // Not every RHP screen has matching central pane defined. In that case we use the REPORT screen as default for initial screen. -// // But we don't want to override the central pane for those screens as they may be opened with different central panes under the overlay. -// // e.g. i-know-a-teacher may be opened with different central panes under the overlay -// if (templateCentralPaneRouteExtracted.name === SCREENS.REPORT) { -// return; -// } -// insertRootRoute(state, templateCentralPaneRoute); -// } -// } -// } +function isSwitchPolicyIdAction(action: CustomRouterAction): action is SwitchPolicyIdActionType { + return action.type === CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID; +} + +function isPushAction(action: CustomRouterAction): action is PushActionType { + return action.type === CONST.NAVIGATION.ACTION_TYPE.PUSH; +} + +function isDismissModalAction(action: CustomRouterAction): action is DismissModalActionType { + return action.type === CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL; +} function shouldPreventReset(state: StackNavigationState, action: CommonActions.Action | StackActionType) { if (action.type !== CONST.NAVIGATION_ACTIONS.RESET || !action?.payload) { @@ -116,24 +41,62 @@ function shouldPreventReset(state: StackNavigationState, action: return false; } -function CustomRouter(options: PlatformStackRouterOptions) { +function isNavigatingToModalFromModal(state: StackNavigationState, action: CommonActions.Action | StackActionType) { + if (action.type !== CONST.NAVIGATION.ACTION_TYPE.PUSH) { + return false; + } + + const lastRoute = state.routes.at(-1); + + // If the last route is a side modal navigator and the generated minimal action want's to push a new side modal navigator that means they are different ones. + // We want to dismiss the one that is currently on the top. + if (isSideModalNavigator(lastRoute?.name) && isSideModalNavigator(action.payload.name)) { + return true; + } + return false; +} + +function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { const stackRouter = StackRouter(options); + const {setActiveWorkspaceID} = useActiveWorkspace(); + // @TODO: Make sure that everything works fine without compareAndAdaptState function. Probably with getMatchingFullScreenRoute. return { ...stackRouter, - getRehydratedState(partialState: StackNavigationState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): StackNavigationState { - // compareAndAdaptState(partialState); - const state = stackRouter.getRehydratedState(partialState, {routeNames, routeParamList, routeGetIdList}); - return state; - }, - getStateForAction(state: StackNavigationState, action: CommonActions.Action | StackActionType, configOptions: RouterConfigOptions) { + getStateForAction(state: StackNavigationState, action: CustomRouterAction, configOptions: RouterConfigOptions) { + if (isSwitchPolicyIdAction(action)) { + return GetStateForActionHandlers.handleSwitchPolicyID(state, action, configOptions, stackRouter, setActiveWorkspaceID); + } + + if (isDismissModalAction(action)) { + return GetStateForActionHandlers.handleDismissModalAction(state, action, configOptions, stackRouter); + } + + if (isPushAction(action)) { + if (action.payload.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { + return GetStateForActionHandlers.handlePushReportAction(state, action, configOptions, stackRouter, setActiveWorkspaceID); + } + + if (action.payload.name === SCREENS.SEARCH.CENTRAL_PANE) { + return GetStateForActionHandlers.handlePushSearchPageAction(state, action, configOptions, stackRouter, setActiveWorkspaceID); + } + } + + // Don't let the user navigate back to a non-onboarding screen if they are currently on an onboarding screen and it's not finished. if (shouldPreventReset(state, action)) { syncBrowserHistory(state); return state; } + + if (isNavigatingToModalFromModal(state, action)) { + const modifiedState = {...state, routes: state.routes.slice(0, -1), index: state.index !== 0 ? state.index - 1 : 0}; + return stackRouter.getStateForAction(modifiedState, action, configOptions); + } + return stackRouter.getStateForAction(state, action, configOptions); }, }; } export default CustomRouter; +export type {CustomRouterActionType}; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts index 3b2a119dbd1c..b2af8cd41f98 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts @@ -2,12 +2,12 @@ import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigatio import {StackActions} from '@react-navigation/native'; import type {ParamListBase, Router} from '@react-navigation/routers'; import Log from '@libs/Log'; -import type {DismissModalActionType, PushActionType, SwitchPolicyIdActionType} from '@libs/Navigation/AppNavigator/createCustomStackNavigator/types'; import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; import type {RootStackParamList, State} from '@libs/Navigation/types'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; +import type {DismissModalActionType, PushActionType, SwitchPolicyIdActionType} from './types'; const MODAL_ROUTES_TO_DISMISS: string[] = [ NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/SearchRoute.tsx b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/SearchRoute.tsx deleted file mode 100644 index 2455587660ab..000000000000 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/SearchRoute.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; -import {View} from 'react-native'; -import useThemeStyles from '@hooks/useThemeStyles'; -import type {ExtraContentProps} from '@libs/Navigation/PlatformStackNavigation/types'; - -function SearchRoute({searchRoute, descriptors}: ExtraContentProps) { - const styles = useThemeStyles(); - - if (!searchRoute) { - return null; - } - - const key = searchRoute.key; - const descriptor = descriptors[key]; - - if (!descriptor) { - return null; - } - - return {descriptor.render()}; -} - -export default SearchRoute; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx index 8bfe1ed4042e..462bb315b33c 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx @@ -5,9 +5,7 @@ import createPlatformStackNavigatorComponent from '@libs/Navigation/PlatformStac import defaultPlatformStackScreenOptions from '@libs/Navigation/PlatformStackNavigation/defaultPlatformStackScreenOptions'; import type {CustomStateHookProps, PlatformStackNavigationEventMap, PlatformStackNavigationOptions, PlatformStackNavigationState} from '@libs/Navigation/PlatformStackNavigation/types'; import {isFullScreenName} from '@libs/NavigationUtils'; -import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; - -const loadCustomRouter = require('@libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter').default; +import CustomRouter from './CustomRouter'; function useCustomRouterState({state}: CustomStateHookProps) { const lastSplitIndex = state.routes.findLastIndex((route) => isFullScreenName(route.name)); @@ -17,7 +15,7 @@ function useCustomRouterState({state}: CustomStateHookProps) { } const ResponsiveStackNavigatorComponent = createPlatformStackNavigatorComponent('ResponsiveStackNavigator', { - createRouter: loadCustomRouter, + createRouter: CustomRouter, defaultScreenOptions: defaultPlatformStackScreenOptions, useCustomEffects: useNavigationResetOnLayoutChange, useCustomState: useCustomRouterState, diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/types.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts rename to src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/types.ts diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/useStateWithSearch.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/useStateWithSearch.ts deleted file mode 100644 index 73984af34d2e..000000000000 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/useStateWithSearch.ts +++ /dev/null @@ -1,80 +0,0 @@ -import type {ParamListBase} from '@react-navigation/native'; -import {useMemo} from 'react'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; -import type {CustomStateHookProps, PlatformStackNavigationState, PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; -import {isCentralPaneName} from '@libs/NavigationUtils'; -import SCREENS from '@src/SCREENS'; - -type Routes = PlatformStackNavigationState['routes']; -function reduceCentralPaneRoutes(routes: Routes): Routes { - const result: Routes = []; - let count = 0; - const reverseRoutes = [...routes].reverse(); - - reverseRoutes.forEach((route) => { - if (isCentralPaneName(route.name)) { - // Remove all central pane routes except the last 3. This will improve performance. - if (count < 3) { - result.push(route); - count++; - } - } else { - result.push(route); - } - }); - - return result.reverse(); -} - -function useStateWithSearch({state}: CustomStateHookProps) { - const {shouldUseNarrowLayout} = useResponsiveLayout(); - return useMemo(() => { - const routes = reduceCentralPaneRoutes(state.routes); - - if (shouldUseNarrowLayout) { - const isSearchCentralPane = (route: PlatformStackRouteProp) => - getTopmostCentralPaneRoute({routes: [route]} as State)?.name === SCREENS.SEARCH.CENTRAL_PANE; - - const lastRoute = routes.at(-1); - const lastSearchCentralPane = lastRoute && isSearchCentralPane(lastRoute) ? lastRoute : undefined; - const filteredRoutes = routes.filter((route) => !isSearchCentralPane(route)); - - // On narrow layout, if we are on /search route we want to hide all central pane routes and show only the bottom tab navigator. - if (lastSearchCentralPane) { - const filteredRoute = filteredRoutes.at(0); - if (filteredRoute) { - return { - stateToRender: { - ...state, - index: 0, - routes: [filteredRoute], - }, - searchRoute: lastSearchCentralPane, - }; - } - } - - return { - stateToRender: { - ...state, - index: filteredRoutes.length - 1, - routes: filteredRoutes, - }, - searchRoute: undefined, - }; - } - - return { - stateToRender: { - ...state, - index: routes.length - 1, - routes: [...routes], - }, - searchRoute: undefined, - }; - }, [state, shouldUseNarrowLayout]); -} - -export default useStateWithSearch; diff --git a/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts b/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts index 32bd0dd10de6..729be96c2d41 100644 --- a/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts +++ b/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts @@ -18,6 +18,7 @@ type RootNavigatorOptions = { fullScreen: PlatformStackNavigationOptions; centralPaneNavigator: PlatformStackNavigationOptions; bottomTab: PlatformStackNavigationOptions; + searchPage: PlatformStackNavigationOptions; }; const commonScreenOptions: PlatformStackNavigationOptions = { @@ -114,9 +115,6 @@ const useRootNavigatorOptions = () => { cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator({props, isFullScreenModal: true}), cardStyle: { ...StyleUtils.getNavigationModalCardStyle(), - - // This is necessary to cover whole screen. Including translated sidebar. - // marginLeft: shouldUseNarrowLayout ? 0 : -variables.sideBarWidth, }, }, }, diff --git a/src/libs/Navigation/PlatformStackNavigation/types/NavigationBuilder.ts b/src/libs/Navigation/PlatformStackNavigation/types/NavigationBuilder.ts index 821584f58645..e3199b27997b 100644 --- a/src/libs/Navigation/PlatformStackNavigation/types/NavigationBuilder.ts +++ b/src/libs/Navigation/PlatformStackNavigation/types/NavigationBuilder.ts @@ -20,7 +20,13 @@ type PlatformNavigationBuilderOptions< EventMap extends PlatformSpecificEventMap & EventMapBase, ParamList extends ParamListBase = ParamListBase, RouterOptions extends PlatformStackRouterOptions = PlatformStackRouterOptions, -> = DefaultNavigatorOptions, NavigationOptions, EventMap> & NavigationBuilderOptions & RouterOptions; +> = DefaultNavigatorOptions, NavigationOptions, EventMap> & + NavigationBuilderOptions & + RouterOptions & { + defaultCentralScreen?: Extract; + sidebarScreen?: Extract; + parentRoute?: RouteProp; + }; // Represents the return type of the useNavigationBuilder function using the types from PlatformStackNavigation. type PlatformNavigationBuilderResult< diff --git a/src/libs/Navigation/PlatformStackNavigation/types/index.ts b/src/libs/Navigation/PlatformStackNavigation/types/index.ts index 04ed4e68d9a8..ff7515e300d4 100644 --- a/src/libs/Navigation/PlatformStackNavigation/types/index.ts +++ b/src/libs/Navigation/PlatformStackNavigation/types/index.ts @@ -27,7 +27,7 @@ type PlatformStackNavigationEventMap = CommonStackNavigationEventMap; type PlatformSpecificEventMap = StackNavigationOptions | NativeStackNavigationOptions; // Router options used in the PlatformStackNavigation -type PlatformStackRouterOptions = StackRouterOptions; +type PlatformStackRouterOptions = StackRouterOptions & {parentRoute?: RouteProp}; // Factory function type for creating a router specific to the PlatformStackNavigation type PlatformStackRouterFactory = RouterFactory< @@ -68,7 +68,10 @@ type PlatformStackNavigatorProps< RouterOptions extends PlatformStackRouterOptions = PlatformStackRouterOptions, > = DefaultNavigatorOptions, PlatformStackNavigationOptions, PlatformStackNavigationEventMap, RouteName> & RouterOptions & - StackNavigationConfig; + StackNavigationConfig & { + defaultCentralScreen?: Extract; + sidebarScreen?: Extract; + }; // The "screenOptions" and "defaultScreenOptions" can either be an object of navigation options or // a factory function that returns the navigation options based on route and navigation props. diff --git a/src/libs/Navigation/getTopmostBottomTabRoute.ts b/src/libs/Navigation/getTopmostBottomTabRoute.ts deleted file mode 100644 index 48a8d80f4096..000000000000 --- a/src/libs/Navigation/getTopmostBottomTabRoute.ts +++ /dev/null @@ -1,21 +0,0 @@ -import NAVIGATORS from '@src/NAVIGATORS'; -import type {BottomTabName, NavigationPartialRoute, RootStackParamList, State} from './types'; - -function getTopmostBottomTabRoute(state: State | undefined): NavigationPartialRoute | undefined { - const bottomTabNavigatorRoute = state?.routes.findLast((route) => route.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR); - - // The bottomTabNavigatorRoute state may be empty if we just logged in. - if (!bottomTabNavigatorRoute || bottomTabNavigatorRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR || bottomTabNavigatorRoute.state === undefined) { - return undefined; - } - - const topmostBottomTabRoute = bottomTabNavigatorRoute.state.routes.at(-1); - - if (!topmostBottomTabRoute) { - throw new Error('BottomTabNavigator route have no routes.'); - } - - return {name: topmostBottomTabRoute.name as BottomTabName, params: topmostBottomTabRoute.params}; -} - -export default getTopmostBottomTabRoute; diff --git a/src/libs/Navigation/linkTo/getActionForBottomTabNavigator.ts b/src/libs/Navigation/linkTo/getActionForBottomTabNavigator.ts deleted file mode 100644 index 85580d068ad7..000000000000 --- a/src/libs/Navigation/linkTo/getActionForBottomTabNavigator.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type {NavigationAction, NavigationState} from '@react-navigation/native'; -import type {Writable} from 'type-fest'; -import type {RootStackParamList, StackNavigationAction} from '@libs/Navigation/types'; -import getTopmostBottomTabRoute from '@navigation/getTopmostBottomTabRoute'; -import CONST from '@src/CONST'; -import type {ActionPayloadParams} from './types'; - -// Because we need to change the type to push, we also need to set target for this action to the bottom tab navigator. -function getActionForBottomTabNavigator( - action: StackNavigationAction, - state: NavigationState, - policyID?: string, - shouldNavigate?: boolean, -): Writable | undefined { - const bottomTabNavigatorRoute = state.routes.at(0); - if (!bottomTabNavigatorRoute || bottomTabNavigatorRoute.state === undefined || !action || action.type !== CONST.NAVIGATION.ACTION_TYPE.NAVIGATE) { - return; - } - - const params = action.payload.params as ActionPayloadParams; - let payloadParams = params.params as Record; - const screen = params.screen; - - if (policyID && !payloadParams?.policyID) { - payloadParams = {...payloadParams, policyID}; - } else if (!policyID) { - delete payloadParams?.policyID; - } - - // Check if the current bottom tab is the same as the one we want to navigate to. If it is, we don't need to do anything. - const bottomTabCurrentTab = getTopmostBottomTabRoute(state); - const bottomTabParams = bottomTabCurrentTab?.params as Record; - - // Verify if the policyID is different than the one we are currently on. If it is, we need to navigate to the new policyID. - const isNewPolicy = bottomTabParams?.policyID !== payloadParams?.policyID; - if (bottomTabCurrentTab?.name === screen && !shouldNavigate && !isNewPolicy) { - return; - } - - return { - type: CONST.NAVIGATION.ACTION_TYPE.PUSH, - payload: { - name: screen, - params: payloadParams, - }, - target: bottomTabNavigatorRoute.state.key, - }; -} - -export default getActionForBottomTabNavigator; diff --git a/src/libs/NavigationUtils.ts b/src/libs/NavigationUtils.ts index baacf9881c36..65c0022d2bc2 100644 --- a/src/libs/NavigationUtils.ts +++ b/src/libs/NavigationUtils.ts @@ -1,7 +1,6 @@ import cloneDeep from 'lodash/cloneDeep'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -import getTopmostBottomTabRoute from './Navigation/getTopmostBottomTabRoute'; import type {CentralPaneName, FullScreenName, OnboardingFlowName, RootStackParamList, SplitNavigatorName, State} from './Navigation/types'; const SPLIT_NAVIGATORS = [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]; @@ -34,10 +33,10 @@ const ONBOARDING_SCREEN_NAMES = new Set([ const removePolicyIDParamFromState = (state: State) => { const stateCopy = cloneDeep(state); - const bottomTabRoute = getTopmostBottomTabRoute(stateCopy); - if (bottomTabRoute?.params && 'policyID' in bottomTabRoute.params) { - delete bottomTabRoute.params.policyID; - } + // const bottomTabRoute = getTopmostBottomTabRoute(stateCopy); + // if (bottomTabRoute?.params && 'policyID' in bottomTabRoute.params) { + // delete bottomTabRoute.params.policyID; + // } return stateCopy; }; diff --git a/src/pages/settings/Wallet/VerifyAccountPage.tsx b/src/pages/settings/Wallet/VerifyAccountPage.tsx index 00da9e948b88..e903d89548e8 100644 --- a/src/pages/settings/Wallet/VerifyAccountPage.tsx +++ b/src/pages/settings/Wallet/VerifyAccountPage.tsx @@ -62,7 +62,7 @@ function VerifyAccountPage({route}: VerifyAccountPageProps) { setIsValidateCodeActionModalVisible(false); if (navigateForwardTo) { - Navigation.navigate(navigateForwardTo, CONST.NAVIGATION.TYPE.UP); + Navigation.navigate(navigateForwardTo, CONST.NAVIGATION.ACTION_TYPE.REPLACE); } else { Navigation.goBack(); } diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx index 3814821f234b..172cee415e2a 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx @@ -1,3 +1,4 @@ +import {useNavigationState} from '@react-navigation/native'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import type {SectionListData} from 'react-native'; import {useOnyx} from 'react-native-onyx'; From 37203aaaf54d8ad663d5d8465ca05338eb4ae82a Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 3 Dec 2024 13:31:24 +0100 Subject: [PATCH 183/257] Remove searchRoute from PlatformStack types --- .../createResponsiveStackNavigator/index.tsx | 2 +- .../AppNavigator/createSplitStackNavigator/index.tsx | 2 +- .../index.native.tsx | 7 +++---- .../createPlatformStackNavigatorComponent/index.tsx | 8 +++----- .../types/NavigatorComponent.ts | 11 ++--------- 5 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx index 462bb315b33c..07920b5ad416 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx @@ -11,7 +11,7 @@ function useCustomRouterState({state}: CustomStateHookProps) { const lastSplitIndex = state.routes.findLastIndex((route) => isFullScreenName(route.name)); const routesToRender = state.routes.slice(Math.max(0, lastSplitIndex - 1), state.routes.length); - return {stateToRender: {...state, routes: routesToRender, index: routesToRender.length - 1}}; + return {...state, routes: routesToRender, index: routesToRender.length - 1}; } const ResponsiveStackNavigatorComponent = createPlatformStackNavigatorComponent('ResponsiveStackNavigator', { diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index 7071e85eb6ed..c86c3f5d6543 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -31,7 +31,7 @@ function useCustomSplitNavigatorState({state}: CustomStateHookProps) { const centralScreenRoutes = state.routes.slice(1); const routesToRender = shouldUseNarrowLayout ? state.routes.slice(-2) : [sidebarScreenRoute, ...centralScreenRoutes.slice(-2)]; - return {stateToRender: {...state, routes: routesToRender, index: routesToRender.length - 1}}; + return {...state, routes: routesToRender, index: routesToRender.length - 1}; } const CustomFullScreenNavigatorComponent = createPlatformStackNavigatorComponent('CustomFullScreenNavigator', { diff --git a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.native.tsx b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.native.tsx index 3794ec2d3834..b3cbf5f893ab 100644 --- a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.native.tsx +++ b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.native.tsx @@ -20,7 +20,7 @@ function createPlatformStackNavigatorComponent ({stateToRender: undefined, searchRoute: undefined})); + const useCustomState = options?.useCustomState ?? (() => undefined); const useCustomEffects = options?.useCustomEffects ?? (() => undefined); const ExtraContent = options?.ExtraContent; const NavigationContentWrapper = options?.NavigationContentWrapper; @@ -74,15 +74,14 @@ function createPlatformStackNavigatorComponent stateToRender ?? originalState, [originalState, stateToRender]); const customCodePropsWithCustomState = useMemo>>( () => ({ ...customCodeProps, state, - searchRoute, }), - [customCodeProps, state, searchRoute], + [customCodeProps, state], ); // Executes custom effects defined in "useCustomEffects" navigator option. diff --git a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx index 8cd35fdab2b7..b5235fa64321 100644 --- a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx +++ b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx @@ -19,7 +19,7 @@ function createPlatformStackNavigatorComponent, ) { const createRouter = options?.createRouter ?? StackRouter; - const useCustomState = options?.useCustomState ?? (() => ({stateToRender: undefined, searchRoute: undefined})); + const useCustomState = options?.useCustomState ?? (() => undefined); const defaultScreenOptions = options?.defaultScreenOptions; const ExtraContent = options?.ExtraContent; const NavigationContentWrapper = options?.NavigationContentWrapper; @@ -74,17 +74,15 @@ function createPlatformStackNavigatorComponent stateToRender ?? originalState, [originalState, stateToRender]); const customCodePropsWithCustomState = useMemo>>( () => ({ ...customCodeProps, state, - searchRoute, }), - [customCodeProps, state, searchRoute], + [customCodeProps, state], ); - // Executes custom effects defined in "useCustomEffects" navigator option. useCustomEffects(customCodePropsWithCustomState, parentRoute); diff --git a/src/libs/Navigation/PlatformStackNavigation/types/NavigatorComponent.ts b/src/libs/Navigation/PlatformStackNavigation/types/NavigatorComponent.ts index 5a0dd8602bc0..b4f8fc25c5f1 100644 --- a/src/libs/Navigation/PlatformStackNavigation/types/NavigatorComponent.ts +++ b/src/libs/Navigation/PlatformStackNavigation/types/NavigatorComponent.ts @@ -9,9 +9,6 @@ import type { } from '.'; import type {PlatformNavigationBuilderDescriptors, PlatformNavigationBuilderNavigation} from './NavigationBuilder'; -// Represents a route in the search context within the navigation state. -type SearchRoute = PlatformStackNavigationState['routes'][number]; - // Props that custom code receives when passed to the createPlatformStackNavigatorComponent generator function. // Custom logic like "transformState", "onWindowDimensionsChange" and custom components like "NavigationContentWrapper" and "ExtraContent" will receive these props type CustomCodeProps< @@ -24,17 +21,13 @@ type CustomCodeProps< navigation: PlatformNavigationBuilderNavigation; descriptors: PlatformNavigationBuilderDescriptors; displayName: string; - searchRoute?: SearchRoute; }; // Props for the custom state hook. type CustomStateHookProps = CustomCodeProps; -// Defines a hook function type for transforming the navigation state based on props, and returning the transformed state and search route. -type CustomStateHook = (props: CustomStateHookProps) => { - stateToRender?: PlatformStackNavigationState; - searchRoute?: SearchRoute; -}; +// Defines a hook function type for transforming the navigation state based on props, and returning the transformed state. +type CustomStateHook = (props: CustomStateHookProps) => PlatformStackNavigationState; // Props for the custom effects hook. type CustomEffectsHookProps = CustomCodeProps; From 741ce5f5c18211ddfee74b0a7f7ec4da0651f4f6 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 4 Dec 2024 17:15:16 +0100 Subject: [PATCH 184/257] Add getSplitNavigatorOptions --- .../Navigation/AppNavigator/AuthScreens.tsx | 29 +++++++++++++++++-- .../Navigators/SettingsSplitNavigator.tsx | 5 ++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index ff31c0779f30..a98a5274e012 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -1,4 +1,5 @@ import {findFocusedRoute} from '@react-navigation/native'; +import type {RouteProp} from '@react-navigation/native'; import React, {memo, useEffect, useRef, useState} from 'react'; import {NativeModules, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; @@ -23,7 +24,9 @@ import KeyboardShortcut from '@libs/KeyboardShortcut'; import Log from '@libs/Log'; import NavBarManager from '@libs/NavBarManager'; import getCurrentUrl from '@libs/Navigation/currentUrl'; +import SIDEBAR_TO_SPLIT from '@libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; +import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation'; import Presentation from '@libs/Navigation/PlatformStackNavigation/navigationOptions/presentation'; import type {AuthScreensParamList} from '@libs/Navigation/types'; import {isOnboardingFlowName} from '@libs/NavigationUtils'; @@ -365,6 +368,26 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); + // Animation is disabled when navigating to the sidebar screen + const getSplitNavigatorOptions = (route: RouteProp) => { + if (!shouldUseNarrowLayout || !route?.params) { + return rootNavigatorOptions.fullScreen; + } + + const screenName = 'screen' in route.params ? route.params.screen : undefined; + + if (!screenName) { + return rootNavigatorOptions.fullScreen; + } + + const animationEnabled = !Object.keys(SIDEBAR_TO_SPLIT).includes(screenName); + + return { + ...rootNavigatorOptions.fullScreen, + animation: animationEnabled ? Animations.SLIDE_FROM_RIGHT : Animations.NONE, + }; + }; + return ( @@ -372,12 +395,12 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie {/* This have to be the first navigator in auth screens. */} getSplitNavigatorOptions(route)} getComponent={loadReportSplitNavigator} /> getSplitNavigatorOptions(route)} getComponent={loadSettingsSplitNavigator} /> getSplitNavigatorOptions(route)} getComponent={loadWorkspaceSplitNavigator} /> Date: Wed, 4 Dec 2024 17:48:55 +0100 Subject: [PATCH 185/257] Add parentRoute to CustomCodeProps --- .../Navigators/BottomTabNavigator.tsx | 33 ------------------- .../createCustomBottomTabNavigator/index.tsx | 32 ------------------ .../useCustomState.ts | 23 ------------- .../createSplitStackNavigator/index.tsx | 6 ++-- .../usePreserveSplitNavigatorState.ts | 5 ++- .../index.native.tsx | 5 +-- .../index.tsx | 5 +-- .../types/NavigatorComponent.ts | 3 +- 8 files changed, 15 insertions(+), 97 deletions(-) delete mode 100644 src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx delete mode 100644 src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx delete mode 100644 src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/useCustomState.ts diff --git a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx deleted file mode 100644 index ce39db030b07..000000000000 --- a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import createCustomBottomTabNavigator from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator'; -import type {PlatformStackNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {BottomTabNavigatorParamList} from '@libs/Navigation/types'; -import SidebarScreen from '@pages/home/sidebar/SidebarScreen'; -import SCREENS from '@src/SCREENS'; -import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; - -const loadInitialSettingsPage = () => require('../../../../pages/settings/InitialSettingsPage').default; -const Tab = createCustomBottomTabNavigator(); - -const screenOptions: PlatformStackNavigationOptions = { - headerShown: false, -}; - -function BottomTabNavigator() { - return ( - - - - - ); -} - -BottomTabNavigator.displayName = 'BottomTabNavigator'; - -export default BottomTabNavigator; diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx deleted file mode 100644 index a4e50aeb6516..000000000000 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import type {ParamListBase} from '@react-navigation/native'; -import {createNavigatorFactory} from '@react-navigation/native'; -import React from 'react'; -import createPlatformStackNavigatorComponent from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent'; -import type {ExtraContentProps, PlatformStackNavigationEventMap, PlatformStackNavigationOptions, PlatformStackNavigationState} from '@libs/Navigation/PlatformStackNavigation/types'; -import BottomTabBar from './BottomTabBar'; -import BottomTabNavigationContentWrapper from './BottomTabNavigationContentWrapper'; -import useCustomState from './useCustomState'; - -const defaultScreenOptions: PlatformStackNavigationOptions = { - animation: 'none', -}; - -function ExtraContent({state}: ExtraContentProps) { - const selectedTab = state.routes.at(-1)?.name; - return ; -} - -const CustomBottomTabNavigatorComponent = createPlatformStackNavigatorComponent('CustomBottomTabNavigator', { - useCustomState, - defaultScreenOptions, - NavigationContentWrapper: BottomTabNavigationContentWrapper, - ExtraContent, -}); - -function createCustomBottomTabNavigator() { - return createNavigatorFactory, PlatformStackNavigationOptions, PlatformStackNavigationEventMap, typeof CustomBottomTabNavigatorComponent>( - CustomBottomTabNavigatorComponent, - )(); -} - -export default createCustomBottomTabNavigator; diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/useCustomState.ts b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/useCustomState.ts deleted file mode 100644 index cf8ffd81840f..000000000000 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/useCustomState.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {useMemo} from 'react'; -import type {CustomStateHookProps} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {NavigationStateRoute} from '@libs/Navigation/types'; -import SCREENS from '@src/SCREENS'; - -function useCustomState({state}: CustomStateHookProps) { - return useMemo(() => { - const routesToRender = [state.routes.at(-1)] as NavigationStateRoute[]; - - // We need to render at least one HOME screen to make sure everything load properly. This may be not necessary after changing how IS_SIDEBAR_LOADED is handled. - // Currently this value will be switched only after the first HOME screen is rendered. - if (routesToRender.at(0)?.name !== SCREENS.HOME) { - const routeToRender = state.routes.find((route) => route.name === SCREENS.HOME); - if (routeToRender) { - routesToRender.unshift(routeToRender); - } - } - - return {stateToRender: {...state, routes: routesToRender, index: routesToRender.length - 1}}; - }, [state]); -} - -export default useCustomState; diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx index c86c3f5d6543..629b48beaeb3 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx @@ -14,9 +14,9 @@ import type { import SplitStackRouter from './SplitStackRouter'; import usePreserveSplitNavigatorState from './usePreserveSplitNavigatorState'; -function useCustomEffects(props: CustomEffectsHookProps, route) { - useNavigationResetOnLayoutChange(props); - usePreserveSplitNavigatorState(route, props.navigation.getState()); +function useCustomEffects(props: CustomEffectsHookProps) { + useNavigationResetOnLayoutChange(); + usePreserveSplitNavigatorState(props.state, props.parentRoute); } function useCustomSplitNavigatorState({state}: CustomStateHookProps) { diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState.ts index 215f03d94a8f..789fc27d81fe 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState.ts @@ -15,8 +15,11 @@ const cleanPreservedSplitNavigatorStates = (state: NavigationState) => { const getPreservedSplitNavigatorState = (key: string) => preservedSplitNavigatorStates[key]; -function usePreserveSplitNavigatorState(route: RouteProp, state: StackNavigationState) { +function usePreserveSplitNavigatorState(state: StackNavigationState, route: RouteProp | undefined) { useEffect(() => { + if (!route) { + return; + } preservedSplitNavigatorStates[route.key] = state; }, [route, state]); } diff --git a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.native.tsx b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.native.tsx index b3cbf5f893ab..1f3b4a4c04ce 100644 --- a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.native.tsx +++ b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.native.tsx @@ -70,8 +70,9 @@ function createPlatformStackNavigatorComponent ( diff --git a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx index b5235fa64321..83af4cc9bd95 100644 --- a/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx +++ b/src/libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent/index.tsx @@ -70,8 +70,9 @@ function createPlatformStackNavigatorComponent ( diff --git a/src/libs/Navigation/PlatformStackNavigation/types/NavigatorComponent.ts b/src/libs/Navigation/PlatformStackNavigation/types/NavigatorComponent.ts index b4f8fc25c5f1..2f170b202181 100644 --- a/src/libs/Navigation/PlatformStackNavigation/types/NavigatorComponent.ts +++ b/src/libs/Navigation/PlatformStackNavigation/types/NavigatorComponent.ts @@ -1,4 +1,4 @@ -import type {EventMapBase, ParamListBase, StackActionHelpers} from '@react-navigation/native'; +import type {EventMapBase, ParamListBase, RouteProp, StackActionHelpers} from '@react-navigation/native'; import type { PlatformSpecificEventMap, PlatformSpecificNavigationOptions, @@ -21,6 +21,7 @@ type CustomCodeProps< navigation: PlatformNavigationBuilderNavigation; descriptors: PlatformNavigationBuilderDescriptors; displayName: string; + parentRoute?: RouteProp; }; // Props for the custom state hook. From 861f87aaefa1b5b4b73a027029750c08bb26a3f6 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 4 Dec 2024 18:15:45 +0100 Subject: [PATCH 186/257] Fix lint --- src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts | 2 +- src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index decb1ae483d3..4108a12b7253 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -2,7 +2,7 @@ import type {NavigationState, PartialState, Route} from '@react-navigation/nativ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import pick from 'lodash/pick'; import {isAnonymousUser} from '@libs/actions/Session'; -import type {NavigationPartialRoute, RootStackParamList, SettingsSplitNavigatorParamList, WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; +import type {NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; import {isFullScreenName} from '@libs/NavigationUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx index 40ce2e8d46a3..e7b7725815c0 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx @@ -10,7 +10,6 @@ import {updateLastAccessedWorkspace} from '@libs/actions/Policy/Policy'; import * as Browser from '@libs/Browser'; import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import TopBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar'; -import Navigation from '@libs/Navigation/Navigation'; import Performance from '@libs/Performance'; import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import Timing from '@userActions/Timing'; From 93fa76d3ba1c26c98be65ccf096bd597fbae5788 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 25 Nov 2024 10:34:54 +0100 Subject: [PATCH 187/257] Remove BOTTOM_TAB, cleanup code related to SplitNavigators --- src/NAVIGATORS.ts | 1 - src/SCREENS.ts | 1 - .../FocusTrap/BOTTOM_TAB_SCREENS.ts | 6 -- .../FocusTrapForScreen/index.web.tsx | 4 +- .../FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts | 2 - .../MentionReportRenderer/index.tsx | 11 +-- src/components/PromotedActionsBar.tsx | 9 +-- .../ScrollOffsetContextProvider.tsx | 15 ++-- .../BottomTabBar.tsx | 2 +- .../BottomTabNavigationContentWrapper.tsx | 22 ------ src/libs/Navigation/Navigation.ts | 20 ++--- .../Navigation/getTopmostCentralPaneRoute.ts | 19 ----- .../Navigation/getTopmostReportActionID.ts | 39 ---------- ...stReportId.ts => getTopmostReportParam.ts} | 15 ++-- .../Navigation/getTopmostWorkspaceRoute.ts | 28 ------- .../isSearchTopmostFullScreenRoute.ts | 2 +- .../linkingConfig/RELATIONS/index.ts | 1 + src/libs/Navigation/linkingConfig/config.ts | 2 - .../linkingConfig/customGetPathFromState.ts | 7 +- .../shouldSetScreenBlurred/index.tsx | 13 ---- src/libs/Navigation/types.ts | 10 --- src/libs/NavigationUtils.ts | 73 ++++++------------- .../FloatingActionButtonAndPopover.tsx | 14 +--- 23 files changed, 58 insertions(+), 258 deletions(-) delete mode 100644 src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts delete mode 100644 src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabNavigationContentWrapper.tsx delete mode 100644 src/libs/Navigation/getTopmostCentralPaneRoute.ts delete mode 100644 src/libs/Navigation/getTopmostReportActionID.ts rename src/libs/Navigation/{getTopmostReportId.ts => getTopmostReportParam.ts} (68%) delete mode 100644 src/libs/Navigation/getTopmostWorkspaceRoute.ts delete mode 100644 src/libs/Navigation/shouldSetScreenBlurred/index.tsx diff --git a/src/NAVIGATORS.ts b/src/NAVIGATORS.ts index c6f014f24e72..7695a42a9501 100644 --- a/src/NAVIGATORS.ts +++ b/src/NAVIGATORS.ts @@ -4,7 +4,6 @@ * */ export default { CENTRAL_PANE_NAVIGATOR: 'CentralPaneNavigator', - BOTTOM_TAB_NAVIGATOR: 'BottomTabNavigator', LEFT_MODAL_NAVIGATOR: 'LeftModalNavigator', RIGHT_MODAL_NAVIGATOR: 'RightModalNavigator', ONBOARDING_MODAL_NAVIGATOR: 'OnboardingModalNavigator', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index e4fa03bf4815..4913869e3e23 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -49,7 +49,6 @@ const SCREENS = { SAVED_SEARCH_RENAME_RHP: 'Search_Saved_Search_Rename_RHP', ADVANCED_FILTERS_IN_RHP: 'Search_Advanced_Filters_In_RHP', TRANSACTION_HOLD_REASON_RHP: 'Search_Transaction_Hold_Reason_RHP', - BOTTOM_TAB: 'Search_Bottom_Tab', }, SETTINGS: { ROOT: 'Settings_Root', diff --git a/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts b/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts deleted file mode 100644 index f6a4f5ba6e83..000000000000 --- a/src/components/FocusTrap/BOTTOM_TAB_SCREENS.ts +++ /dev/null @@ -1,6 +0,0 @@ -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; - -const BOTTOM_TAB_SCREENS = [SCREENS.HOME, SCREENS.SETTINGS.ROOT, NAVIGATORS.BOTTOM_TAB_NAVIGATOR, SCREENS.SEARCH.BOTTOM_TAB]; - -export default BOTTOM_TAB_SCREENS; diff --git a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx index 14f14aee8c73..62a6b5d100a8 100644 --- a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx +++ b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx @@ -1,11 +1,11 @@ import {useIsFocused, useRoute} from '@react-navigation/native'; import FocusTrap from 'focus-trap-react'; import React, {useMemo} from 'react'; -import BOTTOM_TAB_SCREENS from '@components/FocusTrap/BOTTOM_TAB_SCREENS'; import sharedTrapStack from '@components/FocusTrap/sharedTrapStack'; import TOP_TAB_SCREENS from '@components/FocusTrap/TOP_TAB_SCREENS'; import WIDE_LAYOUT_INACTIVE_SCREENS from '@components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import {isSidebarScreenName} from '@libs/NavigationUtils'; import CONST from '@src/CONST'; import type FocusTrapProps from './FocusTrapProps'; @@ -19,7 +19,7 @@ function FocusTrapForScreen({children, focusTrapSettings}: FocusTrapProps) { return focusTrapSettings.active; } // Focus trap can't be active on bottom tab screens because it would block access to the tab bar. - if (BOTTOM_TAB_SCREENS.find((screen) => screen === route.name)) { + if (isSidebarScreenName(route.name)) { return false; } diff --git a/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts b/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts index 32e063f03109..b98809a14f7c 100644 --- a/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts +++ b/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts @@ -1,4 +1,3 @@ -import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; /** @@ -6,7 +5,6 @@ import SCREENS from '@src/SCREENS'; * focus trap when rendered on a wide screen to allow navigation between them using the keyboard */ const WIDE_LAYOUT_INACTIVE_SCREENS: string[] = [ - NAVIGATORS.BOTTOM_TAB_NAVIGATOR, SCREENS.HOME, SCREENS.SETTINGS.ROOT, SCREENS.REPORT, diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx index 89a9fb21d48f..5b05bae39a37 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx @@ -10,14 +10,12 @@ import Text from '@components/Text'; import useCurrentReportID from '@hooks/useCurrentReportID'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; -import Navigation, {navigationRef} from '@navigation/Navigation'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/isSearchTopmostFullScreenRoute'; +import Navigation from '@navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; import type {Route} from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; +import ROUTES from '@src/ROUTES'; import type {Report} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import MentionReportContext from './MentionReportContext'; @@ -74,9 +72,8 @@ function MentionReportRenderer({style, tnode, TDefaultRenderer, ...defaultRender const {reportID, mentionDisplayText} = mentionDetails; let navigationRoute: Route | undefined = reportID ? ROUTES.REPORT_WITH_ID.getRoute(reportID) : undefined; - const topmostCentralPaneRoute = getTopmostCentralPaneRoute(navigationRef.getRootState() as State); const backTo = Navigation.getActiveRoute(); - if (topmostCentralPaneRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { + if (isSearchTopmostFullScreenRoute()) { navigationRoute = reportID ? ROUTES.SEARCH_REPORT.getRoute({reportID, backTo}) : undefined; } const isCurrentRoomMention = reportID === currentReportIDValue; diff --git a/src/components/PromotedActionsBar.tsx b/src/components/PromotedActionsBar.tsx index e6ce3080ee0a..b1a515097ebb 100644 --- a/src/components/PromotedActionsBar.tsx +++ b/src/components/PromotedActionsBar.tsx @@ -5,15 +5,13 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as HeaderUtils from '@libs/HeaderUtils'; import * as Localize from '@libs/Localize'; -import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; -import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/isSearchTopmostFullScreenRoute'; +import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as ReportActions from '@userActions/Report'; import * as Session from '@userActions/Session'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; import type {ReportAction} from '@src/types/onyx'; import type OnyxReport from '@src/types/onyx/Report'; import Button from './Button'; @@ -93,9 +91,8 @@ const PromotedActions = { Navigation.goBack(); } const targetedReportID = reportID ?? reportAction?.childReportID ?? ''; - const topmostCentralPaneRoute = getTopmostCentralPaneRoute(navigationRef.getRootState() as State); - if (topmostCentralPaneRoute?.name !== SCREENS.SEARCH.CENTRAL_PANE && isTextHold) { + if (isSearchTopmostFullScreenRoute() && isTextHold) { ReportUtils.changeMoneyRequestHoldStatus(reportAction, ROUTES.REPORT_WITH_ID.getRoute(targetedReportID)); return; } diff --git a/src/components/ScrollOffsetContextProvider.tsx b/src/components/ScrollOffsetContextProvider.tsx index 78d8c5ed61fb..f5573fd6b2e4 100644 --- a/src/components/ScrollOffsetContextProvider.tsx +++ b/src/components/ScrollOffsetContextProvider.tsx @@ -4,7 +4,7 @@ import {withOnyx} from 'react-native-onyx'; import usePrevious from '@hooks/usePrevious'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {NavigationPartialRoute, State} from '@libs/Navigation/types'; -import NAVIGATORS from '@src/NAVIGATORS'; +import {isSidebarScreenName} from '@libs/NavigationUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import SCREENS from '@src/SCREENS'; import type {PriorityMode} from '@src/types/onyx'; @@ -75,14 +75,11 @@ function ScrollOffsetContextProvider({children, priorityMode}: ScrollOffsetConte }, []); const cleanStaleScrollOffsets: ScrollOffsetContextValue['cleanStaleScrollOffsets'] = useCallback((state) => { - const bottomTabNavigator = state.routes.find((route) => route.name === NAVIGATORS.BOTTOM_TAB_NAVIGATOR); - if (bottomTabNavigator?.state && 'routes' in bottomTabNavigator.state) { - const bottomTabNavigatorRoutes = bottomTabNavigator.state.routes; - const scrollOffsetkeysOfExistingScreens = bottomTabNavigatorRoutes.map((route) => getKey(route)); - for (const key of Object.keys(scrollOffsetsRef.current)) { - if (!scrollOffsetkeysOfExistingScreens.includes(key)) { - delete scrollOffsetsRef.current[key]; - } + const sidebarRoutes = state.routes.filter((route) => isSidebarScreenName(route.name)); + const scrollOffsetkeysOfExistingScreens = sidebarRoutes.map((route) => getKey(route)); + for (const key of Object.keys(scrollOffsetsRef.current)) { + if (!scrollOffsetkeysOfExistingScreens.includes(key)) { + delete scrollOffsetsRef.current[key]; } } }, []); diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index a3ed832a8d06..6ad404d6fddd 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -92,7 +92,7 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { }, [selectedTab]); const navigateToSearch = useCallback(() => { - if (selectedTab === SCREENS.SEARCH.BOTTOM_TAB) { + if (selectedTab === SCREENS.SEARCH.CENTRAL_PANE) { return; } interceptAnonymousUser(() => { diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabNavigationContentWrapper.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabNavigationContentWrapper.tsx deleted file mode 100644 index dd93a6df7b1e..000000000000 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabNavigationContentWrapper.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import {View} from 'react-native'; -import ScreenWrapper from '@components/ScreenWrapper'; -import useThemeStyles from '@hooks/useThemeStyles'; -import type {NavigationContentWrapperProps} from '@libs/Navigation/PlatformStackNavigation/types'; - -function BottomTabNavigationContentWrapper({children, displayName}: NavigationContentWrapperProps) { - const styles = useThemeStyles(); - - return ( - - {children} - - ); -} - -export default BottomTabNavigationContentWrapper; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index f816085f5325..4ef2cbb6255f 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -17,29 +17,23 @@ import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import type {HybridAppRoute, Route} from '@src/ROUTES'; import ROUTES, {HYBRID_APP_ROUTES} from '@src/ROUTES'; -import SCREENS, {PROTECTED_SCREENS} from '@src/SCREENS'; import type {Screen} from '@src/SCREENS'; +import SCREENS, {PROTECTED_SCREENS} from '@src/SCREENS'; import type {Report} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import originalCloseRHPFlow from './closeRHPFlow'; import getPolicyIDFromState from './getPolicyIDFromState'; import getStateFromPath from './getStateFromPath'; -import originalGetTopmostReportActionId from './getTopmostReportActionID'; -import originalGetTopmostReportId from './getTopmostReportId'; +import getTopmostReportParam from './getTopmostReportParam'; import isReportOpenInRHP from './isReportOpenInRHP'; import linkingConfig from './linkingConfig'; import createSplitNavigator from './linkingConfig/createSplitNavigator'; +import RELATIONS from './linkingConfig/RELATIONS'; import linkTo from './linkTo'; import getMinimalAction from './linkTo/getMinimalAction'; import navigationRef from './navigationRef'; import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; -import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, SplitNavigatorLHNScreen, SplitNavigatorParamListType, State} from './types'; - -const SPLIT_NAVIGATOR_TO_SIDEBAR_MAP: Record = { - [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: SCREENS.HOME, - [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: SCREENS.SETTINGS.ROOT, - [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: SCREENS.WORKSPACE.INITIAL, -}; +import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, State} from './types'; function getSidebarScreenParams(splitNavigatorRoute: NavigationStateRoute) { if (splitNavigatorRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { @@ -74,10 +68,10 @@ function canNavigate(methodName: string, params: Record = {}): } // Re-exporting the getTopmostReportId here to fill in default value for state. The getTopmostReportId isn't defined in this file to avoid cyclic dependencies. -const getTopmostReportId = (state = navigationRef.getState()) => originalGetTopmostReportId(state); +const getTopmostReportId = (state = navigationRef.getState()) => getTopmostReportParam(state, 'reportID'); // Re-exporting the getTopmostReportActionID here to fill in default value for state. The getTopmostReportActionID isn't defined in this file to avoid cyclic dependencies. -const getTopmostReportActionId = (state = navigationRef.getState()) => originalGetTopmostReportActionId(state); +const getTopmostReportActionId = (state = navigationRef.getState()) => getTopmostReportParam(state, 'reportActionID'); // Re-exporting the closeRHPFlow here to fill in default value for navigationRef. The closeRHPFlow isn't defined in this file to avoid cyclic dependencies. const closeRHPFlow = (ref = navigationRef) => originalCloseRHPFlow(ref); @@ -282,7 +276,7 @@ function goBack(fallbackRoute?: Route, shouldPopToTop = false) { const canGoBack = navigationRef.current?.canGoBack(); if (!canGoBack && isSplitNavigatorName(lastRoute?.name) && lastRoute?.state?.routes?.length === 1) { - const name = SPLIT_NAVIGATOR_TO_SIDEBAR_MAP[lastRoute.name]; + const name = RELATIONS.SPLIT_TO_SIDEBAR[lastRoute.name]; const params = getSidebarScreenParams(lastRoute); navigationRef.dispatch({ type: 'REPLACE', diff --git a/src/libs/Navigation/getTopmostCentralPaneRoute.ts b/src/libs/Navigation/getTopmostCentralPaneRoute.ts deleted file mode 100644 index 5ac72281eaf6..000000000000 --- a/src/libs/Navigation/getTopmostCentralPaneRoute.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {isCentralPaneName} from '@libs/NavigationUtils'; -import type {CentralPaneName, NavigationPartialRoute, RootStackParamList, State} from './types'; - -// Get the name of topmost central pane route in the navigation stack. -function getTopmostCentralPaneRoute(state: State): NavigationPartialRoute | undefined { - if (!state) { - return; - } - - const topmostCentralPane = state.routes.filter((route) => isCentralPaneName(route.name)).at(-1); - - if (!topmostCentralPane) { - return; - } - - return topmostCentralPane as NavigationPartialRoute; -} - -export default getTopmostCentralPaneRoute; diff --git a/src/libs/Navigation/getTopmostReportActionID.ts b/src/libs/Navigation/getTopmostReportActionID.ts deleted file mode 100644 index b789d45cc9a6..000000000000 --- a/src/libs/Navigation/getTopmostReportActionID.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type {NavigationState, PartialState} from '@react-navigation/native'; -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; -import type {RootStackParamList} from './types'; - -// This function is in a separate file than Navigation.ts to avoid cyclic dependency. - -/** - * Find the last visited report screen in the navigation state and get the linked reportActionID of it. - * - * @param state - The react-navigation state - * @returns - It's possible that there is no report screen - */ -function getTopmostReportActionID(state: NavigationState | NavigationState | PartialState): string | undefined { - if (!state) { - return; - } - - const topmostReportsSplitNavigator = state.routes.filter((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR).at(-1); - if (!topmostReportsSplitNavigator?.state) { - return; - } - - const topmostReport = topmostReportsSplitNavigator.state?.routes.filter((route) => route.name === SCREENS.REPORT).at(-1); - - if (!topmostReport || !topmostReport?.params) { - return; - } - - const reportActionID = 'reportActionID' in topmostReport.params && topmostReport.params.reportActionID; - - if (typeof reportActionID !== 'string') { - return; - } - - return reportActionID; -} - -export default getTopmostReportActionID; diff --git a/src/libs/Navigation/getTopmostReportId.ts b/src/libs/Navigation/getTopmostReportParam.ts similarity index 68% rename from src/libs/Navigation/getTopmostReportId.ts rename to src/libs/Navigation/getTopmostReportParam.ts index 0969f46b6b5d..30354c7c6dd0 100644 --- a/src/libs/Navigation/getTopmostReportId.ts +++ b/src/libs/Navigation/getTopmostReportParam.ts @@ -11,7 +11,11 @@ import type {RootStackParamList} from './types'; * @param state - The react-navigation state * @returns - It's possible that there is no report screen */ -function getTopmostReportId(state: NavigationState | NavigationState | PartialState): string | undefined { + +type State = NavigationState | NavigationState | PartialState; +type ReportParam = 'reportID' | 'reportActionID'; + +function getTopmostReportParam(state: State, reportParam: ReportParam): string | undefined { if (!state) { return; } @@ -28,12 +32,9 @@ function getTopmostReportId(state: NavigationState | NavigationState; - return topmostReportId; + return topmostReportParams?.[reportParam]; } -export default getTopmostReportId; +export default getTopmostReportParam; diff --git a/src/libs/Navigation/getTopmostWorkspaceRoute.ts b/src/libs/Navigation/getTopmostWorkspaceRoute.ts deleted file mode 100644 index 04e1237643dd..000000000000 --- a/src/libs/Navigation/getTopmostWorkspaceRoute.ts +++ /dev/null @@ -1,28 +0,0 @@ -import NAVIGATORS from '@src/NAVIGATORS'; -import type {NavigationPartialRoute, RootStackParamList, State, WorkspaceScreenName} from './types'; - -// Get the name of topmost workspace navigator route in the navigation stack. -function getTopmostWorkspaceRoute(state: State): NavigationPartialRoute | undefined { - if (!state) { - return; - } - - const topmostWorkspaceRoute = state.routes.filter((route) => route.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR).at(-1); - - if (!topmostWorkspaceRoute) { - return; - } - - if (topmostWorkspaceRoute.state) { - // There will be at least one route in the workspace navigator. - const {name, params} = topmostWorkspaceRoute.state.routes.at(-1) as NavigationPartialRoute; - - return {name, params}; - } - - if (!!topmostWorkspaceRoute.params && 'screen' in topmostWorkspaceRoute.params) { - return {name: topmostWorkspaceRoute.params.screen as WorkspaceScreenName, params: topmostWorkspaceRoute.params.params}; - } -} - -export default getTopmostWorkspaceRoute; diff --git a/src/libs/Navigation/isSearchTopmostFullScreenRoute.ts b/src/libs/Navigation/isSearchTopmostFullScreenRoute.ts index eaae1f807489..5599ec650c14 100644 --- a/src/libs/Navigation/isSearchTopmostFullScreenRoute.ts +++ b/src/libs/Navigation/isSearchTopmostFullScreenRoute.ts @@ -10,7 +10,7 @@ const isSearchTopmostFullScreenRoute = (): boolean => { return false; } - return rootState.routes.filter((route) => isFullScreenName(route.name)).at(-1)?.name === SCREENS.SEARCH.CENTRAL_PANE; + return rootState.routes.findLast((route) => isFullScreenName(route.name))?.name === SCREENS.SEARCH.CENTRAL_PANE; }; export default isSearchTopmostFullScreenRoute; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/index.ts b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts index 90865784f68c..3c4c9140d2d8 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/index.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts @@ -25,4 +25,5 @@ export default { SIDEBAR_TO_RHP, WORKSPACE_TO_RHP, SIDEBAR_TO_SPLIT, + SPLIT_TO_SIDEBAR: createInverseRelation(SIDEBAR_TO_RHP), }; diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 677765b0879e..b8546716d96f 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -9,8 +9,6 @@ import createNormalizedConfigs from './createNormalizedConfigs'; // Moved to a separate file to avoid cyclic dependencies. const config: LinkingOptions['config'] = { - // initialRouteName: NAVIGATORS.BOTTOM_TAB_NAVIGATOR, - // initialRouteName: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, screens: { // Main Routes [SCREENS.VALIDATE_LOGIN]: ROUTES.VALIDATE_LOGIN, diff --git a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts index 9ffdcae2224b..8954e48955f8 100644 --- a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts +++ b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts @@ -1,12 +1,9 @@ import {getPathFromState} from '@react-navigation/native'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; -import {isFullScreenName, removePolicyIDParamFromState} from '@libs/NavigationUtils'; +import {isFullScreenName} from '@libs/NavigationUtils'; import NAVIGATORS from '@src/NAVIGATORS'; const customGetPathFromState: typeof getPathFromState = (state, options) => { - // For the Home page we should remove policyID from the params, because on small screens it's displayed twice in the URL - const stateWithoutPolicyID = removePolicyIDParamFromState(state as State); - const path = getPathFromState(stateWithoutPolicyID, options); + const path = getPathFromState(state, options); const fullScreenRoute = state.routes.findLast((route) => isFullScreenName(route.name)); const shouldAddPolicyID = fullScreenRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; diff --git a/src/libs/Navigation/shouldSetScreenBlurred/index.tsx b/src/libs/Navigation/shouldSetScreenBlurred/index.tsx deleted file mode 100644 index 2461187046d8..000000000000 --- a/src/libs/Navigation/shouldSetScreenBlurred/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -/** - * @param navigationIndex - * - * Decides whether to set screen to blurred state. - * - * Allow freezing the first screen and more in the stack only on - * web and desktop platforms. The reason is that in the case of - * LHN, we have FlashList rendering in the back while we are on - * Settings screen. - */ -const shouldSetScreenBlurred = (navigationIndex: number) => navigationIndex > 1; - -export default shouldSetScreenBlurred; diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 569fba200f44..304aa93c13f0 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1569,12 +1569,6 @@ type ExplanationModalNavigatorParamList = { [SCREENS.EXPLANATION_MODAL.ROOT]: undefined; }; -type BottomTabNavigatorParamList = { - [SCREENS.HOME]: {policyID?: string}; - [SCREENS.SEARCH.BOTTOM_TAB]: undefined; - [SCREENS.SETTINGS.ROOT]: {policyID?: string}; -}; - type SharedScreensParamList = { [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: NavigatorScreenParams; [SCREENS.TRANSITION_BETWEEN_APPS]: { @@ -1729,8 +1723,6 @@ type DebugParamList = { type RootStackParamList = PublicScreensParamList & AuthScreensParamList & LeftModalNavigatorParamList; -type BottomTabName = keyof BottomTabNavigatorParamList; - type WorkspaceScreenName = keyof WorkspaceSplitNavigatorParamList; type CentralPaneName = keyof CentralPaneScreensParamList; @@ -1764,8 +1756,6 @@ export type { CentralPaneName, BackToParams, BackToAndForwardToParms, - BottomTabName, - BottomTabNavigatorParamList, DetailsNavigatorParamList, EditRequestNavigatorParamList, EnablePaymentsNavigatorParamList, diff --git a/src/libs/NavigationUtils.ts b/src/libs/NavigationUtils.ts index 65c0022d2bc2..139694afcfe6 100644 --- a/src/libs/NavigationUtils.ts +++ b/src/libs/NavigationUtils.ts @@ -1,74 +1,45 @@ -import cloneDeep from 'lodash/cloneDeep'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -import type {CentralPaneName, FullScreenName, OnboardingFlowName, RootStackParamList, SplitNavigatorName, State} from './Navigation/types'; +import type {FullScreenName, OnboardingFlowName, SplitNavigatorLHNScreen, SplitNavigatorName} from './Navigation/types'; const SPLIT_NAVIGATORS = [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]; - -const SPLIT_NAVIGATORS_SET = new Set(SPLIT_NAVIGATORS); - -const FULL_SCREEN_ROUTES_SET = new Set([...SPLIT_NAVIGATORS, SCREENS.SEARCH.CENTRAL_PANE]); - -const CENTRAL_PANE_SCREEN_NAMES = new Set([ - SCREENS.SETTINGS.WORKSPACES, - SCREENS.SETTINGS.PREFERENCES.ROOT, - SCREENS.SETTINGS.SECURITY, - SCREENS.SETTINGS.PROFILE.ROOT, - SCREENS.SETTINGS.WALLET.ROOT, - SCREENS.SETTINGS.ABOUT, - SCREENS.SETTINGS.TROUBLESHOOT, - SCREENS.SETTINGS.SAVE_THE_WORLD, - SCREENS.SETTINGS.SUBSCRIPTION.ROOT, - SCREENS.SEARCH.CENTRAL_PANE, - SCREENS.REPORT, -]); - -const ONBOARDING_SCREEN_NAMES = new Set([ +const FULL_SCREENS = [...SPLIT_NAVIGATORS, SCREENS.SEARCH.CENTRAL_PANE]; +const SIDEBARS = [SCREENS.HOME, SCREENS.SETTINGS.ROOT, SCREENS.WORKSPACE.INITIAL]; +const ONBOARDING_SCREENS = [ SCREENS.ONBOARDING.PERSONAL_DETAILS, SCREENS.ONBOARDING.PURPOSE, SCREENS.ONBOARDING_MODAL.ONBOARDING, SCREENS.ONBOARDING.EMPLOYEES, SCREENS.ONBOARDING.ACCOUNTING, -]); +]; -const removePolicyIDParamFromState = (state: State) => { - const stateCopy = cloneDeep(state); - // const bottomTabRoute = getTopmostBottomTabRoute(stateCopy); - // if (bottomTabRoute?.params && 'policyID' in bottomTabRoute.params) { - // delete bottomTabRoute.params.policyID; - // } - return stateCopy; -}; - -function isCentralPaneName(screen: string | undefined): screen is CentralPaneName { - if (!screen) { - return false; - } - return CENTRAL_PANE_SCREEN_NAMES.has(screen as CentralPaneName); -} +const SPLIT_NAVIGATORS_SET = new Set(SPLIT_NAVIGATORS); +const FULL_SCREENS_SET = new Set(FULL_SCREENS); +const SIDEBARS_SET = new Set(SIDEBARS); +const ONBOARDING_SCREENS_SET = new Set(ONBOARDING_SCREENS); -function isOnboardingFlowName(screen: string | undefined): screen is OnboardingFlowName { +function checkIsScreenHasMatchingNameToSetValues(screen: string | undefined, set: Set): screen is T { if (!screen) { return false; } - return ONBOARDING_SCREEN_NAMES.has(screen as OnboardingFlowName); + return set.has(screen as T); } -function isSplitNavigatorName(screen: string | undefined): screen is SplitNavigatorName { - if (!screen) { - return false; - } +function isOnboardingFlowName(screen: string | undefined) { + return checkIsScreenHasMatchingNameToSetValues(screen, ONBOARDING_SCREENS_SET); +} - return SPLIT_NAVIGATORS_SET.has(screen as SplitNavigatorName); +function isSplitNavigatorName(screen: string | undefined) { + return checkIsScreenHasMatchingNameToSetValues(screen, SPLIT_NAVIGATORS_SET); } -function isFullScreenName(screen: string | undefined): screen is FullScreenName { - if (!screen) { - return false; - } +function isFullScreenName(screen: string | undefined) { + return checkIsScreenHasMatchingNameToSetValues(screen, FULL_SCREENS_SET); +} - return FULL_SCREEN_ROUTES_SET.has(screen as FullScreenName); +function isSidebarScreenName(screen: string | undefined) { + return checkIsScreenHasMatchingNameToSetValues(screen, SIDEBARS_SET); } -export {isCentralPaneName, isFullScreenName, isOnboardingFlowName, isSplitNavigatorName, removePolicyIDParamFromState}; +export {isFullScreenName, isOnboardingFlowName, isSidebarScreenName, isSplitNavigatorName}; diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx index f0e8d2ba1781..bfc3fad7a71f 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx @@ -1,4 +1,4 @@ -import {useIsFocused as useIsFocusedOriginal, useNavigationState} from '@react-navigation/native'; +import {useIsFocused} from '@react-navigation/native'; import type {ImageContentFit} from 'expo-image'; import type {ForwardedRef} from 'react'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; @@ -23,9 +23,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import getIconForAction from '@libs/getIconForAction'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; -import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute'; import Navigation from '@libs/Navigation/Navigation'; -import type {CentralPaneName, NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; import {hasSeenTourSelector} from '@libs/onboardingSelectors'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -43,21 +41,11 @@ import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import type {QuickActionName} from '@src/types/onyx/QuickAction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import mapOnyxCollectionItems from '@src/utils/mapOnyxCollectionItems'; -// On small screen we hide the search page from central pane to show the search bottom tab page with bottom tab bar. -// We need to take this in consideration when checking if the screen is focused. -const useIsFocused = () => { - const {shouldUseNarrowLayout} = useResponsiveLayout(); - const isFocused = useIsFocusedOriginal(); - const topmostCentralPane = useNavigationState | undefined>(getTopmostCentralPaneRoute); - return isFocused || (topmostCentralPane?.name === SCREENS.SEARCH.CENTRAL_PANE && shouldUseNarrowLayout); -}; - type PolicySelector = Pick; type FloatingActionButtonAndPopoverProps = { From 4ace213f360295f972480a7d316c4f88af1d8b36 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 25 Nov 2024 11:01:02 +0100 Subject: [PATCH 188/257] Cleanup config.ts --- src/libs/Navigation/linkingConfig/config.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index b8546716d96f..3be3be9d15ec 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -60,18 +60,6 @@ const config: LinkingOptions['config'] = { // [SCREENS.SETTINGS.SAVE_THE_WORLD]: ROUTES.SETTINGS_SAVE_THE_WORLD, // [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: ROUTES.SETTINGS_SUBSCRIPTION, - // Sidebar - // [NAVIGATORS.BOTTOM_TAB_NAVIGATOR]: { - // path: ROUTES.ROOT, - // initialRouteName: SCREENS.HOME, - // screens: { - // [SCREENS.HOME]: ROUTES.HOME, - // // [SCREENS.SETTINGS.ROOT]: { - // // path: ROUTES.SETTINGS, - // // }, - // }, - // }, - [SCREENS.NOT_FOUND]: '*', [NAVIGATORS.LEFT_MODAL_NAVIGATOR]: { screens: { From fd99fa881d035834e52698e6bd49ec6895df8cc1 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 25 Nov 2024 13:08:39 +0100 Subject: [PATCH 189/257] Remove subscribe --- src/libs/Navigation/linkingConfig/index.ts | 2 - .../linkingConfig/subscribe/index.native.ts | 40 ------------------- .../linkingConfig/subscribe/index.ts | 7 ---- 3 files changed, 49 deletions(-) delete mode 100644 src/libs/Navigation/linkingConfig/subscribe/index.native.ts delete mode 100644 src/libs/Navigation/linkingConfig/subscribe/index.ts diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index 1f556aa67809..3e958d593ec9 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -5,7 +5,6 @@ import config from './config'; import customGetPathFromState from './customGetPathFromState'; import getAdaptedStateFromPath from './getAdaptedStateFromPath'; import prefixes from './prefixes'; -import subscribe from './subscribe'; const linkingConfig: LinkingOptions = { getStateFromPath: (...args) => { @@ -14,7 +13,6 @@ const linkingConfig: LinkingOptions = { // ResultState | undefined is the type this function expect. return adaptedState; }, - subscribe, getPathFromState: customGetPathFromState, prefixes, config, diff --git a/src/libs/Navigation/linkingConfig/subscribe/index.native.ts b/src/libs/Navigation/linkingConfig/subscribe/index.native.ts deleted file mode 100644 index 46720e9884e9..000000000000 --- a/src/libs/Navigation/linkingConfig/subscribe/index.native.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import type {LinkingOptions} from '@react-navigation/native'; -import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; -import extractPathFromURL from '@react-navigation/native/src/extractPathFromURL'; -import {Linking} from 'react-native'; -import Navigation from '@libs/Navigation/Navigation'; -import config from '@navigation/linkingConfig/config'; -import prefixes from '@navigation/linkingConfig/prefixes'; -import type {RootStackParamList} from '@navigation/types'; -import type {Route} from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; - -// This field in linkingConfig is supported on native only. -const subscribe: LinkingOptions['subscribe'] = (listener) => { - // We need to override the default behaviour for the deep link to search screen. - // Even on mobile narrow layout, this screen need to push two screens on the stack to work (bottom tab and central pane). - // That's why we are going to handle it with our navigate function instead the default react-navigation one. - const linkingSubscription = Linking.addEventListener('url', ({url}) => { - const path = extractPathFromURL(prefixes, url); - - if (path) { - const stateFromPath = getStateFromPath(path, config); - if (stateFromPath) { - const focusedRoute = findFocusedRoute(stateFromPath); - if (focusedRoute && focusedRoute.name === SCREENS.SEARCH.CENTRAL_PANE) { - Navigation.navigate(path as Route); - return; - } - } - } - - listener(url); - }); - return () => { - // Clean up the event listeners - linkingSubscription.remove(); - }; -}; - -export default subscribe; diff --git a/src/libs/Navigation/linkingConfig/subscribe/index.ts b/src/libs/Navigation/linkingConfig/subscribe/index.ts deleted file mode 100644 index 74ef4133cb55..000000000000 --- a/src/libs/Navigation/linkingConfig/subscribe/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type {LinkingOptions} from '@react-navigation/native'; -import type {RootStackParamList} from '@libs/Navigation/types'; - -// This field in linkingConfig is supported on native only. -const subscribe: LinkingOptions['subscribe'] = undefined; - -export default subscribe; From d54df17da16b1527fc37a1850050a95b681cfaf6 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 25 Nov 2024 14:21:27 +0100 Subject: [PATCH 190/257] Remove Navigation.removeScreenFromNavigationState --- src/libs/Navigation/Navigation.ts | 16 ---------------- src/pages/workspace/AccessOrNotFoundWrapper.tsx | 9 --------- 2 files changed, 25 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 4ef2cbb6255f..8013eb6c20c3 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -17,7 +17,6 @@ import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import type {HybridAppRoute, Route} from '@src/ROUTES'; import ROUTES, {HYBRID_APP_ROUTES} from '@src/ROUTES'; -import type {Screen} from '@src/SCREENS'; import SCREENS, {PROTECTED_SCREENS} from '@src/SCREENS'; import type {Report} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -461,20 +460,6 @@ const dismissModalWithReport = (report: OnyxEntry) => { isNavigationReady().then(() => navigateToReportWithPolicyCheck({report})); }; -function removeScreenFromNavigationState(screen: Screen) { - isNavigationReady().then(() => { - navigationRef.dispatch((state) => { - const routes = state.routes?.filter((item) => item.name !== screen); - - return CommonActions.reset({ - ...state, - routes, - index: routes.length < state.routes.length ? state.index - 1 : state.index, - }); - }); - }); -} - export default { setShouldPopAllStateOnUP, navigate, @@ -499,7 +484,6 @@ export default { setNavigationActionToMicrotaskQueue, navigateToReportWithPolicyCheck, goUp, - removeScreenFromNavigationState, }; export {navigationRef}; diff --git a/src/pages/workspace/AccessOrNotFoundWrapper.tsx b/src/pages/workspace/AccessOrNotFoundWrapper.tsx index 7a260d876371..83a24e2084d3 100644 --- a/src/pages/workspace/AccessOrNotFoundWrapper.tsx +++ b/src/pages/workspace/AccessOrNotFoundWrapper.tsx @@ -17,7 +17,6 @@ import type {IOUType} from '@src/CONST'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import type {PolicyFeatureName} from '@src/types/onyx/Policy'; import callOrReturn from '@src/types/utils/callOrReturn'; @@ -166,14 +165,6 @@ function AccessOrNotFoundWrapper({ setIsPolicyFeatureEnabled(isFeatureEnabled); }, [pendingField, isOffline, isFeatureEnabled]); - useEffect(() => { - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - if (isLoadingReportData || !isPolicyNotAccessible) { - return; - } - Navigation.removeScreenFromNavigationState(SCREENS.WORKSPACE.INITIAL); - }, [isLoadingReportData, isPolicyNotAccessible]); - if (shouldShowFullScreenLoadingIndicator) { return ; } From 9280e9e511018832dcbb22218cb2bb38263bad1b Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 25 Nov 2024 14:38:15 +0100 Subject: [PATCH 191/257] Fix typo in NavigationUtils.ts --- src/libs/NavigationUtils.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/NavigationUtils.ts b/src/libs/NavigationUtils.ts index 139694afcfe6..6ec44e62d690 100644 --- a/src/libs/NavigationUtils.ts +++ b/src/libs/NavigationUtils.ts @@ -18,7 +18,7 @@ const FULL_SCREENS_SET = new Set(FULL_SCREENS); const SIDEBARS_SET = new Set(SIDEBARS); const ONBOARDING_SCREENS_SET = new Set(ONBOARDING_SCREENS); -function checkIsScreenHasMatchingNameToSetValues(screen: string | undefined, set: Set): screen is T { +function checkIfScreenHasMatchingNameToSetValues(screen: string | undefined, set: Set): screen is T { if (!screen) { return false; } @@ -27,19 +27,19 @@ function checkIsScreenHasMatchingNameToSetValues(screen: strin } function isOnboardingFlowName(screen: string | undefined) { - return checkIsScreenHasMatchingNameToSetValues(screen, ONBOARDING_SCREENS_SET); + return checkIfScreenHasMatchingNameToSetValues(screen, ONBOARDING_SCREENS_SET); } function isSplitNavigatorName(screen: string | undefined) { - return checkIsScreenHasMatchingNameToSetValues(screen, SPLIT_NAVIGATORS_SET); + return checkIfScreenHasMatchingNameToSetValues(screen, SPLIT_NAVIGATORS_SET); } function isFullScreenName(screen: string | undefined) { - return checkIsScreenHasMatchingNameToSetValues(screen, FULL_SCREENS_SET); + return checkIfScreenHasMatchingNameToSetValues(screen, FULL_SCREENS_SET); } function isSidebarScreenName(screen: string | undefined) { - return checkIsScreenHasMatchingNameToSetValues(screen, SIDEBARS_SET); + return checkIfScreenHasMatchingNameToSetValues(screen, SIDEBARS_SET); } export {isFullScreenName, isOnboardingFlowName, isSidebarScreenName, isSplitNavigatorName}; From 9fbccec67a3c6d0697935a2c6b842e65fa3fd082 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 25 Nov 2024 20:24:16 +0100 Subject: [PATCH 192/257] Add navigation helpers --- .../DeeplinkWrapper/index.website.tsx | 2 +- .../MentionReportRenderer/index.tsx | 2 +- src/components/Lottie/index.tsx | 2 +- src/components/PromotedActionsBar.tsx | 2 +- src/components/Search/index.tsx | 2 +- .../Navigation/AppNavigator/AuthScreens.tsx | 2 +- .../Navigators/ReportsSplitNavigator.tsx | 2 +- .../CustomRouter.ts | 2 +- .../GetStateForActionHandlers.ts | 5 ++--- .../SplitStackRouter.ts | 2 +- src/libs/Navigation/Navigation.ts | 16 +++++++------- src/libs/Navigation/NavigationRoot.tsx | 3 +-- .../Navigation/{ => helpers}/closeRHPFlow.ts | 2 +- .../createNormalizedConfigs.ts | 0 .../createSplitNavigator.ts | 3 ++- .../customGetPathFromState.ts | 0 .../{ => helpers}/extractPolicyIDFromQuery.ts | 2 +- .../extrapolateStateFromParams.ts | 0 .../getAdaptedStateFromPath.ts | 6 +++--- .../getOnboardingAdaptedState.ts | 0 .../getParamsFromRoute.ts | 2 +- .../{ => helpers}/getPolicyIDFromState.ts | 2 +- .../{ => helpers}/getStateFromPath.ts | 2 +- .../{ => helpers}/getTopmostReportParam.ts | 2 +- .../{ => helpers}/getTopmostRouteName.ts | 0 src/libs/Navigation/helpers/index.ts | 21 +++++++++++++++++++ .../{ => helpers}/isReportOpenInRHP.ts | 0 .../isSearchTopmostFullScreenRoute.ts | 4 ++-- .../{ => helpers}/isSideModalNavigator.ts | 0 .../normalizePath.ts | 0 .../replacePathInNestedState.ts | 0 .../setNavigationActionToMicrotaskQueue.ts | 0 .../{ => helpers}/shouldOpenOnAdminRoom.ts | 2 +- .../shouldPreventDeeplinkPrompt.ts | 0 src/libs/Navigation/linkTo/index.ts | 5 ++--- src/libs/Navigation/linkingConfig/config.ts | 4 ++-- src/libs/Navigation/linkingConfig/index.ts | 4 ++-- src/libs/ReportActionComposeFocusManager.ts | 4 ++-- src/libs/actions/IOU.ts | 2 +- src/libs/actions/Welcome/OnboardingFlow.ts | 2 +- src/libs/navigateAfterOnboarding.ts | 2 +- src/pages/EditReportFieldPage.tsx | 2 +- src/pages/home/report/ReportActionsList.tsx | 2 +- src/pages/settings/InitialSettingsPage.tsx | 2 +- src/pages/workspace/WorkspaceInitialPage.tsx | 2 +- 45 files changed, 71 insertions(+), 50 deletions(-) rename src/libs/Navigation/{ => helpers}/closeRHPFlow.ts (94%) rename src/libs/Navigation/{linkingConfig => helpers}/createNormalizedConfigs.ts (100%) rename src/libs/Navigation/{linkingConfig => helpers}/createSplitNavigator.ts (91%) rename src/libs/Navigation/{linkingConfig => helpers}/customGetPathFromState.ts (100%) rename src/libs/Navigation/{ => helpers}/extractPolicyIDFromQuery.ts (89%) rename src/libs/Navigation/{ => helpers}/extrapolateStateFromParams.ts (100%) rename src/libs/Navigation/{linkingConfig => helpers}/getAdaptedStateFromPath.ts (98%) rename src/libs/Navigation/{linkingConfig => helpers}/getOnboardingAdaptedState.ts (100%) rename src/libs/Navigation/{linkingConfig => helpers}/getParamsFromRoute.ts (80%) rename src/libs/Navigation/{ => helpers}/getPolicyIDFromState.ts (97%) rename src/libs/Navigation/{ => helpers}/getStateFromPath.ts (93%) rename src/libs/Navigation/{ => helpers}/getTopmostReportParam.ts (95%) rename src/libs/Navigation/{ => helpers}/getTopmostRouteName.ts (100%) create mode 100644 src/libs/Navigation/helpers/index.ts rename src/libs/Navigation/{ => helpers}/isReportOpenInRHP.ts (100%) rename src/libs/Navigation/{ => helpers}/isSearchTopmostFullScreenRoute.ts (77%) rename src/libs/Navigation/{ => helpers}/isSideModalNavigator.ts (100%) rename src/libs/Navigation/{linkingConfig => helpers}/normalizePath.ts (100%) rename src/libs/Navigation/{linkingConfig => helpers}/replacePathInNestedState.ts (100%) rename src/libs/Navigation/{ => helpers}/setNavigationActionToMicrotaskQueue.ts (100%) rename src/libs/Navigation/{ => helpers}/shouldOpenOnAdminRoom.ts (75%) rename src/libs/Navigation/{ => helpers}/shouldPreventDeeplinkPrompt.ts (100%) diff --git a/src/components/DeeplinkWrapper/index.website.tsx b/src/components/DeeplinkWrapper/index.website.tsx index 73427f0d11aa..9848902a817f 100644 --- a/src/components/DeeplinkWrapper/index.website.tsx +++ b/src/components/DeeplinkWrapper/index.website.tsx @@ -1,9 +1,9 @@ import {Str} from 'expensify-common'; import {useEffect, useRef, useState} from 'react'; import * as Browser from '@libs/Browser'; +import {shouldPreventDeeplinkPrompt} from '@libs/Navigation/helpers'; import Navigation from '@libs/Navigation/Navigation'; import navigationRef from '@libs/Navigation/navigationRef'; -import shouldPreventDeeplinkPrompt from '@libs/Navigation/shouldPreventDeeplinkPrompt'; import * as App from '@userActions/App'; import * as Link from '@userActions/Link'; import * as Session from '@userActions/Session'; diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx index 5b05bae39a37..7dd36d372d96 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx @@ -10,7 +10,7 @@ import Text from '@components/Text'; import useCurrentReportID from '@hooks/useCurrentReportID'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import isSearchTopmostFullScreenRoute from '@libs/Navigation/isSearchTopmostFullScreenRoute'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation from '@navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/components/Lottie/index.tsx b/src/components/Lottie/index.tsx index 017d68aa4b56..190b24cbbf7b 100644 --- a/src/components/Lottie/index.tsx +++ b/src/components/Lottie/index.tsx @@ -9,7 +9,7 @@ import useAppState from '@hooks/useAppState'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Browser from '@libs/Browser'; -import isSideModalNavigator from '@libs/Navigation/isSideModalNavigator'; +import isSideModalNavigator from '@libs/Navigation/helpers/isSideModalNavigator'; import CONST from '@src/CONST'; import {useSplashScreenStateContext} from '@src/SplashScreenStateContext'; diff --git a/src/components/PromotedActionsBar.tsx b/src/components/PromotedActionsBar.tsx index b1a515097ebb..be4c734608c7 100644 --- a/src/components/PromotedActionsBar.tsx +++ b/src/components/PromotedActionsBar.tsx @@ -5,7 +5,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as HeaderUtils from '@libs/HeaderUtils'; import * as Localize from '@libs/Localize'; -import isSearchTopmostFullScreenRoute from '@libs/Navigation/isSearchTopmostFullScreenRoute'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as ReportActions from '@userActions/Report'; diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 9664c76c81ea..7675866017d4 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -19,7 +19,7 @@ import * as SearchActions from '@libs/actions/Search'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Log from '@libs/Log'; import memoize from '@libs/memoize'; -import isSearchTopmostFullScreenRoute from '@libs/Navigation/isSearchTopmostFullScreenRoute'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types'; import * as ReportUtils from '@libs/ReportUtils'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index a98a5274e012..f73f424ccacb 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -1,5 +1,5 @@ -import {findFocusedRoute} from '@react-navigation/native'; import type {RouteProp} from '@react-navigation/native'; +import {findFocusedRoute} from '@react-navigation/native'; import React, {memo, useEffect, useRef, useState} from 'react'; import {NativeModules, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index f5e90411722d..73972199e7b7 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -7,7 +7,7 @@ import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplit import FreezeWrapper from '@libs/Navigation/AppNavigator/FreezeWrapper'; import useRootNavigatorOptions from '@libs/Navigation/AppNavigator/useRootNavigatorOptions'; import getCurrentUrl from '@libs/Navigation/currentUrl'; -import shouldOpenOnAdminRoom from '@libs/Navigation/shouldOpenOnAdminRoom'; +import shouldOpenOnAdminRoom from '@libs/Navigation/helpers/shouldOpenOnAdminRoom'; import type {ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts index f678425e2ec5..ae3815e91997 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts @@ -3,7 +3,7 @@ import {findFocusedRoute, StackRouter} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/routers'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import * as Localize from '@libs/Localize'; -import isSideModalNavigator from '@libs/Navigation/isSideModalNavigator'; +import {isSideModalNavigator} from '@libs/Navigation/helpers'; import {isOnboardingFlowName} from '@libs/NavigationUtils'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts index b2af8cd41f98..1a952c0c6caa 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts @@ -2,12 +2,12 @@ import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigatio import {StackActions} from '@react-navigation/native'; import type {ParamListBase, Router} from '@react-navigation/routers'; import Log from '@libs/Log'; -import getPolicyIDFromState from '@libs/Navigation/getPolicyIDFromState'; +import getPolicyIDFromState from '@libs/Navigation/helpers/getPolicyIDFromState'; import type {RootStackParamList, State} from '@libs/Navigation/types'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -import type {DismissModalActionType, PushActionType, SwitchPolicyIdActionType} from './types'; +import type {PushActionType, SwitchPolicyIdActionType} from './types'; const MODAL_ROUTES_TO_DISMISS: string[] = [ NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, @@ -137,7 +137,6 @@ function handlePushSearchPageAction( function handleDismissModalAction( state: StackNavigationState, - action: DismissModalActionType, configOptions: RouterConfigOptions, stackRouter: Router, CommonActions.Action | StackActionType>, ) { diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts index 6dd910985b41..3bc1e50717ec 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts @@ -2,7 +2,7 @@ import type {CommonActions, ParamListBase, PartialState, RouterConfigOptions, St import {StackActions, StackRouter} from '@react-navigation/native'; import pick from 'lodash/pick'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import getParamsFromRoute from '@libs/Navigation/linkingConfig/getParamsFromRoute'; +import {getParamsFromRoute} from '@libs/Navigation/helpers'; import navigationRef from '@libs/Navigation/navigationRef'; import SCREENS from '@src/SCREENS'; import type {SplitStackNavigatorRouterOptions} from './types'; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 8013eb6c20c3..b1d32c5f6016 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -20,18 +20,20 @@ import ROUTES, {HYBRID_APP_ROUTES} from '@src/ROUTES'; import SCREENS, {PROTECTED_SCREENS} from '@src/SCREENS'; import type {Report} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import originalCloseRHPFlow from './closeRHPFlow'; -import getPolicyIDFromState from './getPolicyIDFromState'; -import getStateFromPath from './getStateFromPath'; -import getTopmostReportParam from './getTopmostReportParam'; -import isReportOpenInRHP from './isReportOpenInRHP'; +import { + createSplitNavigator, + getPolicyIDFromState, + getStateFromPath, + getTopmostReportParam, + isReportOpenInRHP, + closeRHPFlow as originalCloseRHPFlow, + setNavigationActionToMicrotaskQueue, +} from './helpers'; import linkingConfig from './linkingConfig'; -import createSplitNavigator from './linkingConfig/createSplitNavigator'; import RELATIONS from './linkingConfig/RELATIONS'; import linkTo from './linkTo'; import getMinimalAction from './linkTo/getMinimalAction'; import navigationRef from './navigationRef'; -import setNavigationActionToMicrotaskQueue from './setNavigationActionToMicrotaskQueue'; import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, State} from './types'; function getSidebarScreenParams(splitNavigatorRoute: NavigationStateRoute) { diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 03d761575400..99723d3422a9 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -23,9 +23,8 @@ import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import AppNavigator from './AppNavigator'; import {cleanPreservedSplitNavigatorStates} from './AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState'; +import {customGetPathFromState, getAdaptedStateFromPath} from './helpers'; import linkingConfig from './linkingConfig'; -import customGetPathFromState from './linkingConfig/customGetPathFromState'; -import getAdaptedStateFromPath from './linkingConfig/getAdaptedStateFromPath'; import Navigation, {navigationRef} from './Navigation'; import setupCustomAndroidBackHandler from './setupCustomAndroidBackHandler'; diff --git a/src/libs/Navigation/closeRHPFlow.ts b/src/libs/Navigation/helpers/closeRHPFlow.ts similarity index 94% rename from src/libs/Navigation/closeRHPFlow.ts rename to src/libs/Navigation/helpers/closeRHPFlow.ts index 9bc40f51f472..0f814ca13bb7 100644 --- a/src/libs/Navigation/closeRHPFlow.ts +++ b/src/libs/Navigation/helpers/closeRHPFlow.ts @@ -1,8 +1,8 @@ import type {NavigationContainerRef} from '@react-navigation/native'; import {StackActions} from '@react-navigation/native'; import Log from '@libs/Log'; +import type {RootStackParamList} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; -import type {RootStackParamList} from './types'; /** * Closes the last RHP flow, if there is only one, closes the entire RHP. diff --git a/src/libs/Navigation/linkingConfig/createNormalizedConfigs.ts b/src/libs/Navigation/helpers/createNormalizedConfigs.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/createNormalizedConfigs.ts rename to src/libs/Navigation/helpers/createNormalizedConfigs.ts diff --git a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts b/src/libs/Navigation/helpers/createSplitNavigator.ts similarity index 91% rename from src/libs/Navigation/linkingConfig/createSplitNavigator.ts rename to src/libs/Navigation/helpers/createSplitNavigator.ts index c2d09d28dc87..a43e5a83d7ab 100644 --- a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts +++ b/src/libs/Navigation/helpers/createSplitNavigator.ts @@ -1,6 +1,6 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; +import LHN_TO_SPLIT_NAVIGATOR_NAME from '@libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING'; import type {NavigationPartialRoute, SplitNavigatorByLHN, SplitNavigatorLHNScreen, SplitNavigatorParamListType} from '@libs/Navigation/types'; -import LHN_TO_SPLIT_NAVIGATOR_NAME from './RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING'; type ExtractRouteType = Extract; @@ -25,4 +25,5 @@ function createSplitNavigator( params: splitNavigatorParams, }; } + export default createSplitNavigator; diff --git a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts b/src/libs/Navigation/helpers/customGetPathFromState.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/customGetPathFromState.ts rename to src/libs/Navigation/helpers/customGetPathFromState.ts diff --git a/src/libs/Navigation/extractPolicyIDFromQuery.ts b/src/libs/Navigation/helpers/extractPolicyIDFromQuery.ts similarity index 89% rename from src/libs/Navigation/extractPolicyIDFromQuery.ts rename to src/libs/Navigation/helpers/extractPolicyIDFromQuery.ts index f091690c16f2..d37ded16b4b5 100644 --- a/src/libs/Navigation/extractPolicyIDFromQuery.ts +++ b/src/libs/Navigation/helpers/extractPolicyIDFromQuery.ts @@ -1,5 +1,5 @@ +import type {NavigationPartialRoute} from '@libs/Navigation/types'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; -import type {NavigationPartialRoute} from './types'; function extractPolicyIDFromQuery(route?: NavigationPartialRoute) { if (!route?.params) { diff --git a/src/libs/Navigation/extrapolateStateFromParams.ts b/src/libs/Navigation/helpers/extrapolateStateFromParams.ts similarity index 100% rename from src/libs/Navigation/extrapolateStateFromParams.ts rename to src/libs/Navigation/helpers/extrapolateStateFromParams.ts diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts similarity index 98% rename from src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts rename to src/libs/Navigation/helpers/getAdaptedStateFromPath.ts index 4108a12b7253..a3f5bc3af16f 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts @@ -2,18 +2,18 @@ import type {NavigationState, PartialState, Route} from '@react-navigation/nativ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import pick from 'lodash/pick'; import {isAnonymousUser} from '@libs/actions/Session'; +import config from '@libs/Navigation/linkingConfig/config'; +import RELATIONS from '@libs/Navigation/linkingConfig/RELATIONS'; import type {NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; import {isFullScreenName} from '@libs/NavigationUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; -import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import SCREENS from '@src/SCREENS'; -import config from './config'; import createSplitNavigator from './createSplitNavigator'; +import extractPolicyIDFromQuery from './extractPolicyIDFromQuery'; import getParamsFromRoute from './getParamsFromRoute'; -import RELATIONS from './RELATIONS'; import replacePathInNestedState from './replacePathInNestedState'; type GetAdaptedStateReturnType = { diff --git a/src/libs/Navigation/linkingConfig/getOnboardingAdaptedState.ts b/src/libs/Navigation/helpers/getOnboardingAdaptedState.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/getOnboardingAdaptedState.ts rename to src/libs/Navigation/helpers/getOnboardingAdaptedState.ts diff --git a/src/libs/Navigation/linkingConfig/getParamsFromRoute.ts b/src/libs/Navigation/helpers/getParamsFromRoute.ts similarity index 80% rename from src/libs/Navigation/linkingConfig/getParamsFromRoute.ts rename to src/libs/Navigation/helpers/getParamsFromRoute.ts index 0b020ddbd7bf..1dd815f65e9b 100644 --- a/src/libs/Navigation/linkingConfig/getParamsFromRoute.ts +++ b/src/libs/Navigation/helpers/getParamsFromRoute.ts @@ -1,5 +1,5 @@ +import {normalizedConfigs} from '@libs/Navigation/linkingConfig/config'; import type {Screen} from '@src/SCREENS'; -import {normalizedConfigs} from './config'; function getParamsFromRoute(screenName: string): string[] { const routeConfig = normalizedConfigs[screenName as Screen]; diff --git a/src/libs/Navigation/getPolicyIDFromState.ts b/src/libs/Navigation/helpers/getPolicyIDFromState.ts similarity index 97% rename from src/libs/Navigation/getPolicyIDFromState.ts rename to src/libs/Navigation/helpers/getPolicyIDFromState.ts index f5604c8a3733..b4b81ee15db8 100644 --- a/src/libs/Navigation/getPolicyIDFromState.ts +++ b/src/libs/Navigation/helpers/getPolicyIDFromState.ts @@ -1,7 +1,7 @@ +import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import extractPolicyIDFromQuery from './extractPolicyIDFromQuery'; -import type {NavigationPartialRoute, RootStackParamList, State} from './types'; /** * returns policyID value if one exists in navigation state diff --git a/src/libs/Navigation/getStateFromPath.ts b/src/libs/Navigation/helpers/getStateFromPath.ts similarity index 93% rename from src/libs/Navigation/getStateFromPath.ts rename to src/libs/Navigation/helpers/getStateFromPath.ts index 50254bb3898d..19272ca3938f 100644 --- a/src/libs/Navigation/getStateFromPath.ts +++ b/src/libs/Navigation/helpers/getStateFromPath.ts @@ -1,7 +1,7 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; import {getStateFromPath as RNGetStateFromPath} from '@react-navigation/native'; +import linkingConfig from '@libs/Navigation/linkingConfig'; import type {Route} from '@src/ROUTES'; -import linkingConfig from './linkingConfig'; /** * @param path - The path to parse diff --git a/src/libs/Navigation/getTopmostReportParam.ts b/src/libs/Navigation/helpers/getTopmostReportParam.ts similarity index 95% rename from src/libs/Navigation/getTopmostReportParam.ts rename to src/libs/Navigation/helpers/getTopmostReportParam.ts index 30354c7c6dd0..026cd379aa1a 100644 --- a/src/libs/Navigation/getTopmostReportParam.ts +++ b/src/libs/Navigation/helpers/getTopmostReportParam.ts @@ -1,7 +1,7 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; +import type {RootStackParamList} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -import type {RootStackParamList} from './types'; // This function is in a separate file than Navigation.ts to avoid cyclic dependency. diff --git a/src/libs/Navigation/getTopmostRouteName.ts b/src/libs/Navigation/helpers/getTopmostRouteName.ts similarity index 100% rename from src/libs/Navigation/getTopmostRouteName.ts rename to src/libs/Navigation/helpers/getTopmostRouteName.ts diff --git a/src/libs/Navigation/helpers/index.ts b/src/libs/Navigation/helpers/index.ts new file mode 100644 index 000000000000..56cc2c28611d --- /dev/null +++ b/src/libs/Navigation/helpers/index.ts @@ -0,0 +1,21 @@ +export * from './createNormalizedConfigs'; +export {default as customGetPathFromState} from './customGetPathFromState'; +export {default as getOnboardingAdaptedState} from './getOnboardingAdaptedState'; +export {default as getParamsFromRoute} from './getParamsFromRoute'; +export {default as normalizePath} from './normalizePath'; +export {default as replacePathInNestedState} from './replacePathInNestedState'; +export {default as createNormalizedConfigs} from './createNormalizedConfigs'; +export {default as createSplitNavigator} from './createSplitNavigator'; +export {default as getAdaptedStateFromPath} from './getAdaptedStateFromPath'; +export {default as extractPolicyIDFromQuery} from './extractPolicyIDFromQuery'; +export {default as closeRHPFlow} from './closeRHPFlow'; +export {default as getPolicyIDFromState} from './getPolicyIDFromState'; +export {default as getStateFromPath} from './getStateFromPath'; +export {default as getTopmostReportParam} from './getTopmostReportParam'; +export {default as getTopmostRouteName} from './getTopmostRouteName'; +export {default as isReportOpenInRHP} from './isReportOpenInRHP'; +export {default as isSearchTopmostFullScreenRoute} from './isSearchTopmostFullScreenRoute'; +export {default as isSideModalNavigator} from './isSideModalNavigator'; +export {default as setNavigationActionToMicrotaskQueue} from './setNavigationActionToMicrotaskQueue'; +export {default as shouldOpenOnAdminRoom} from './shouldOpenOnAdminRoom'; +export {default as shouldPreventDeeplinkPrompt} from './shouldPreventDeeplinkPrompt'; diff --git a/src/libs/Navigation/isReportOpenInRHP.ts b/src/libs/Navigation/helpers/isReportOpenInRHP.ts similarity index 100% rename from src/libs/Navigation/isReportOpenInRHP.ts rename to src/libs/Navigation/helpers/isReportOpenInRHP.ts diff --git a/src/libs/Navigation/isSearchTopmostFullScreenRoute.ts b/src/libs/Navigation/helpers/isSearchTopmostFullScreenRoute.ts similarity index 77% rename from src/libs/Navigation/isSearchTopmostFullScreenRoute.ts rename to src/libs/Navigation/helpers/isSearchTopmostFullScreenRoute.ts index 5599ec650c14..4991ae40a7e5 100644 --- a/src/libs/Navigation/isSearchTopmostFullScreenRoute.ts +++ b/src/libs/Navigation/helpers/isSearchTopmostFullScreenRoute.ts @@ -1,7 +1,7 @@ +import {navigationRef} from '@libs/Navigation/Navigation'; +import type {RootStackParamList, State} from '@libs/Navigation/types'; import {isFullScreenName} from '@libs/NavigationUtils'; import SCREENS from '@src/SCREENS'; -import {navigationRef} from './Navigation'; -import type {RootStackParamList, State} from './types'; const isSearchTopmostFullScreenRoute = (): boolean => { const rootState = navigationRef.getRootState() as State; diff --git a/src/libs/Navigation/isSideModalNavigator.ts b/src/libs/Navigation/helpers/isSideModalNavigator.ts similarity index 100% rename from src/libs/Navigation/isSideModalNavigator.ts rename to src/libs/Navigation/helpers/isSideModalNavigator.ts diff --git a/src/libs/Navigation/linkingConfig/normalizePath.ts b/src/libs/Navigation/helpers/normalizePath.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/normalizePath.ts rename to src/libs/Navigation/helpers/normalizePath.ts diff --git a/src/libs/Navigation/linkingConfig/replacePathInNestedState.ts b/src/libs/Navigation/helpers/replacePathInNestedState.ts similarity index 100% rename from src/libs/Navigation/linkingConfig/replacePathInNestedState.ts rename to src/libs/Navigation/helpers/replacePathInNestedState.ts diff --git a/src/libs/Navigation/setNavigationActionToMicrotaskQueue.ts b/src/libs/Navigation/helpers/setNavigationActionToMicrotaskQueue.ts similarity index 100% rename from src/libs/Navigation/setNavigationActionToMicrotaskQueue.ts rename to src/libs/Navigation/helpers/setNavigationActionToMicrotaskQueue.ts diff --git a/src/libs/Navigation/shouldOpenOnAdminRoom.ts b/src/libs/Navigation/helpers/shouldOpenOnAdminRoom.ts similarity index 75% rename from src/libs/Navigation/shouldOpenOnAdminRoom.ts rename to src/libs/Navigation/helpers/shouldOpenOnAdminRoom.ts index a593e8c22768..ae316fa3fa44 100644 --- a/src/libs/Navigation/shouldOpenOnAdminRoom.ts +++ b/src/libs/Navigation/helpers/shouldOpenOnAdminRoom.ts @@ -1,4 +1,4 @@ -import getCurrentUrl from './currentUrl'; +import getCurrentUrl from '@libs/Navigation/currentUrl'; export default function shouldOpenOnAdminRoom() { const url = getCurrentUrl(); diff --git a/src/libs/Navigation/shouldPreventDeeplinkPrompt.ts b/src/libs/Navigation/helpers/shouldPreventDeeplinkPrompt.ts similarity index 100% rename from src/libs/Navigation/shouldPreventDeeplinkPrompt.ts rename to src/libs/Navigation/helpers/shouldPreventDeeplinkPrompt.ts diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/linkTo/index.ts index 9925980d37b8..26feeb8f4a85 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/linkTo/index.ts @@ -1,11 +1,10 @@ import {getActionFromState} from '@react-navigation/core'; import type {NavigationContainerRef, NavigationState, PartialState, StackActionType} from '@react-navigation/native'; import {findFocusedRoute, StackActions} from '@react-navigation/native'; -import {getMatchingFullScreenRoute, isFullScreenName} from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; -import normalizePath from '@libs/Navigation/linkingConfig/normalizePath'; +import {getStateFromPath, normalizePath} from '@libs/Navigation/helpers'; +import {getMatchingFullScreenRoute, isFullScreenName} from '@libs/Navigation/helpers/getAdaptedStateFromPath'; import {shallowCompare} from '@libs/ObjectUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; -import getStateFromPath from '@navigation/getStateFromPath'; import linkingConfig from '@navigation/linkingConfig'; import type {NavigationPartialRoute, ReportsSplitNavigatorParamList, RootStackParamList, StackNavigationAction} from '@navigation/types'; import CONST from '@src/CONST'; diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 3be3be9d15ec..252f1793af55 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1,11 +1,11 @@ import type {LinkingOptions} from '@react-navigation/native'; +import {createNormalizedConfigs} from '@libs/Navigation/helpers'; +import type {RouteConfig} from '@libs/Navigation/helpers'; import type {RootStackParamList} from '@navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import ROUTES from '@src/ROUTES'; import type {Screen} from '@src/SCREENS'; import SCREENS from '@src/SCREENS'; -import type {RouteConfig} from './createNormalizedConfigs'; -import createNormalizedConfigs from './createNormalizedConfigs'; // Moved to a separate file to avoid cyclic dependencies. const config: LinkingOptions['config'] = { diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index 3e958d593ec9..dcdd14241cff 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type {LinkingOptions} from '@react-navigation/native'; +import {customGetPathFromState} from '@libs/Navigation/helpers'; +import getAdaptedStateFromPath from '@libs/Navigation/helpers/getAdaptedStateFromPath'; import type {RootStackParamList} from '@navigation/types'; import config from './config'; -import customGetPathFromState from './customGetPathFromState'; -import getAdaptedStateFromPath from './getAdaptedStateFromPath'; import prefixes from './prefixes'; const linkingConfig: LinkingOptions = { diff --git a/src/libs/ReportActionComposeFocusManager.ts b/src/libs/ReportActionComposeFocusManager.ts index 450a6d7f5481..2967a49512ea 100644 --- a/src/libs/ReportActionComposeFocusManager.ts +++ b/src/libs/ReportActionComposeFocusManager.ts @@ -2,8 +2,8 @@ import React from 'react'; import type {MutableRefObject} from 'react'; import type {TextInput} from 'react-native'; import SCREENS from '@src/SCREENS'; -import getTopmostRouteName from './Navigation/getTopmostRouteName'; -import isReportOpenInRHP from './Navigation/isReportOpenInRHP'; +import getTopmostRouteName from './Navigation/helpers/getTopmostRouteName'; +import isReportOpenInRHP from './Navigation/helpers/isReportOpenInRHP'; import navigationRef from './Navigation/navigationRef'; type FocusCallback = (shouldFocusForNonBlurInputOnTapOutside?: boolean) => void; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 1ccfd4989a11..6547a7394d53 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -39,7 +39,7 @@ import GoogleTagManager from '@libs/GoogleTagManager'; import * as IOUUtils from '@libs/IOUUtils'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; import * as Localize from '@libs/Localize'; -import isSearchTopmostFullScreenRoute from '@libs/Navigation/isSearchTopmostFullScreenRoute'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import * as NextStepUtils from '@libs/NextStepUtils'; import {rand64} from '@libs/NumberUtils'; diff --git a/src/libs/actions/Welcome/OnboardingFlow.ts b/src/libs/actions/Welcome/OnboardingFlow.ts index 5a1b4fc0474a..3908f372b891 100644 --- a/src/libs/actions/Welcome/OnboardingFlow.ts +++ b/src/libs/actions/Welcome/OnboardingFlow.ts @@ -1,8 +1,8 @@ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import type {NavigationState, PartialState} from '@react-navigation/native'; import Onyx from 'react-native-onyx'; +import {getAdaptedStateFromPath} from '@libs/Navigation/helpers'; import linkingConfig from '@libs/Navigation/linkingConfig'; -import getAdaptedStateFromPath from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath'; import {navigationRef} from '@libs/Navigation/Navigation'; import type {RootStackParamList} from '@libs/Navigation/types'; import CONST from '@src/CONST'; diff --git a/src/libs/navigateAfterOnboarding.ts b/src/libs/navigateAfterOnboarding.ts index d84927988b5c..494c70c907f4 100644 --- a/src/libs/navigateAfterOnboarding.ts +++ b/src/libs/navigateAfterOnboarding.ts @@ -1,7 +1,7 @@ import ROUTES from '@src/ROUTES'; import * as Report from './actions/Report'; +import {shouldOpenOnAdminRoom} from './Navigation/helpers'; import Navigation from './Navigation/Navigation'; -import shouldOpenOnAdminRoom from './Navigation/shouldOpenOnAdminRoom'; import * as ReportUtils from './ReportUtils'; const navigateAfterOnboarding = ( diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index be40e7f6c9e0..afa402959356 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -11,7 +11,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import isSearchTopmostFullScreenRoute from '@libs/Navigation/isSearchTopmostFullScreenRoute'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {EditRequestNavigatorParamList} from '@libs/Navigation/types'; diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx index 620f4fb3dcf5..ec14c55b36a6 100644 --- a/src/pages/home/report/ReportActionsList.tsx +++ b/src/pages/home/report/ReportActionsList.tsx @@ -19,7 +19,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import DateUtils from '@libs/DateUtils'; -import isSearchTopmostFullScreenRoute from '@libs/Navigation/isSearchTopmostFullScreenRoute'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 15597fb7b277..b147e28c5a77 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -32,7 +32,7 @@ import useWaitForNavigation from '@hooks/useWaitForNavigation'; import {resetExitSurveyForm} from '@libs/actions/ExitSurvey'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; -import getTopmostRouteName from '@libs/Navigation/getTopmostRouteName'; +import getTopmostRouteName from '@libs/Navigation/helpers/getTopmostRouteName'; import Navigation from '@libs/Navigation/Navigation'; import * as SubscriptionUtils from '@libs/SubscriptionUtils'; import * as UserUtils from '@libs/UserUtils'; diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 097891219017..952293b540b4 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -24,7 +24,7 @@ import {isConnectionInProgress} from '@libs/actions/connections'; import * as CardUtils from '@libs/CardUtils'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; -import getTopmostRouteName from '@libs/Navigation/getTopmostRouteName'; +import getTopmostRouteName from '@libs/Navigation/helpers/getTopmostRouteName'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; From be9cb55519ac8eb6ae4217f37f9295ac1b74d421 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 26 Nov 2024 09:19:23 +0100 Subject: [PATCH 193/257] Move navigation functions to helpers package --- .../FocusTrapForScreen/index.web.tsx | 2 +- .../ScrollOffsetContextProvider.tsx | 2 +- .../getIsScreenBlurred/index.native.ts | 2 +- .../FreezeWrapper/getIsScreenBlurred/index.ts | 2 +- .../CustomRouter.ts | 3 +-- src/libs/Navigation/Navigation.ts | 6 +++--- src/libs/Navigation/NavigationRoot.tsx | 3 +-- .../helpers/customGetPathFromState.ts | 2 +- .../helpers/getAdaptedStateFromPath.ts | 2 +- src/libs/Navigation/helpers/index.ts | 19 ++++++++++++------- .../helpers/isNavigatorName.ts} | 2 +- .../helpers/isSearchTopmostFullScreenRoute.ts | 2 +- .../{ => helpers}/linkTo/getMinimalAction.ts | 0 .../Navigation/{ => helpers}/linkTo/index.ts | 3 ++- .../Navigation/{ => helpers}/linkTo/types.ts | 0 .../index.android.ts | 0 .../setupCustomAndroidBackHandler/index.ts | 0 src/libs/ReportUtils.ts | 2 +- src/libs/actions/Report.ts | 2 +- src/pages/AddPersonalBankAccountPage.tsx | 2 +- 20 files changed, 30 insertions(+), 26 deletions(-) rename src/libs/{NavigationUtils.ts => Navigation/helpers/isNavigatorName.ts} (96%) rename src/libs/Navigation/{ => helpers}/linkTo/getMinimalAction.ts (100%) rename src/libs/Navigation/{ => helpers}/linkTo/index.ts (97%) rename src/libs/Navigation/{ => helpers}/linkTo/types.ts (100%) rename src/libs/Navigation/{ => helpers}/setupCustomAndroidBackHandler/index.android.ts (100%) rename src/libs/Navigation/{ => helpers}/setupCustomAndroidBackHandler/index.ts (100%) diff --git a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx index 62a6b5d100a8..2a5fb850066c 100644 --- a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx +++ b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx @@ -5,7 +5,7 @@ import sharedTrapStack from '@components/FocusTrap/sharedTrapStack'; import TOP_TAB_SCREENS from '@components/FocusTrap/TOP_TAB_SCREENS'; import WIDE_LAYOUT_INACTIVE_SCREENS from '@components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import {isSidebarScreenName} from '@libs/NavigationUtils'; +import {isSidebarScreenName} from '@libs/Navigation/helpers'; import CONST from '@src/CONST'; import type FocusTrapProps from './FocusTrapProps'; diff --git a/src/components/ScrollOffsetContextProvider.tsx b/src/components/ScrollOffsetContextProvider.tsx index f5573fd6b2e4..9620da9e72e5 100644 --- a/src/components/ScrollOffsetContextProvider.tsx +++ b/src/components/ScrollOffsetContextProvider.tsx @@ -2,9 +2,9 @@ import type {ParamListBase} from '@react-navigation/native'; import React, {createContext, useCallback, useEffect, useMemo, useRef} from 'react'; import {withOnyx} from 'react-native-onyx'; import usePrevious from '@hooks/usePrevious'; +import {isSidebarScreenName} from '@libs/Navigation/helpers'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {NavigationPartialRoute, State} from '@libs/Navigation/types'; -import {isSidebarScreenName} from '@libs/NavigationUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import SCREENS from '@src/SCREENS'; import type {PriorityMode} from '@src/types/onyx'; diff --git a/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.native.ts b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.native.ts index 9b1cbd94dced..4cc3caa86cdb 100644 --- a/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.native.ts +++ b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.native.ts @@ -1,5 +1,5 @@ import type {NavigationState} from '@react-navigation/native'; -import {isFullScreenName} from '@libs/NavigationUtils'; +import {isFullScreenName} from '@libs/Navigation/helpers'; function getIsScreenBlurred(state: NavigationState, currentRouteKey: string) { // If the screen is one of the last two fullscreen routes in the stack, it is not freezed on native platforms. diff --git a/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.ts b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.ts index beae98460c1a..4ad2ea2c9aa5 100644 --- a/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.ts +++ b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.ts @@ -1,5 +1,5 @@ import type {NavigationState} from '@react-navigation/native'; -import {isFullScreenName} from '@libs/NavigationUtils'; +import {isFullScreenName} from '@libs/Navigation/helpers'; function getIsScreenBlurred(state: NavigationState, currentRouteKey: string) { const lastFullScreenRoute = state.routes.findLast((route) => isFullScreenName(route.name)); diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts index ae3815e91997..94bb91fb5434 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts @@ -3,8 +3,7 @@ import {findFocusedRoute, StackRouter} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/routers'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import * as Localize from '@libs/Localize'; -import {isSideModalNavigator} from '@libs/Navigation/helpers'; -import {isOnboardingFlowName} from '@libs/NavigationUtils'; +import {isOnboardingFlowName, isSideModalNavigator} from '@libs/Navigation/helpers'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index b1d32c5f6016..48229b9a2ef4 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -7,7 +7,6 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {Writable} from 'type-fest'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import Log from '@libs/Log'; -import {isSplitNavigatorName} from '@libs/NavigationUtils'; import {shallowCompare} from '@libs/ObjectUtils'; import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils'; import * as ReportConnection from '@libs/ReportConnection'; @@ -22,17 +21,18 @@ import type {Report} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import { createSplitNavigator, + getMinimalAction, getPolicyIDFromState, getStateFromPath, getTopmostReportParam, isReportOpenInRHP, + isSplitNavigatorName, + linkTo, closeRHPFlow as originalCloseRHPFlow, setNavigationActionToMicrotaskQueue, } from './helpers'; import linkingConfig from './linkingConfig'; import RELATIONS from './linkingConfig/RELATIONS'; -import linkTo from './linkTo'; -import getMinimalAction from './linkTo/getMinimalAction'; import navigationRef from './navigationRef'; import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, State} from './types'; diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 99723d3422a9..3181e2d60979 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -23,10 +23,9 @@ import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import AppNavigator from './AppNavigator'; import {cleanPreservedSplitNavigatorStates} from './AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState'; -import {customGetPathFromState, getAdaptedStateFromPath} from './helpers'; +import {customGetPathFromState, getAdaptedStateFromPath, setupCustomAndroidBackHandler} from './helpers'; import linkingConfig from './linkingConfig'; import Navigation, {navigationRef} from './Navigation'; -import setupCustomAndroidBackHandler from './setupCustomAndroidBackHandler'; type NavigationRootProps = { /** Whether the current user is logged in with an authToken */ diff --git a/src/libs/Navigation/helpers/customGetPathFromState.ts b/src/libs/Navigation/helpers/customGetPathFromState.ts index 8954e48955f8..0a42aa67a1ce 100644 --- a/src/libs/Navigation/helpers/customGetPathFromState.ts +++ b/src/libs/Navigation/helpers/customGetPathFromState.ts @@ -1,6 +1,6 @@ import {getPathFromState} from '@react-navigation/native'; -import {isFullScreenName} from '@libs/NavigationUtils'; import NAVIGATORS from '@src/NAVIGATORS'; +import {isFullScreenName} from './isNavigatorName'; const customGetPathFromState: typeof getPathFromState = (state, options) => { const path = getPathFromState(state, options); diff --git a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts index a3f5bc3af16f..7122bc8b75e0 100644 --- a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts @@ -5,7 +5,6 @@ import {isAnonymousUser} from '@libs/actions/Session'; import config from '@libs/Navigation/linkingConfig/config'; import RELATIONS from '@libs/Navigation/linkingConfig/RELATIONS'; import type {NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; -import {isFullScreenName} from '@libs/NavigationUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -14,6 +13,7 @@ import SCREENS from '@src/SCREENS'; import createSplitNavigator from './createSplitNavigator'; import extractPolicyIDFromQuery from './extractPolicyIDFromQuery'; import getParamsFromRoute from './getParamsFromRoute'; +import {isFullScreenName} from './isNavigatorName'; import replacePathInNestedState from './replacePathInNestedState'; type GetAdaptedStateReturnType = { diff --git a/src/libs/Navigation/helpers/index.ts b/src/libs/Navigation/helpers/index.ts index 56cc2c28611d..46a977002326 100644 --- a/src/libs/Navigation/helpers/index.ts +++ b/src/libs/Navigation/helpers/index.ts @@ -1,14 +1,14 @@ export * from './createNormalizedConfigs'; -export {default as customGetPathFromState} from './customGetPathFromState'; -export {default as getOnboardingAdaptedState} from './getOnboardingAdaptedState'; -export {default as getParamsFromRoute} from './getParamsFromRoute'; -export {default as normalizePath} from './normalizePath'; -export {default as replacePathInNestedState} from './replacePathInNestedState'; +export * from './isNavigatorName'; +export * from './linkTo/types'; +export {default as closeRHPFlow} from './closeRHPFlow'; export {default as createNormalizedConfigs} from './createNormalizedConfigs'; export {default as createSplitNavigator} from './createSplitNavigator'; -export {default as getAdaptedStateFromPath} from './getAdaptedStateFromPath'; +export {default as customGetPathFromState} from './customGetPathFromState'; export {default as extractPolicyIDFromQuery} from './extractPolicyIDFromQuery'; -export {default as closeRHPFlow} from './closeRHPFlow'; +export {default as getAdaptedStateFromPath} from './getAdaptedStateFromPath'; +export {default as getOnboardingAdaptedState} from './getOnboardingAdaptedState'; +export {default as getParamsFromRoute} from './getParamsFromRoute'; export {default as getPolicyIDFromState} from './getPolicyIDFromState'; export {default as getStateFromPath} from './getStateFromPath'; export {default as getTopmostReportParam} from './getTopmostReportParam'; @@ -16,6 +16,11 @@ export {default as getTopmostRouteName} from './getTopmostRouteName'; export {default as isReportOpenInRHP} from './isReportOpenInRHP'; export {default as isSearchTopmostFullScreenRoute} from './isSearchTopmostFullScreenRoute'; export {default as isSideModalNavigator} from './isSideModalNavigator'; +export {default as linkTo} from './linkTo'; +export {default as getMinimalAction} from './linkTo/getMinimalAction'; +export {default as normalizePath} from './normalizePath'; +export {default as replacePathInNestedState} from './replacePathInNestedState'; export {default as setNavigationActionToMicrotaskQueue} from './setNavigationActionToMicrotaskQueue'; +export {default as setupCustomAndroidBackHandler} from './setupCustomAndroidBackHandler'; export {default as shouldOpenOnAdminRoom} from './shouldOpenOnAdminRoom'; export {default as shouldPreventDeeplinkPrompt} from './shouldPreventDeeplinkPrompt'; diff --git a/src/libs/NavigationUtils.ts b/src/libs/Navigation/helpers/isNavigatorName.ts similarity index 96% rename from src/libs/NavigationUtils.ts rename to src/libs/Navigation/helpers/isNavigatorName.ts index 6ec44e62d690..49bada1dc286 100644 --- a/src/libs/NavigationUtils.ts +++ b/src/libs/Navigation/helpers/isNavigatorName.ts @@ -1,6 +1,6 @@ +import type {FullScreenName, OnboardingFlowName, SplitNavigatorLHNScreen, SplitNavigatorName} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -import type {FullScreenName, OnboardingFlowName, SplitNavigatorLHNScreen, SplitNavigatorName} from './Navigation/types'; const SPLIT_NAVIGATORS = [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]; const FULL_SCREENS = [...SPLIT_NAVIGATORS, SCREENS.SEARCH.CENTRAL_PANE]; diff --git a/src/libs/Navigation/helpers/isSearchTopmostFullScreenRoute.ts b/src/libs/Navigation/helpers/isSearchTopmostFullScreenRoute.ts index 4991ae40a7e5..e98b253b74bd 100644 --- a/src/libs/Navigation/helpers/isSearchTopmostFullScreenRoute.ts +++ b/src/libs/Navigation/helpers/isSearchTopmostFullScreenRoute.ts @@ -1,7 +1,7 @@ import {navigationRef} from '@libs/Navigation/Navigation'; import type {RootStackParamList, State} from '@libs/Navigation/types'; -import {isFullScreenName} from '@libs/NavigationUtils'; import SCREENS from '@src/SCREENS'; +import {isFullScreenName} from './isNavigatorName'; const isSearchTopmostFullScreenRoute = (): boolean => { const rootState = navigationRef.getRootState() as State; diff --git a/src/libs/Navigation/linkTo/getMinimalAction.ts b/src/libs/Navigation/helpers/linkTo/getMinimalAction.ts similarity index 100% rename from src/libs/Navigation/linkTo/getMinimalAction.ts rename to src/libs/Navigation/helpers/linkTo/getMinimalAction.ts diff --git a/src/libs/Navigation/linkTo/index.ts b/src/libs/Navigation/helpers/linkTo/index.ts similarity index 97% rename from src/libs/Navigation/linkTo/index.ts rename to src/libs/Navigation/helpers/linkTo/index.ts index 26feeb8f4a85..39dd6b0b1571 100644 --- a/src/libs/Navigation/linkTo/index.ts +++ b/src/libs/Navigation/helpers/linkTo/index.ts @@ -1,8 +1,9 @@ import {getActionFromState} from '@react-navigation/core'; import type {NavigationContainerRef, NavigationState, PartialState, StackActionType} from '@react-navigation/native'; import {findFocusedRoute, StackActions} from '@react-navigation/native'; -import {getStateFromPath, normalizePath} from '@libs/Navigation/helpers'; import {getMatchingFullScreenRoute, isFullScreenName} from '@libs/Navigation/helpers/getAdaptedStateFromPath'; +import getStateFromPath from '@libs/Navigation/helpers/getStateFromPath'; +import normalizePath from '@libs/Navigation/helpers/normalizePath'; import {shallowCompare} from '@libs/ObjectUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import linkingConfig from '@navigation/linkingConfig'; diff --git a/src/libs/Navigation/linkTo/types.ts b/src/libs/Navigation/helpers/linkTo/types.ts similarity index 100% rename from src/libs/Navigation/linkTo/types.ts rename to src/libs/Navigation/helpers/linkTo/types.ts diff --git a/src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts b/src/libs/Navigation/helpers/setupCustomAndroidBackHandler/index.android.ts similarity index 100% rename from src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts rename to src/libs/Navigation/helpers/setupCustomAndroidBackHandler/index.android.ts diff --git a/src/libs/Navigation/setupCustomAndroidBackHandler/index.ts b/src/libs/Navigation/helpers/setupCustomAndroidBackHandler/index.ts similarity index 100% rename from src/libs/Navigation/setupCustomAndroidBackHandler/index.ts rename to src/libs/Navigation/helpers/setupCustomAndroidBackHandler/index.ts diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 2179799c788b..fdc4fc712de2 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -74,9 +74,9 @@ import * as Localize from './Localize'; import Log from './Log'; import {isEmailPublicDomain} from './LoginUtils'; import ModifiedExpenseMessage from './ModifiedExpenseMessage'; +import {isFullScreenName} from './Navigation/helpers/isNavigatorName'; import linkingConfig from './Navigation/linkingConfig'; import Navigation, {navigationRef} from './Navigation/Navigation'; -import {isFullScreenName} from './NavigationUtils'; import * as NumberUtils from './NumberUtils'; import Parser from './Parser'; import Permissions from './Permissions'; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 5be8ed0a0eed..40d62d5d5559 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -67,8 +67,8 @@ import isPublicScreenRoute from '@libs/isPublicScreenRoute'; import * as Localize from '@libs/Localize'; import Log from '@libs/Log'; import {registerPaginationConfig} from '@libs/Middleware/Pagination'; +import {isOnboardingFlowName} from '@libs/Navigation/helpers'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; -import {isOnboardingFlowName} from '@libs/NavigationUtils'; import enhanceParameters from '@libs/Network/enhanceParameters'; import type {NetworkStatus} from '@libs/NetworkConnection'; import LocalNotification from '@libs/Notification/LocalNotification'; diff --git a/src/pages/AddPersonalBankAccountPage.tsx b/src/pages/AddPersonalBankAccountPage.tsx index cd8d3817c927..8c7ba7e9af14 100644 --- a/src/pages/AddPersonalBankAccountPage.tsx +++ b/src/pages/AddPersonalBankAccountPage.tsx @@ -10,8 +10,8 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import getPlaidOAuthReceivedRedirectURI from '@libs/getPlaidOAuthReceivedRedirectURI'; +import {isFullScreenName} from '@libs/Navigation/helpers'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; -import {isFullScreenName} from '@libs/NavigationUtils'; import * as BankAccounts from '@userActions/BankAccounts'; import * as PaymentMethods from '@userActions/PaymentMethods'; import NAVIGATORS from '@src/NAVIGATORS'; From e8749f4ddf816ae804323eaa50e143392d8c552c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 26 Nov 2024 14:42:59 +0100 Subject: [PATCH 194/257] Make goUp private --- src/libs/Navigation/Navigation.ts | 16 ++++++++++------ src/pages/home/sidebar/BottomTabAvatar.tsx | 4 ++-- .../request/step/IOURequestStepConfirmation.tsx | 2 +- .../PersonalDetails/CountrySelectionPage.tsx | 2 +- .../PersonalDetails/StateSelectionPage.tsx | 2 +- .../Subscription/CardSection/CardSection.tsx | 2 +- src/pages/workspace/AccessOrNotFoundWrapper.tsx | 2 +- src/pages/workspace/WorkspaceInitialPage.tsx | 6 +++--- .../workspace/WorkspacePageWithSections.tsx | 4 ++-- src/pages/workspace/WorkspacesListPage.tsx | 4 ++-- .../expensifyCard/issueNew/ConfirmationStep.tsx | 2 +- 11 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 48229b9a2ef4..9f3eeb43aedf 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -186,23 +186,26 @@ function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | Navi return shallowCompare(routeParams, minimalActionParams); } -type GoUpOptions = { +type GoBackOptions = { /** If we should compare params when searching for a route in state to go up to. * There are situations where we want to compare params when going up e.g. goUp to a specific report. * Sometimes we want to go up and update params of screen e.g. country picker. * In that case we want to goUp to a country picker with any params so we don't compare them. */ compareParams?: boolean; + + shouldPopToTop?: boolean; }; -const defaultGoUpOptions: Required = { +const defaultGoUpOptions: Required = { compareParams: true, + shouldPopToTop: false, }; function isRootNavigatorState(state: State): state is State { return state.key === navigationRef.current?.getRootState().key; } -function goUp(fallbackRoute: Route, options?: GoUpOptions) { +function goUp(fallbackRoute: Route, options?: GoBackOptions) { const compareParams = options?.compareParams ?? defaultGoUpOptions.compareParams; if (!canNavigate('goBack')) { @@ -253,11 +256,13 @@ function goUp(fallbackRoute: Route, options?: GoUpOptions) { * @param fallbackRoute - Fallback route if pop/goBack action should, but is not possible within RHP * @param shouldPopToTop - Should we navigate to LHN on back press */ -function goBack(fallbackRoute?: Route, shouldPopToTop = false) { +function goBack(fallbackRoute?: Route, options?: GoBackOptions) { if (!canNavigate('goBack')) { return; } + const shouldPopToTop = options?.shouldPopToTop ?? false; + if (shouldPopToTop) { if (shouldPopAllStateOnUP) { shouldPopAllStateOnUP = false; @@ -267,7 +272,7 @@ function goBack(fallbackRoute?: Route, shouldPopToTop = false) { } if (fallbackRoute) { - goUp(fallbackRoute); + goUp(fallbackRoute, options); return; } @@ -485,7 +490,6 @@ export default { closeRHPFlow, setNavigationActionToMicrotaskQueue, navigateToReportWithPolicyCheck, - goUp, }; export {navigationRef}; diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index 631287f544a8..0d93b3ff5a87 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -45,12 +45,12 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT } if (route.name === SCREENS.SETTINGS.WORKSPACES && shouldUseNarrowLayout) { - Navigation.goUp(ROUTES.SETTINGS); + Navigation.goBack(ROUTES.SETTINGS); return; } if (route.name === SCREENS.WORKSPACE.INITIAL) { - Navigation.goUp(ROUTES.SETTINGS); + Navigation.goBack(ROUTES.SETTINGS); if (shouldUseNarrowLayout) { Navigation.navigate(ROUTES.SETTINGS, CONST.NAVIGATION.ACTION_TYPE.REPLACE); } diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index ccdbe7ebdf29..ab1f27f163f9 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -184,7 +184,7 @@ function IOURequestStepConfirmation({ // back to the participants step if (!transaction?.participantsAutoAssigned && participantsAutoAssignedFromRoute !== 'true') { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - Navigation.goUp(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, transaction?.reportID || reportID, undefined, action), {compareParams: false}); + Navigation.goBack(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, transaction?.reportID || reportID, undefined, action), {compareParams: false}); return; } IOUUtils.navigateToStartMoneyRequestStep(requestType, iouType, transactionID, reportID, action); diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx index 28af0b5d4364..303ffa1c9967 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.tsx @@ -50,7 +50,7 @@ function CountrySelectionPage({route}: CountrySelectionPageProps) { Navigation.goBack(); } else { // Set compareParams to false because we want to goUp to this particular screen and update params (country). - Navigation.goUp(appendParam(backTo, 'country', option.value), {compareParams: false}); + Navigation.goBack(appendParam(backTo, 'country', option.value), {compareParams: false}); } }, [route], diff --git a/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx b/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx index 390b48f0d995..14a3248d2c80 100644 --- a/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx +++ b/src/pages/settings/Profile/PersonalDetails/StateSelectionPage.tsx @@ -60,7 +60,7 @@ function StateSelectionPage() { Navigation.goBack(); } else { // Set compareParams to false because we want to goUp to this particular screen and update params (state). - Navigation.goUp(appendParam(backTo, 'state', option.value), {compareParams: false}); + Navigation.goBack(appendParam(backTo, 'state', option.value), {compareParams: false}); } }, [params?.backTo], diff --git a/src/pages/settings/Subscription/CardSection/CardSection.tsx b/src/pages/settings/Subscription/CardSection/CardSection.tsx index 947a2d10f777..80381a345ff9 100644 --- a/src/pages/settings/Subscription/CardSection/CardSection.tsx +++ b/src/pages/settings/Subscription/CardSection/CardSection.tsx @@ -57,7 +57,7 @@ function CardSection() { const requestRefund = useCallback(() => { User.requestRefund(); setIsRequestRefundModalVisible(false); - Navigation.goUp(ROUTES.HOME); + Navigation.goBack(ROUTES.HOME); }, []); const viewPurchases = useCallback(() => { diff --git a/src/pages/workspace/AccessOrNotFoundWrapper.tsx b/src/pages/workspace/AccessOrNotFoundWrapper.tsx index 83a24e2084d3..39ac7b2f9451 100644 --- a/src/pages/workspace/AccessOrNotFoundWrapper.tsx +++ b/src/pages/workspace/AccessOrNotFoundWrapper.tsx @@ -98,7 +98,7 @@ function PageNotFoundFallback({policyID, fullPageNotFoundViewProps, isFeatureEna shouldForceFullScreen={shouldShowFullScreenFallback} onBackButtonPress={() => { if (isPolicyNotAccessible) { - Navigation.goUp(ROUTES.SETTINGS_WORKSPACES); + Navigation.goBack(ROUTES.SETTINGS_WORKSPACES); return; } Navigation.goBack(policyID && !isMoneyRequest ? ROUTES.WORKSPACE_PROFILE.getRoute(policyID) : undefined); diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 952293b540b4..a858f42a7e6e 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -398,7 +398,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac > Navigation.goUp(ROUTES.HOME)} + onLinkPress={() => Navigation.goBack(ROUTES.HOME)} shouldShow={shouldShowNotFoundPage} subtitleKey={shouldShowPolicy ? 'workspace.common.notAuthorized' : undefined} > @@ -406,10 +406,10 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac title={policyName} onBackButtonPress={() => { if (route.params?.backTo) { - Navigation.goUp(ROUTES.HOME); + Navigation.goBack(ROUTES.HOME); Navigation.isNavigationReady().then(() => Navigation.navigate(route.params?.backTo as Route)); } else { - Navigation.goUp(ROUTES.SETTINGS_WORKSPACES); + Navigation.goBack(ROUTES.SETTINGS_WORKSPACES); } }} policyAvatar={policyAvatar} diff --git a/src/pages/workspace/WorkspacePageWithSections.tsx b/src/pages/workspace/WorkspacePageWithSections.tsx index 6ebe98d0bef6..a74c9fcef02a 100644 --- a/src/pages/workspace/WorkspacePageWithSections.tsx +++ b/src/pages/workspace/WorkspacePageWithSections.tsx @@ -174,8 +174,8 @@ function WorkspacePageWithSections({ shouldShowOfflineIndicatorInWideScreen={shouldShowOfflineIndicatorInWideScreen && !shouldShow} > Navigation.goUp(ROUTES.SETTINGS_WORKSPACES)} - onLinkPress={() => Navigation.goUp(ROUTES.HOME)} + onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_WORKSPACES)} + onLinkPress={() => Navigation.goBack(ROUTES.HOME)} shouldShow={shouldShow} subtitleKey={shouldShowPolicy ? 'workspace.common.notAuthorized' : undefined} shouldForceFullScreen diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 4db55d08b290..17e9800f2924 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -395,7 +395,7 @@ function WorkspacesListPage() { title={translate('common.workspaces')} shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter - onBackButtonPress={() => Navigation.goUp(ROUTES.SETTINGS)} + onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS)} icon={Illustrations.BigRocket} /> @@ -430,7 +430,7 @@ function WorkspacesListPage() { title={translate('common.workspaces')} shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter - onBackButtonPress={() => Navigation.goUp(ROUTES.SETTINGS)} + onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS)} icon={Illustrations.BigRocket} > {!shouldUseNarrowLayout && getHeaderButton()} diff --git a/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx b/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx index 0b574c64c673..f168f0617af1 100644 --- a/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx +++ b/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx @@ -57,7 +57,7 @@ function ConfirmationStep({policyID, backTo}: ConfirmationStepProps) { if (!isSuccessful) { return; } - Navigation.goUp(backTo ?? ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID ?? '-1')); + Navigation.goBack(backTo ?? ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID ?? '-1')); Card.clearIssueNewCardFlow(); }, [backTo, policyID, isSuccessful]); From 3ed172efa7c67f630bff8cb881184c9d18b0d8b1 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 26 Nov 2024 15:01:26 +0100 Subject: [PATCH 195/257] Rename SplitNavigatorLHNScreen to SplitNavigatorSidebarScreen --- src/libs/Navigation/helpers/createSplitNavigator.ts | 6 +++--- src/libs/Navigation/helpers/isNavigatorName.ts | 4 ++-- .../Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts | 6 +++--- .../linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts | 4 ++-- src/libs/Navigation/types.ts | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libs/Navigation/helpers/createSplitNavigator.ts b/src/libs/Navigation/helpers/createSplitNavigator.ts index a43e5a83d7ab..8ceb765b9922 100644 --- a/src/libs/Navigation/helpers/createSplitNavigator.ts +++ b/src/libs/Navigation/helpers/createSplitNavigator.ts @@ -1,13 +1,13 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; import LHN_TO_SPLIT_NAVIGATOR_NAME from '@libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING'; -import type {NavigationPartialRoute, SplitNavigatorByLHN, SplitNavigatorLHNScreen, SplitNavigatorParamListType} from '@libs/Navigation/types'; +import type {NavigationPartialRoute, SplitNavigatorByLHN, SplitNavigatorParamListType, SplitNavigatorSidebarScreen} from '@libs/Navigation/types'; -type ExtractRouteType = Extract; +type ExtractRouteType = Extract; // The function getPathFromState that we are using in some places isn't working correctly without defined index. const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState => ({routes, index: routes.length - 1}); -function createSplitNavigator( +function createSplitNavigator( splitNavigatorLHN: NavigationPartialRoute, route?: NavigationPartialRoute>, splitNavigatorParams?: Record, diff --git a/src/libs/Navigation/helpers/isNavigatorName.ts b/src/libs/Navigation/helpers/isNavigatorName.ts index 49bada1dc286..ae5118b9833e 100644 --- a/src/libs/Navigation/helpers/isNavigatorName.ts +++ b/src/libs/Navigation/helpers/isNavigatorName.ts @@ -1,4 +1,4 @@ -import type {FullScreenName, OnboardingFlowName, SplitNavigatorLHNScreen, SplitNavigatorName} from '@libs/Navigation/types'; +import type {FullScreenName, OnboardingFlowName, SplitNavigatorName, SplitNavigatorSidebarScreen} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; @@ -39,7 +39,7 @@ function isFullScreenName(screen: string | undefined) { } function isSidebarScreenName(screen: string | undefined) { - return checkIfScreenHasMatchingNameToSetValues(screen, SIDEBARS_SET); + return checkIfScreenHasMatchingNameToSetValues(screen, SIDEBARS_SET); } export {isFullScreenName, isOnboardingFlowName, isSidebarScreenName, isSplitNavigatorName}; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts index a07ef3b8b9ac..1923b50b4ea2 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts @@ -1,9 +1,9 @@ -import type {SplitNavigatorLHNScreen} from '@libs/Navigation/types'; +import type {SplitNavigatorSidebarScreen} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; -// This file is used to define the relationship between the sidebar (LHN) and the right hand pane (RHP) screen. +// This file is used to define the relationship between the sidebar and the right hand pane (RHP) screen. // These screens don't care about the split navigator's central screen and are in relation directly to the sidebar. -const SIDEBAR_TO_RHP: Partial> = { +const SIDEBAR_TO_RHP: Partial> = { [SCREENS.SETTINGS.ROOT]: [ SCREENS.SETTINGS.SHARE_CODE, SCREENS.SETTINGS.PROFILE.STATUS, diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts index 943552f929b8..d5c1b6089812 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts @@ -1,8 +1,8 @@ // @TODO Remove this file before merging to the main. -import type {SplitNavigatorLHNScreen, SplitNavigatorScreenName} from '@navigation/types'; +import type {SplitNavigatorScreenName, SplitNavigatorSidebarScreen} from '@navigation/types'; import SCREENS from '@src/SCREENS'; -const TAB_TO_CENTRAL_PANE_MAPPING: Record = { +const TAB_TO_CENTRAL_PANE_MAPPING: Record = { [SCREENS.HOME]: [SCREENS.REPORT], [SCREENS.SETTINGS.ROOT]: [ SCREENS.SETTINGS.PROFILE.ROOT, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 304aa93c13f0..9483ae20274e 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -53,7 +53,7 @@ type NavigationPartialRoute = PartialRoute = NavigationState | PartialState>; -type SplitNavigatorLHNScreen = keyof typeof LHN_TO_SPLIT_NAVIGATOR_NAME; +type SplitNavigatorSidebarScreen = keyof typeof LHN_TO_SPLIT_NAVIGATOR_NAME; type SplitNavigatorParamListType = { [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: SettingsSplitNavigatorParamList; @@ -61,7 +61,7 @@ type SplitNavigatorParamListType = { [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: WorkspaceSplitNavigatorParamList; }; -type SplitNavigatorByLHN = (typeof LHN_TO_SPLIT_NAVIGATOR_NAME)[T]; +type SplitNavigatorByLHN = (typeof LHN_TO_SPLIT_NAVIGATOR_NAME)[T]; type CentralPaneScreensParamList = { [SCREENS.REPORT]: { @@ -1810,7 +1810,7 @@ export type { SplitNavigatorName, SplitNavigatorScreenName, FullScreenName, - SplitNavigatorLHNScreen, + SplitNavigatorSidebarScreen, SplitNavigatorParamListType, SplitNavigatorByLHN, }; From dd7a57c17015c96d969315eee95e205f4ae0e6bf Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 26 Nov 2024 15:39:17 +0100 Subject: [PATCH 196/257] Rename createSplitNavigator to getInitialSplitNavigatorState --- .../getInitialSplitNavigatorState.ts} | 4 ++-- src/libs/Navigation/Navigation.ts | 4 ++-- src/libs/Navigation/helpers/getAdaptedStateFromPath.ts | 10 +++++----- src/libs/Navigation/helpers/index.ts | 1 - 4 files changed, 9 insertions(+), 10 deletions(-) rename src/libs/Navigation/{helpers/createSplitNavigator.ts => AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState.ts} (90%) diff --git a/src/libs/Navigation/helpers/createSplitNavigator.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState.ts similarity index 90% rename from src/libs/Navigation/helpers/createSplitNavigator.ts rename to src/libs/Navigation/AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState.ts index 8ceb765b9922..de272f67d926 100644 --- a/src/libs/Navigation/helpers/createSplitNavigator.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState.ts @@ -7,7 +7,7 @@ type ExtractRouteType = Extract => ({routes, index: routes.length - 1}); -function createSplitNavigator( +function getInitialSplitNavigatorState( splitNavigatorLHN: NavigationPartialRoute, route?: NavigationPartialRoute>, splitNavigatorParams?: Record, @@ -26,4 +26,4 @@ function createSplitNavigator( }; } -export default createSplitNavigator; +export default getInitialSplitNavigatorState; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 9f3eeb43aedf..2f682112ee9d 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -19,8 +19,8 @@ import ROUTES, {HYBRID_APP_ROUTES} from '@src/ROUTES'; import SCREENS, {PROTECTED_SCREENS} from '@src/SCREENS'; import type {Report} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import getInitialSplitNavigatorState from './AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState'; import { - createSplitNavigator, getMinimalAction, getPolicyIDFromState, getStateFromPath, @@ -314,7 +314,7 @@ function resetToHome() { name: SCREENS.REPORT, } : undefined; - const payload = createSplitNavigator({name: SCREENS.HOME}, splitNavigatorMainScreen); + const payload = getInitialSplitNavigatorState({name: SCREENS.HOME}, splitNavigatorMainScreen); navigationRef.dispatch({payload, type: 'REPLACE', target: rootState.key}); } diff --git a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts index 7122bc8b75e0..c7a712f0fd7a 100644 --- a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts @@ -2,6 +2,7 @@ import type {NavigationState, PartialState, Route} from '@react-navigation/nativ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import pick from 'lodash/pick'; import {isAnonymousUser} from '@libs/actions/Session'; +import getInitialSplitNavigatorState from '@libs/Navigation/AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState'; import config from '@libs/Navigation/linkingConfig/config'; import RELATIONS from '@libs/Navigation/linkingConfig/RELATIONS'; import type {NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; @@ -10,7 +11,6 @@ import * as ReportConnection from '@libs/ReportConnection'; import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import SCREENS from '@src/SCREENS'; -import createSplitNavigator from './createSplitNavigator'; import extractPolicyIDFromQuery from './extractPolicyIDFromQuery'; import getParamsFromRoute from './getParamsFromRoute'; import {isFullScreenName} from './isNavigatorName'; @@ -70,7 +70,7 @@ function getMatchingFullScreenRoute(route: NavigationPartialRoute, policyID?: st } if (RELATIONS.RHP_TO_SIDEBAR[route.name]) { - return createSplitNavigator( + return getInitialSplitNavigatorState( { name: RELATIONS.RHP_TO_SIDEBAR[route.name], }, @@ -82,7 +82,7 @@ function getMatchingFullScreenRoute(route: NavigationPartialRoute, policyID?: st if (RELATIONS.RHP_TO_WORKSPACE[route.name]) { const paramsFromRoute = getParamsFromRoute(RELATIONS.RHP_TO_WORKSPACE[route.name]); - return createSplitNavigator( + return getInitialSplitNavigatorState( { name: SCREENS.WORKSPACE.INITIAL, params: paramsFromRoute.length > 0 ? pick(route.params, paramsFromRoute) : undefined, @@ -97,7 +97,7 @@ function getMatchingFullScreenRoute(route: NavigationPartialRoute, policyID?: st if (RELATIONS.RHP_TO_SETTINGS[route.name]) { const paramsFromRoute = getParamsFromRoute(RELATIONS.RHP_TO_SETTINGS[route.name]); - return createSplitNavigator( + return getInitialSplitNavigatorState( { name: SCREENS.SETTINGS.ROOT, }, @@ -128,7 +128,7 @@ function getDefaultFullScreenRoute(route?: NavigationPartialRoute, policyID?: st return fallbackRoute; } - return createSplitNavigator( + return getInitialSplitNavigatorState( { name: SCREENS.HOME, }, diff --git a/src/libs/Navigation/helpers/index.ts b/src/libs/Navigation/helpers/index.ts index 46a977002326..d3756c09b877 100644 --- a/src/libs/Navigation/helpers/index.ts +++ b/src/libs/Navigation/helpers/index.ts @@ -3,7 +3,6 @@ export * from './isNavigatorName'; export * from './linkTo/types'; export {default as closeRHPFlow} from './closeRHPFlow'; export {default as createNormalizedConfigs} from './createNormalizedConfigs'; -export {default as createSplitNavigator} from './createSplitNavigator'; export {default as customGetPathFromState} from './customGetPathFromState'; export {default as extractPolicyIDFromQuery} from './extractPolicyIDFromQuery'; export {default as getAdaptedStateFromPath} from './getAdaptedStateFromPath'; From 2afede2b8fb6fd39ae493a64a2175cc6e932b811 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 26 Nov 2024 15:48:00 +0100 Subject: [PATCH 197/257] Fix goBack calls with shouldPopToTop --- src/libs/actions/Report.ts | 2 +- src/libs/navigateAfterJoinRequest/index.desktop.ts | 2 +- src/libs/navigateAfterJoinRequest/index.ts | 2 +- src/libs/navigateAfterJoinRequest/index.web.ts | 2 +- src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx | 4 ++-- src/pages/EnablePayments/EnablePayments.tsx | 2 +- src/pages/home/ReportScreen.tsx | 4 ++-- src/pages/workspace/WorkspaceJoinUserPage.tsx | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 40d62d5d5559..e62891dba5cb 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2422,7 +2422,7 @@ function navigateToConciergeChatAndDeleteReport(reportID: string, shouldPopToTop Navigation.setShouldPopAllStateOnUP(true); } // @TODO: Check if this method works the same as on the main branch - Navigation.goBack(undefined, shouldPopToTop); + Navigation.goBack(undefined, {shouldPopToTop}); navigateToConciergeChat(); InteractionManager.runAfterInteractions(() => { deleteReport(reportID, shouldDeleteChildReports); diff --git a/src/libs/navigateAfterJoinRequest/index.desktop.ts b/src/libs/navigateAfterJoinRequest/index.desktop.ts index 15ebdca70a44..9b72ee30de57 100644 --- a/src/libs/navigateAfterJoinRequest/index.desktop.ts +++ b/src/libs/navigateAfterJoinRequest/index.desktop.ts @@ -4,7 +4,7 @@ import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { // @TODO: Check if this method works the same as on the main branch - Navigation.goBack(undefined, true); + Navigation.goBack(undefined, {shouldPopToTop: true}); if (getIsSmallScreenWidth()) { Navigation.navigate(ROUTES.SETTINGS); } diff --git a/src/libs/navigateAfterJoinRequest/index.ts b/src/libs/navigateAfterJoinRequest/index.ts index 0425f52c1e56..a3ac50cd59be 100644 --- a/src/libs/navigateAfterJoinRequest/index.ts +++ b/src/libs/navigateAfterJoinRequest/index.ts @@ -3,7 +3,7 @@ import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { // @TODO: Check if this method works the same as on the main branch - Navigation.goBack(undefined, true); + Navigation.goBack(undefined, {shouldPopToTop: true}); Navigation.navigate(ROUTES.SETTINGS); Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); }; diff --git a/src/libs/navigateAfterJoinRequest/index.web.ts b/src/libs/navigateAfterJoinRequest/index.web.ts index 15ebdca70a44..9b72ee30de57 100644 --- a/src/libs/navigateAfterJoinRequest/index.web.ts +++ b/src/libs/navigateAfterJoinRequest/index.web.ts @@ -4,7 +4,7 @@ import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { // @TODO: Check if this method works the same as on the main branch - Navigation.goBack(undefined, true); + Navigation.goBack(undefined, {shouldPopToTop: true}); if (getIsSmallScreenWidth()) { Navigation.navigate(ROUTES.SETTINGS); } diff --git a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx index 55f19f8c35b9..060d5664ac93 100644 --- a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx +++ b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx @@ -52,7 +52,7 @@ function AddBankAccount() { PaymentMethods.continueSetup(onSuccessFallbackRoute); return; } - Navigation.goBack(ROUTES.SETTINGS_WALLET, true); + Navigation.goBack(ROUTES.SETTINGS_WALLET, {shouldPopToTop: true}); }; const handleBackButtonPress = () => { @@ -63,7 +63,7 @@ function AddBankAccount() { if (screenIndex === 0) { BankAccounts.clearPersonalBankAccount(); Wallet.updateCurrentStep(null); - Navigation.goBack(ROUTES.SETTINGS_WALLET, true); + Navigation.goBack(ROUTES.SETTINGS_WALLET, {shouldPopToTop: true}); return; } prevScreen(); diff --git a/src/pages/EnablePayments/EnablePayments.tsx b/src/pages/EnablePayments/EnablePayments.tsx index 357a2be9b1e0..b8aeb4103a59 100644 --- a/src/pages/EnablePayments/EnablePayments.tsx +++ b/src/pages/EnablePayments/EnablePayments.tsx @@ -46,7 +46,7 @@ function EnablePaymentsPage() { > Navigation.goBack(ROUTES.SETTINGS_WALLET, true)} + onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_WALLET, {shouldPopToTop: true})} /> diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 6d956d95829e..de66614c82c4 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -295,7 +295,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro return; } // @TODO: Check if this method works the same as on the main branch - Navigation.goBack(undefined, true); + Navigation.goBack(undefined, {shouldPopToTop: true}); }, [isInNarrowPaneModal]); let headerView = ( @@ -592,7 +592,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro if (Navigation.getTopmostReportId() === prevOnyxReportID) { Navigation.setShouldPopAllStateOnUP(true); // @TODO: Check if this method works the same as on the main branch - Navigation.goBack(undefined, true); + Navigation.goBack(undefined, {shouldPopToTop: true}); } if (prevReport?.parentReportID) { // Prevent navigation to the IOU/Expense Report if it is pending deletion. diff --git a/src/pages/workspace/WorkspaceJoinUserPage.tsx b/src/pages/workspace/WorkspaceJoinUserPage.tsx index 9c79e02d40fc..66caff7263ef 100644 --- a/src/pages/workspace/WorkspaceJoinUserPage.tsx +++ b/src/pages/workspace/WorkspaceJoinUserPage.tsx @@ -47,7 +47,7 @@ function WorkspaceJoinUserPage({route, policy}: WorkspaceJoinUserPageProps) { Navigation.isNavigationReady().then(() => { // @TODO: Check if this method works the same as on the main branch // NOTE: It probably doesn't need any params. When this method is called, shouldPopAllStateOnUP is always false - Navigation.goBack(undefined, true); + Navigation.goBack(undefined, {shouldPopToTop: true}); Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID ?? '-1')); }); return; From 3afe817a754af2df0361833eaa446fa6dea286f2 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 26 Nov 2024 17:07:32 +0100 Subject: [PATCH 198/257] Remove LHN_TO_SPLIT_NAVIGATOR_MAPPING --- .../getInitialSplitNavigatorState.ts | 14 +++--- src/libs/Navigation/Navigation.ts | 4 +- .../LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts | 11 ----- src/libs/Navigation/types.ts | 48 +++++++++---------- 4 files changed, 33 insertions(+), 44 deletions(-) delete mode 100644 src/libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState.ts index de272f67d926..65ca59f9d8db 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState.ts @@ -1,26 +1,26 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; -import LHN_TO_SPLIT_NAVIGATOR_NAME from '@libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING'; -import type {NavigationPartialRoute, SplitNavigatorByLHN, SplitNavigatorParamListType, SplitNavigatorSidebarScreen} from '@libs/Navigation/types'; +import SIDEBAR_TO_SPLIT from '@libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT'; +import type {NavigationPartialRoute, SplitNavigatorBySidebar, SplitNavigatorParamListType, SplitNavigatorSidebarScreen} from '@libs/Navigation/types'; -type ExtractRouteType = Extract; +type ExtractRouteType = Extract; // The function getPathFromState that we are using in some places isn't working correctly without defined index. const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState => ({routes, index: routes.length - 1}); function getInitialSplitNavigatorState( - splitNavigatorLHN: NavigationPartialRoute, + splitNavigatorSidebarRoute: NavigationPartialRoute, route?: NavigationPartialRoute>, splitNavigatorParams?: Record, -): NavigationPartialRoute> { +): NavigationPartialRoute> { const routes = []; - routes.push(splitNavigatorLHN); + routes.push(splitNavigatorSidebarRoute); if (route) { routes.push(route); } return { - name: LHN_TO_SPLIT_NAVIGATOR_NAME[splitNavigatorLHN.name], + name: SIDEBAR_TO_SPLIT[splitNavigatorSidebarRoute.name], state: getRoutesWithIndex(routes), params: splitNavigatorParams, }; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 2f682112ee9d..8f59b828bdd3 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -196,7 +196,7 @@ type GoBackOptions = { shouldPopToTop?: boolean; }; -const defaultGoUpOptions: Required = { +const defaultGoBackOptions: Required = { compareParams: true, shouldPopToTop: false, }; @@ -206,7 +206,7 @@ function isRootNavigatorState(state: State): state is State } function goUp(fallbackRoute: Route, options?: GoBackOptions) { - const compareParams = options?.compareParams ?? defaultGoUpOptions.compareParams; + const compareParams = options?.compareParams ?? defaultGoBackOptions.compareParams; if (!canNavigate('goBack')) { return; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts deleted file mode 100644 index 2871d34adaf8..000000000000 --- a/src/libs/Navigation/linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING.ts +++ /dev/null @@ -1,11 +0,0 @@ -// @TODO remove this file before merging to the main. -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; - -const LHN_TO_SPLIT_NAVIGATOR_NAME = { - [SCREENS.SETTINGS.ROOT]: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, - [SCREENS.HOME]: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, - [SCREENS.WORKSPACE.INITIAL]: NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, -}; - -export default LHN_TO_SPLIT_NAVIGATOR_NAME; diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 9483ae20274e..417663088dbe 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -22,7 +22,7 @@ import type SCREENS from '@src/SCREENS'; import type EXIT_SURVEY_REASON_FORM_INPUT_IDS from '@src/types/form/ExitSurveyReasonForm'; import type {CompanyCardFeed} from '@src/types/onyx'; import type {ConnectionName, SageIntacctMappingName} from '@src/types/onyx/Policy'; -import type LHN_TO_SPLIT_NAVIGATOR_NAME from './linkingConfig/RELATIONS/LHN_TO_SPLIT_NAVIGATOR_MAPPING'; +import type SIDEBAR_TO_SPLIT from './linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT'; type NavigationRef = NavigationContainerRefWithCurrent; @@ -53,7 +53,7 @@ type NavigationPartialRoute = PartialRoute = NavigationState | PartialState>; -type SplitNavigatorSidebarScreen = keyof typeof LHN_TO_SPLIT_NAVIGATOR_NAME; +type SplitNavigatorSidebarScreen = keyof typeof SIDEBAR_TO_SPLIT; type SplitNavigatorParamListType = { [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: SettingsSplitNavigatorParamList; @@ -61,7 +61,7 @@ type SplitNavigatorParamListType = { [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: WorkspaceSplitNavigatorParamList; }; -type SplitNavigatorByLHN = (typeof LHN_TO_SPLIT_NAVIGATOR_NAME)[T]; +type SplitNavigatorBySidebar = (typeof SIDEBAR_TO_SPLIT)[T]; type CentralPaneScreensParamList = { [SCREENS.REPORT]: { @@ -1752,18 +1752,20 @@ declare global { export type { AddPersonalBankAccountNavigatorParamList, AuthScreensParamList, - CentralPaneScreensParamList, - CentralPaneName, - BackToParams, BackToAndForwardToParms, + BackToParams, + CentralPaneName, + CentralPaneScreensParamList, + DebugParamList, DetailsNavigatorParamList, EditRequestNavigatorParamList, EnablePaymentsNavigatorParamList, ExplanationModalNavigatorParamList, + FeatureTrainingNavigatorParamList, FlagCommentNavigatorParamList, - WorkspaceScreenName, - WorkspaceSplitNavigatorParamList, + FullScreenName, LeftModalNavigatorParamList, + MissingPersonalDetailsParamList, MoneyRequestNavigatorParamList, NavigationPartialRoute, NavigationRef, @@ -1771,8 +1773,8 @@ export type { NavigationStateRoute, NewChatNavigatorParamList, NewTaskNavigatorParamList, - OnboardingModalNavigatorParamList, OnboardingFlowName, + OnboardingModalNavigatorParamList, ParticipantsNavigatorParamList, PrivateNotesNavigatorParamList, ProfileNavigatorParamList, @@ -1783,34 +1785,32 @@ export type { ReportDetailsNavigatorParamList, ReportSettingsNavigatorParamList, ReportsSplitNavigatorParamList, + RestrictedActionParamList, RightModalNavigatorParamList, RoomMembersNavigatorParamList, RootStackParamList, + SearchAdvancedFiltersParamList, + SearchReportParamList, + SearchSavedSearchParamList, SettingsNavigatorParamList, SettingsSplitNavigatorParamList, SignInNavigatorParamList, - FeatureTrainingNavigatorParamList, SplitDetailsNavigatorParamList, + SplitNavigatorBySidebar, + SplitNavigatorName, + SplitNavigatorParamListType, + SplitNavigatorScreenName, + SplitNavigatorSidebarScreen, StackNavigationAction, State, StateOrRoute, SwitchPolicyIDParams, - TravelNavigatorParamList, TaskDetailsNavigatorParamList, TeachersUniteNavigatorParamList, + TransactionDuplicateNavigatorParamList, + TravelNavigatorParamList, WalletStatementNavigatorParamList, WelcomeVideoModalNavigatorParamList, - TransactionDuplicateNavigatorParamList, - SearchReportParamList, - SearchAdvancedFiltersParamList, - SearchSavedSearchParamList, - RestrictedActionParamList, - MissingPersonalDetailsParamList, - DebugParamList, - SplitNavigatorName, - SplitNavigatorScreenName, - FullScreenName, - SplitNavigatorSidebarScreen, - SplitNavigatorParamListType, - SplitNavigatorByLHN, + WorkspaceScreenName, + WorkspaceSplitNavigatorParamList, }; From 324b59859e7ff28b07a92b7a47abd013c687ef00 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 27 Nov 2024 08:17:25 +0100 Subject: [PATCH 199/257] Cleanup navigation types and remove redundant mapping files --- .../Navigation/AppNavigator/AuthScreens.tsx | 2 +- .../createResponsiveStackNavigator/index.tsx | 2 +- .../RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts | 46 ------- src/libs/Navigation/types.ts | 127 +++++++----------- 4 files changed, 49 insertions(+), 128 deletions(-) delete mode 100755 src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index f73f424ccacb..4100b58c4173 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -29,7 +29,6 @@ import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation'; import Presentation from '@libs/Navigation/PlatformStackNavigation/navigationOptions/presentation'; import type {AuthScreensParamList} from '@libs/Navigation/types'; -import {isOnboardingFlowName} from '@libs/NavigationUtils'; import NetworkConnection from '@libs/NetworkConnection'; import onyxSubscribe from '@libs/onyxSubscribe'; import * as Pusher from '@libs/Pusher/pusher'; @@ -58,6 +57,7 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; +import {isOnboardingFlowName} from '../helpers'; import createResponsiveStackNavigator from './createResponsiveStackNavigator'; import defaultScreenOptions from './defaultScreenOptions'; import ExplanationModalNavigator from './Navigators/ExplanationModalNavigator'; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx index 07920b5ad416..5662b394339c 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx @@ -1,10 +1,10 @@ import type {ParamListBase} from '@react-navigation/native'; import {createNavigatorFactory} from '@react-navigation/native'; import useNavigationResetOnLayoutChange from '@libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange'; +import {isFullScreenName} from '@libs/Navigation/helpers'; import createPlatformStackNavigatorComponent from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent'; import defaultPlatformStackScreenOptions from '@libs/Navigation/PlatformStackNavigation/defaultPlatformStackScreenOptions'; import type {CustomStateHookProps, PlatformStackNavigationEventMap, PlatformStackNavigationOptions, PlatformStackNavigationState} from '@libs/Navigation/PlatformStackNavigation/types'; -import {isFullScreenName} from '@libs/NavigationUtils'; import CustomRouter from './CustomRouter'; function useCustomRouterState({state}: CustomStateHookProps) { diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts deleted file mode 100755 index d5c1b6089812..000000000000 --- a/src/libs/Navigation/linkingConfig/RELATIONS/TAB_TO_CENTRAL_PANE_MAPPING.ts +++ /dev/null @@ -1,46 +0,0 @@ -// @TODO Remove this file before merging to the main. -import type {SplitNavigatorScreenName, SplitNavigatorSidebarScreen} from '@navigation/types'; -import SCREENS from '@src/SCREENS'; - -const TAB_TO_CENTRAL_PANE_MAPPING: Record = { - [SCREENS.HOME]: [SCREENS.REPORT], - [SCREENS.SETTINGS.ROOT]: [ - SCREENS.SETTINGS.PROFILE.ROOT, - SCREENS.SETTINGS.PREFERENCES.ROOT, - SCREENS.SETTINGS.SECURITY, - SCREENS.SETTINGS.WALLET.ROOT, - SCREENS.SETTINGS.ABOUT, - SCREENS.SETTINGS.WORKSPACES, - SCREENS.SETTINGS.SAVE_THE_WORLD, - SCREENS.SETTINGS.TROUBLESHOOT, - SCREENS.SETTINGS.SUBSCRIPTION.ROOT, - ], - [SCREENS.WORKSPACE.INITIAL]: [ - SCREENS.WORKSPACE.PROFILE, - SCREENS.WORKSPACE.MEMBERS, - SCREENS.WORKSPACE.WORKFLOWS, - SCREENS.WORKSPACE.ACCOUNTING.ROOT, - SCREENS.WORKSPACE.TAXES, - SCREENS.WORKSPACE.TAGS, - SCREENS.WORKSPACE.CATEGORIES, - SCREENS.WORKSPACE.DISTANCE_RATES, - SCREENS.WORKSPACE.REPORT_FIELDS, - SCREENS.WORKSPACE.INVOICES, - SCREENS.WORKSPACE.EXPENSIFY_CARD, - ], -}; - -const generateCentralPaneToTabMapping = (): Record => { - const mapping: Record = {} as Record; - for (const [tabName, CentralPaneNames] of Object.entries(TAB_TO_CENTRAL_PANE_MAPPING)) { - for (const CentralPaneName of CentralPaneNames) { - mapping[CentralPaneName] = tabName as SplitNavigatorScreenName; - } - } - return mapping; -}; - -const CENTRAL_PANE_TO_TAB_MAPPING: Record = generateCentralPaneToTabMapping(); - -export {CENTRAL_PANE_TO_TAB_MAPPING}; -export default TAB_TO_CENTRAL_PANE_MAPPING; diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 417663088dbe..4ddac42dd130 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -63,29 +63,6 @@ type SplitNavigatorParamListType = { type SplitNavigatorBySidebar = (typeof SIDEBAR_TO_SPLIT)[T]; -type CentralPaneScreensParamList = { - [SCREENS.REPORT]: { - reportActionID: string; - reportID: string; - openOnAdminRoom?: boolean; - referrer?: string; - }; - // [SCREENS.SETTINGS.WORKSPACES]: undefined; - [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; - // [SCREENS.SETTINGS.PROFILE.ROOT]: undefined; - [SCREENS.SETTINGS.SECURITY]: undefined; - // [SCREENS.SETTINGS.WALLET.ROOT]: undefined; - [SCREENS.SETTINGS.ABOUT]: undefined; - [SCREENS.SETTINGS.TROUBLESHOOT]: undefined; - - [SCREENS.SEARCH.CENTRAL_PANE]: { - q: SearchQueryString; - name?: string; - }; - // [SCREENS.SETTINGS.SAVE_THE_WORLD]: undefined; - [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: undefined; -}; - type BackToParams = { backTo?: Routes; }; @@ -1600,53 +1577,54 @@ type PublicScreensParamList = SharedScreensParamList & { [SCREENS.CONNECTION_COMPLETE]: undefined; }; -type AuthScreensParamList = CentralPaneScreensParamList & - SharedScreensParamList & { - [SCREENS.CONCIERGE]: undefined; - [SCREENS.TRACK_EXPENSE]: undefined; - [SCREENS.SUBMIT_EXPENSE]: undefined; - [SCREENS.ATTACHMENTS]: { - reportID: string; - source: string; - type: ValueOf; - accountID: string; - isAuthTokenRequired?: string; - fileName?: string; - attachmentLink?: string; - }; - [SCREENS.PROFILE_AVATAR]: { - accountID: string; - }; - [SCREENS.WORKSPACE_AVATAR]: { - policyID: string; - }; - [SCREENS.WORKSPACE_JOIN_USER]: { - policyID: string; - email: string; - }; - [SCREENS.REPORT_AVATAR]: { - reportID: string; - policyID?: string; - }; - [SCREENS.NOT_FOUND]: undefined; - [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: NavigatorScreenParams & {policyID?: string}; - [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: NavigatorScreenParams & {policyID?: string}; - [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: NavigatorScreenParams; - [NAVIGATORS.LEFT_MODAL_NAVIGATOR]: NavigatorScreenParams; - [NAVIGATORS.RIGHT_MODAL_NAVIGATOR]: NavigatorScreenParams; - [NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR]: NavigatorScreenParams; - [NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR]: NavigatorScreenParams; - [NAVIGATORS.WELCOME_VIDEO_MODAL_NAVIGATOR]: NavigatorScreenParams; - [NAVIGATORS.EXPLANATION_MODAL_NAVIGATOR]: NavigatorScreenParams; - [SCREENS.DESKTOP_SIGN_IN_REDIRECT]: undefined; - [SCREENS.TRANSACTION_RECEIPT]: { - reportID: string; - transactionID: string; - readonly?: string; - isFromReviewDuplicates?: string; - }; - [SCREENS.CONNECTION_COMPLETE]: undefined; +type AuthScreensParamList = SharedScreensParamList & { + [SCREENS.CONCIERGE]: undefined; + [SCREENS.TRACK_EXPENSE]: undefined; + [SCREENS.SUBMIT_EXPENSE]: undefined; + [SCREENS.ATTACHMENTS]: { + reportID: string; + source: string; + type: ValueOf; + accountID: string; + isAuthTokenRequired?: string; }; + [SCREENS.PROFILE_AVATAR]: { + accountID: string; + }; + [SCREENS.WORKSPACE_AVATAR]: { + policyID: string; + }; + [SCREENS.WORKSPACE_JOIN_USER]: { + policyID: string; + email: string; + }; + [SCREENS.REPORT_AVATAR]: { + reportID: string; + policyID?: string; + }; + [SCREENS.NOT_FOUND]: undefined; + [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: NavigatorScreenParams & {policyID?: string}; + [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: NavigatorScreenParams & {policyID?: string}; + [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: NavigatorScreenParams; + [NAVIGATORS.LEFT_MODAL_NAVIGATOR]: NavigatorScreenParams; + [NAVIGATORS.RIGHT_MODAL_NAVIGATOR]: NavigatorScreenParams; + [NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR]: NavigatorScreenParams; + [NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR]: NavigatorScreenParams; + [NAVIGATORS.WELCOME_VIDEO_MODAL_NAVIGATOR]: NavigatorScreenParams; + [NAVIGATORS.EXPLANATION_MODAL_NAVIGATOR]: NavigatorScreenParams; + [SCREENS.DESKTOP_SIGN_IN_REDIRECT]: undefined; + [SCREENS.TRANSACTION_RECEIPT]: { + reportID: string; + transactionID: string; + readonly?: string; + isFromReviewDuplicates?: string; + }; + [SCREENS.CONNECTION_COMPLETE]: undefined; + [SCREENS.SEARCH.CENTRAL_PANE]: { + q: SearchQueryString; + name?: string; + }; +}; type SearchReportParamList = { [SCREENS.SEARCH.REPORT_RHP]: { @@ -1725,8 +1703,6 @@ type RootStackParamList = PublicScreensParamList & AuthScreensParamList & LeftMo type WorkspaceScreenName = keyof WorkspaceSplitNavigatorParamList; -type CentralPaneName = keyof CentralPaneScreensParamList; - type OnboardingFlowName = keyof OnboardingModalNavigatorParamList; type SplitNavigatorName = keyof SplitNavigatorParamListType; @@ -1735,12 +1711,6 @@ type SplitNavigatorScreenName = keyof (WorkspaceSplitNavigatorParamList & Settin type FullScreenName = SplitNavigatorName | typeof SCREENS.SEARCH.CENTRAL_PANE; -type SwitchPolicyIDParams = { - policyID?: string; - route?: Routes; - isPolicyAdmin?: boolean; -}; - declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace ReactNavigation { @@ -1754,8 +1724,6 @@ export type { AuthScreensParamList, BackToAndForwardToParms, BackToParams, - CentralPaneName, - CentralPaneScreensParamList, DebugParamList, DetailsNavigatorParamList, EditRequestNavigatorParamList, @@ -1804,7 +1772,6 @@ export type { StackNavigationAction, State, StateOrRoute, - SwitchPolicyIDParams, TaskDetailsNavigatorParamList, TeachersUniteNavigatorParamList, TransactionDuplicateNavigatorParamList, From f44db08bf4030705984085387f5b3228655bb7c8 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 27 Nov 2024 15:57:20 +0100 Subject: [PATCH 200/257] Add missing docs to navigation functions --- src/libs/Navigation/Navigation.ts | 88 +++++++++++-------- .../helpers/customGetPathFromState.ts | 1 + .../helpers/getOnboardingAdaptedState.ts | 4 + .../helpers/getPolicyIDFromState.ts | 2 +- .../helpers/getTopmostReportParam.ts | 3 +- .../Navigation/helpers/isNavigatorName.ts | 4 + .../Navigation/helpers/isReportOpenInRHP.ts | 1 + .../index.android.ts | 2 +- 8 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 8f59b828bdd3..1342fb620e17 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -36,6 +36,7 @@ import RELATIONS from './linkingConfig/RELATIONS'; import navigationRef from './navigationRef'; import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, State} from './types'; +// Get the sidebar screen parameters from the split navigator passed as a param function getSidebarScreenParams(splitNavigatorRoute: NavigationStateRoute) { if (splitNavigatorRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { return splitNavigatorRoute.state?.routes?.at(0)?.params; @@ -68,18 +69,16 @@ function canNavigate(methodName: string, params: Record = {}): return false; } -// Re-exporting the getTopmostReportId here to fill in default value for state. The getTopmostReportId isn't defined in this file to avoid cyclic dependencies. +// Extracts from the topmost report its id. const getTopmostReportId = (state = navigationRef.getState()) => getTopmostReportParam(state, 'reportID'); -// Re-exporting the getTopmostReportActionID here to fill in default value for state. The getTopmostReportActionID isn't defined in this file to avoid cyclic dependencies. +// Extracts from the topmost report its action id. const getTopmostReportActionId = (state = navigationRef.getState()) => getTopmostReportParam(state, 'reportActionID'); // Re-exporting the closeRHPFlow here to fill in default value for navigationRef. The closeRHPFlow isn't defined in this file to avoid cyclic dependencies. const closeRHPFlow = (ref = navigationRef) => originalCloseRHPFlow(ref); -/** - * Function that generates dynamic urls from paths passed from OldDot - */ +// Function that generates dynamic urls from paths passed from OldDot. function parseHybridAppUrl(url: HybridAppRoute | Route): Route { switch (url) { case HYBRID_APP_ROUTES.MONEY_REQUEST_CREATE_TAB_MANUAL: @@ -94,7 +93,7 @@ function parseHybridAppUrl(url: HybridAppRoute | Route): Route { } } -/** Returns the current active route */ +// Returns the current active route. function getActiveRoute(): string { const currentRoute = navigationRef.current && navigationRef.current.getCurrentRoute(); if (!currentRoute?.name) { @@ -109,7 +108,7 @@ function getActiveRoute(): string { return ''; } - +// Returns the route of a report opened in RHP. function getReportRHPActiveRoute(): string { if (isReportOpenInRHP(navigationRef.getRootState())) { return getActiveRoute(); @@ -146,10 +145,14 @@ function navigate(route: Route = ROUTES.HOME, type?: string) { pendingRoute = route; return; } - // linkTo(navigationRef.current, route, type, isActiveRoute(route)); + linkTo(navigationRef.current, route, type); } +/** + * When routes are compared to determine whether the fallback route passed to the goUp function is in the state, + * these parameters shouldn't be included in the comparison. + */ const routeParamsIgnore = ['path', 'initial', 'params', 'state', 'screen', 'policyID']; // If we use destructuring, we will get an error if any of the ignored properties are not present in the object. @@ -186,13 +189,24 @@ function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | Navi return shallowCompare(routeParams, minimalActionParams); } +// Checks whether the given state is the root navigator state +function isRootNavigatorState(state: State): state is State { + return state.key === navigationRef.current?.getRootState().key; +} + type GoBackOptions = { - /** If we should compare params when searching for a route in state to go up to. + /** + * If we should compare params when searching for a route in state to go up to. * There are situations where we want to compare params when going up e.g. goUp to a specific report. * Sometimes we want to go up and update params of screen e.g. country picker. - * In that case we want to goUp to a country picker with any params so we don't compare them. */ + * In that case we want to goUp to a country picker with any params so we don't compare them. + */ compareParams?: boolean; + /** + * Specifies whether goBack should pop to top when invoked. + * Additionaly, to execute popToTop, set the value of the global variable ShouldPopAllStateOnUP to true using the setShouldPopAllStateOnUP function. + */ shouldPopToTop?: boolean; }; @@ -201,14 +215,17 @@ const defaultGoBackOptions: Required = { shouldPopToTop: false, }; -function isRootNavigatorState(state: State): state is State { - return state.key === navigationRef.current?.getRootState().key; -} - +/** + * Navigate to the given fallbackRoute taking into account whether it is possible to go back to this screen. Within one nested navigator, we can go back by any number + * of screens, but if as a result of going back we would have to remove more than one screen from the rootState, + * replace is performed so as not to lose the visited pages. + * If fallbackRoute is not found in the state, replace is also called then. + * + * @param fallbackRoute - The route to go up. + * @param options - Optional configuration that affects navigation logic, such as parameter comparison. + */ function goUp(fallbackRoute: Route, options?: GoBackOptions) { - const compareParams = options?.compareParams ?? defaultGoBackOptions.compareParams; - - if (!canNavigate('goBack')) { + if (!canNavigate('goUp')) { return; } @@ -231,6 +248,7 @@ function goUp(fallbackRoute: Route, options?: GoBackOptions) { return; } + const compareParams = options?.compareParams ?? defaultGoBackOptions.compareParams; const indexOfFallbackRoute = targetState.routes.findLastIndex((route) => doesRouteMatchToMinimalActionPayload(route, minimalAction, compareParams)); const distanceToPop = targetState.routes.length - indexOfFallbackRoute - 1; @@ -242,8 +260,10 @@ function goUp(fallbackRoute: Route, options?: GoBackOptions) { return; } - // If we are not comparing params, we want to use navigate action because it will replace params in the route already existing in the state if necessary. - // This part will need refactor after migrating to react-navigation 7. We will use popTo instead. + /** + * If we are not comparing params, we want to use navigate action because it will replace params in the route already existing in the state if necessary. + * This part will need refactor after migrating to react-navigation 7. We will use popTo instead. + */ if (!compareParams) { navigationRef.current.dispatch(minimalAction); return; @@ -254,16 +274,14 @@ function goUp(fallbackRoute: Route, options?: GoBackOptions) { /** * @param fallbackRoute - Fallback route if pop/goBack action should, but is not possible within RHP - * @param shouldPopToTop - Should we navigate to LHN on back press + * @param options - Optional configuration that affects navigation logic, e.g. whether goBack should popToTop. */ function goBack(fallbackRoute?: Route, options?: GoBackOptions) { if (!canNavigate('goBack')) { return; } - const shouldPopToTop = options?.shouldPopToTop ?? false; - - if (shouldPopToTop) { + if (options?.shouldPopToTop) { if (shouldPopAllStateOnUP) { shouldPopAllStateOnUP = false; navigationRef.current?.dispatch(StackActions.popToTop()); @@ -302,9 +320,7 @@ function goBack(fallbackRoute?: Route, options?: GoBackOptions) { navigationRef.current?.goBack(); } -/** - * Reset the navigation state to Home page - */ +// Reset the navigation state to Home page function resetToHome() { const isNarrowLayout = getIsNarrowLayout(); const rootState = navigationRef.getRootState(); @@ -318,9 +334,7 @@ function resetToHome() { navigationRef.dispatch({payload, type: 'REPLACE', target: rootState.key}); } -/** - * Update route params for the specified route. - */ +// Update route params for the specified route. function setParams(params: Record, routeKey = '') { navigationRef.current?.dispatch({ ...CommonActions.setParams(params), @@ -328,14 +342,12 @@ function setParams(params: Record, routeKey = '') { }); } -/** - * Returns the current active route without the URL params - */ +// Returns the current active route without the URL params. function getActiveRouteWithoutParams(): string { return getActiveRoute().replace(/\?.*/, ''); } -/** Returns the active route name from a state event from the navigationRef */ +// Returns the active route name from a state event from the navigationRef. function getRouteNameFromStateEvent(event: EventArg<'state', false, NavigationContainerEventMap['state']['data']>): string | undefined { if (!event.data.state) { return; @@ -415,12 +427,17 @@ function waitForProtectedRoutes() { }); } +// Changes the currently selected policy in the app. function switchPolicyID(policyID?: string) { navigationRef.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID, payload: {policyID}}); } type NavigateToReportWithPolicyCheckPayload = {report?: OnyxEntry; reportID?: string; reportActionID?: string; referrer?: string; policyIDToCheck?: string}; +/** + * Navigates to a report passed as a param (as an id or report object) and checks whether the target object belongs to the currently selected workspace. + * If not, the current workspace is set to global. + */ function navigateToReportWithPolicyCheck({report, reportID, reportActionID, referrer, policyIDToCheck}: NavigateToReportWithPolicyCheckPayload, ref = navigationRef) { const targetReport = reportID ? {reportID, ...ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]} : report; const policyID = policyIDToCheck ?? getPolicyIDFromState(navigationRef.getRootState() as State); @@ -453,8 +470,7 @@ function navigateToReportWithPolicyCheck({report, reportID, reportActionID, refe ); } -// @TODO In places where we use dismissModal with report arg we should do dismiss modal and then navigate to the report. -// We left it here to limit the number of changed files. +// Closes the modal navigator (RHP, LHP, onboarding). const dismissModal = (reportID?: string, ref = navigationRef) => { ref.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL}); if (!reportID) { @@ -462,6 +478,8 @@ const dismissModal = (reportID?: string, ref = navigationRef) => { } isNavigationReady().then(() => navigateToReportWithPolicyCheck({reportID})); }; + +// Dismisses the modal and opens the given report. const dismissModalWithReport = (report: OnyxEntry) => { dismissModal(); isNavigationReady().then(() => navigateToReportWithPolicyCheck({report})); diff --git a/src/libs/Navigation/helpers/customGetPathFromState.ts b/src/libs/Navigation/helpers/customGetPathFromState.ts index 0a42aa67a1ce..24fa3dbe1321 100644 --- a/src/libs/Navigation/helpers/customGetPathFromState.ts +++ b/src/libs/Navigation/helpers/customGetPathFromState.ts @@ -2,6 +2,7 @@ import {getPathFromState} from '@react-navigation/native'; import NAVIGATORS from '@src/NAVIGATORS'; import {isFullScreenName} from './isNavigatorName'; +// This function adds the policyID param to the url. const customGetPathFromState: typeof getPathFromState = (state, options) => { const path = getPathFromState(state, options); const fullScreenRoute = state.routes.findLast((route) => isFullScreenName(route.name)); diff --git a/src/libs/Navigation/helpers/getOnboardingAdaptedState.ts b/src/libs/Navigation/helpers/getOnboardingAdaptedState.ts index eee3f9f5e52d..cbb0ac71b8c4 100644 --- a/src/libs/Navigation/helpers/getOnboardingAdaptedState.ts +++ b/src/libs/Navigation/helpers/getOnboardingAdaptedState.ts @@ -1,6 +1,10 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; import SCREENS from '@src/SCREENS'; +/** + * When we open the application via deeplink to a specific onboarding screen, we want the previous onboarding screens to be able to go back to them. + * Therefore, the paths of the previous screens are added here. + */ export default function getOnboardingAdaptedState(state: PartialState): PartialState { const onboardingRoute = state.routes.at(0); if (!onboardingRoute || onboardingRoute.name === SCREENS.ONBOARDING.PURPOSE) { diff --git a/src/libs/Navigation/helpers/getPolicyIDFromState.ts b/src/libs/Navigation/helpers/getPolicyIDFromState.ts index b4b81ee15db8..808455834247 100644 --- a/src/libs/Navigation/helpers/getPolicyIDFromState.ts +++ b/src/libs/Navigation/helpers/getPolicyIDFromState.ts @@ -7,7 +7,7 @@ import extractPolicyIDFromQuery from './extractPolicyIDFromQuery'; * returns policyID value if one exists in navigation state * * PolicyID in this app can be stored in two ways: - * - on most screens but NOT Search as `policyID` param (on bottom tab screens) + * - on NAVIGATORS.REPORTS_SPLIT_NAVIGATOR as `policyID` param * - on Search related screens as policyID filter inside `q` (SearchQuery) param (only for SEARCH_CENTRAL_PANE) */ const getPolicyIDFromState = (state: State): string | undefined => { diff --git a/src/libs/Navigation/helpers/getTopmostReportParam.ts b/src/libs/Navigation/helpers/getTopmostReportParam.ts index 026cd379aa1a..40955d719755 100644 --- a/src/libs/Navigation/helpers/getTopmostReportParam.ts +++ b/src/libs/Navigation/helpers/getTopmostReportParam.ts @@ -6,9 +6,10 @@ import SCREENS from '@src/SCREENS'; // This function is in a separate file than Navigation.ts to avoid cyclic dependency. /** - * Find the last visited report screen in the navigation state and get the id of it. + * Find the last visited report screen in the navigation state and get its specific param (id or action id). * * @param state - The react-navigation state + * @param reportParam - param to get from the report route params * @returns - It's possible that there is no report screen */ diff --git a/src/libs/Navigation/helpers/isNavigatorName.ts b/src/libs/Navigation/helpers/isNavigatorName.ts index ae5118b9833e..db8b103309ec 100644 --- a/src/libs/Navigation/helpers/isNavigatorName.ts +++ b/src/libs/Navigation/helpers/isNavigatorName.ts @@ -18,6 +18,10 @@ const FULL_SCREENS_SET = new Set(FULL_SCREENS); const SIDEBARS_SET = new Set(SIDEBARS); const ONBOARDING_SCREENS_SET = new Set(ONBOARDING_SCREENS); +/** + * Functions defined below are used to check whether a screen belongs to a specific group. + * It is mainly used to filter routes in the navigation state. + */ function checkIfScreenHasMatchingNameToSetValues(screen: string | undefined, set: Set): screen is T { if (!screen) { return false; diff --git a/src/libs/Navigation/helpers/isReportOpenInRHP.ts b/src/libs/Navigation/helpers/isReportOpenInRHP.ts index 51e8a95bb66b..6158c3ec9d04 100644 --- a/src/libs/Navigation/helpers/isReportOpenInRHP.ts +++ b/src/libs/Navigation/helpers/isReportOpenInRHP.ts @@ -2,6 +2,7 @@ import type {NavigationState} from '@react-navigation/native'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; +// Determines whether the report page is opened in RHP. const isReportOpenInRHP = (state: NavigationState | undefined): boolean => { const lastRoute = state?.routes?.at(-1); if (!lastRoute) { diff --git a/src/libs/Navigation/helpers/setupCustomAndroidBackHandler/index.android.ts b/src/libs/Navigation/helpers/setupCustomAndroidBackHandler/index.android.ts index 04c1791145ca..54b16e09947e 100644 --- a/src/libs/Navigation/helpers/setupCustomAndroidBackHandler/index.android.ts +++ b/src/libs/Navigation/helpers/setupCustomAndroidBackHandler/index.android.ts @@ -1,7 +1,7 @@ import {BackHandler, NativeModules} from 'react-native'; import navigationRef from '@navigation/navigationRef'; -// We need to do some custom handling for the back button on Android for actions related to the search page. +// We need to do some custom handling for the back button on Android for actions related to the hybrid app. function setupCustomAndroidBackHandler() { const onBackPress = () => { const rootState = navigationRef.getRootState(); From 216c8128a70b3cd663df1cd9213ebbf2450c3491 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 28 Nov 2024 10:48:48 +0100 Subject: [PATCH 201/257] Cleanup isNavigatorName --- src/libs/Navigation/helpers/isNavigatorName.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/libs/Navigation/helpers/isNavigatorName.ts b/src/libs/Navigation/helpers/isNavigatorName.ts index db8b103309ec..b642526716c0 100644 --- a/src/libs/Navigation/helpers/isNavigatorName.ts +++ b/src/libs/Navigation/helpers/isNavigatorName.ts @@ -1,10 +1,7 @@ +import RELATIONS from '@libs/Navigation/linkingConfig/RELATIONS'; import type {FullScreenName, OnboardingFlowName, SplitNavigatorName, SplitNavigatorSidebarScreen} from '@libs/Navigation/types'; -import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -const SPLIT_NAVIGATORS = [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]; -const FULL_SCREENS = [...SPLIT_NAVIGATORS, SCREENS.SEARCH.CENTRAL_PANE]; -const SIDEBARS = [SCREENS.HOME, SCREENS.SETTINGS.ROOT, SCREENS.WORKSPACE.INITIAL]; const ONBOARDING_SCREENS = [ SCREENS.ONBOARDING.PERSONAL_DETAILS, SCREENS.ONBOARDING.PURPOSE, @@ -13,9 +10,9 @@ const ONBOARDING_SCREENS = [ SCREENS.ONBOARDING.ACCOUNTING, ]; -const SPLIT_NAVIGATORS_SET = new Set(SPLIT_NAVIGATORS); -const FULL_SCREENS_SET = new Set(FULL_SCREENS); -const SIDEBARS_SET = new Set(SIDEBARS); +const SPLIT_NAVIGATORS_SET = new Set(Object.values(RELATIONS.SIDEBAR_TO_SPLIT)); +const FULL_SCREENS_SET = new Set([...Object.values(RELATIONS.SIDEBAR_TO_SPLIT), SCREENS.SEARCH.CENTRAL_PANE]); +const SIDEBARS_SET = new Set(Object.values(RELATIONS.SPLIT_TO_SIDEBAR)); const ONBOARDING_SCREENS_SET = new Set(ONBOARDING_SCREENS); /** From f46818a310e32af19596156633c0b65496dddf25 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 29 Nov 2024 08:48:34 +0100 Subject: [PATCH 202/257] Adjust comment in SIDEBAR_TO_RHP --- .../Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts index 1923b50b4ea2..4deffa6fd876 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_RHP.ts @@ -1,8 +1,10 @@ import type {SplitNavigatorSidebarScreen} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; -// This file is used to define the relationship between the sidebar and the right hand pane (RHP) screen. -// These screens don't care about the split navigator's central screen and are in relation directly to the sidebar. +/** + * This file is used to define the relationship between the sidebar and the right hand pane (RHP) screen. + * This means that going back from RHP will take the user directly to the sidebar. On wide layout the default central screen will be used to fill the space. + */ const SIDEBAR_TO_RHP: Partial> = { [SCREENS.SETTINGS.ROOT]: [ SCREENS.SETTINGS.SHARE_CODE, From 7cf08be593397e20831b4fc2146cac26fdb06a6d Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 29 Nov 2024 09:56:02 +0100 Subject: [PATCH 203/257] Refactor getTopmostReportParam to getTopmostReportParams --- src/libs/Navigation/Navigation.ts | 6 +++--- ...ostReportParam.ts => getTopmostReportParams.ts} | 14 +++++--------- src/libs/Navigation/helpers/index.ts | 2 +- 3 files changed, 9 insertions(+), 13 deletions(-) rename src/libs/Navigation/helpers/{getTopmostReportParam.ts => getTopmostReportParams.ts} (65%) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 1342fb620e17..865294ae0832 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -24,7 +24,7 @@ import { getMinimalAction, getPolicyIDFromState, getStateFromPath, - getTopmostReportParam, + getTopmostReportParams, isReportOpenInRHP, isSplitNavigatorName, linkTo, @@ -70,10 +70,10 @@ function canNavigate(methodName: string, params: Record = {}): } // Extracts from the topmost report its id. -const getTopmostReportId = (state = navigationRef.getState()) => getTopmostReportParam(state, 'reportID'); +const getTopmostReportId = (state = navigationRef.getState()) => getTopmostReportParams(state)?.reportID; // Extracts from the topmost report its action id. -const getTopmostReportActionId = (state = navigationRef.getState()) => getTopmostReportParam(state, 'reportActionID'); +const getTopmostReportActionId = (state = navigationRef.getState()) => getTopmostReportParams(state)?.reportActionID; // Re-exporting the closeRHPFlow here to fill in default value for navigationRef. The closeRHPFlow isn't defined in this file to avoid cyclic dependencies. const closeRHPFlow = (ref = navigationRef) => originalCloseRHPFlow(ref); diff --git a/src/libs/Navigation/helpers/getTopmostReportParam.ts b/src/libs/Navigation/helpers/getTopmostReportParams.ts similarity index 65% rename from src/libs/Navigation/helpers/getTopmostReportParam.ts rename to src/libs/Navigation/helpers/getTopmostReportParams.ts index 40955d719755..618b8760add4 100644 --- a/src/libs/Navigation/helpers/getTopmostReportParam.ts +++ b/src/libs/Navigation/helpers/getTopmostReportParams.ts @@ -1,22 +1,20 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; -import type {RootStackParamList} from '@libs/Navigation/types'; +import type {ReportsSplitNavigatorParamList, RootStackParamList} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; // This function is in a separate file than Navigation.ts to avoid cyclic dependency. /** - * Find the last visited report screen in the navigation state and get its specific param (id or action id). + * Find the last visited report screen in the navigation state and get its params. * * @param state - The react-navigation state - * @param reportParam - param to get from the report route params * @returns - It's possible that there is no report screen */ type State = NavigationState | NavigationState | PartialState; -type ReportParam = 'reportID' | 'reportActionID'; -function getTopmostReportParam(state: State, reportParam: ReportParam): string | undefined { +function getTopmostReportParams(state: State): ReportsSplitNavigatorParamList[typeof SCREENS.REPORT] | undefined { if (!state) { return; } @@ -33,9 +31,7 @@ function getTopmostReportParam(state: State, reportParam: ReportParam): string | return; } - const topmostReportParams = topmostReport?.params as Record; - - return topmostReportParams?.[reportParam]; + return topmostReport?.params as ReportsSplitNavigatorParamList[typeof SCREENS.REPORT]; } -export default getTopmostReportParam; +export default getTopmostReportParams; diff --git a/src/libs/Navigation/helpers/index.ts b/src/libs/Navigation/helpers/index.ts index d3756c09b877..71ef89bedf7e 100644 --- a/src/libs/Navigation/helpers/index.ts +++ b/src/libs/Navigation/helpers/index.ts @@ -10,7 +10,7 @@ export {default as getOnboardingAdaptedState} from './getOnboardingAdaptedState' export {default as getParamsFromRoute} from './getParamsFromRoute'; export {default as getPolicyIDFromState} from './getPolicyIDFromState'; export {default as getStateFromPath} from './getStateFromPath'; -export {default as getTopmostReportParam} from './getTopmostReportParam'; +export {default as getTopmostReportParams} from './getTopmostReportParams'; export {default as getTopmostRouteName} from './getTopmostRouteName'; export {default as isReportOpenInRHP} from './isReportOpenInRHP'; export {default as isSearchTopmostFullScreenRoute} from './isSearchTopmostFullScreenRoute'; From 21f7bf6c199ff93370d8a8f9baa950f084fa7abc Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 29 Nov 2024 10:05:01 +0100 Subject: [PATCH 204/257] Adjust getOnboardingAdaptedState docs --- src/libs/Navigation/helpers/getOnboardingAdaptedState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/helpers/getOnboardingAdaptedState.ts b/src/libs/Navigation/helpers/getOnboardingAdaptedState.ts index cbb0ac71b8c4..97f02bd91509 100644 --- a/src/libs/Navigation/helpers/getOnboardingAdaptedState.ts +++ b/src/libs/Navigation/helpers/getOnboardingAdaptedState.ts @@ -3,7 +3,7 @@ import SCREENS from '@src/SCREENS'; /** * When we open the application via deeplink to a specific onboarding screen, we want the previous onboarding screens to be able to go back to them. - * Therefore, the paths of the previous screens are added here. + * Therefore, the routes of the previous screens are added here. */ export default function getOnboardingAdaptedState(state: PartialState): PartialState { const onboardingRoute = state.routes.at(0); From b11cba2f6d97414ec2fe34dc273ef9f2916752da Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 11 Dec 2024 10:18:40 +0100 Subject: [PATCH 205/257] Adjust screen navigation props types --- src/components/ScreenWrapper.tsx | 4 ++-- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 2 +- .../createResponsiveStackNavigator/CustomRouter.ts | 2 +- src/libs/Navigation/types.ts | 2 ++ src/pages/home/ReportScreen.tsx | 4 ++-- src/pages/home/report/ReportActionsList.tsx | 8 ++++---- src/pages/home/report/ReportActionsView.tsx | 4 ++-- src/pages/home/report/UserTypingEventListener.tsx | 4 ++-- 8 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/components/ScreenWrapper.tsx b/src/components/ScreenWrapper.tsx index c8d1aa474eb9..59bd36a8ddc5 100644 --- a/src/components/ScreenWrapper.tsx +++ b/src/components/ScreenWrapper.tsx @@ -16,7 +16,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import * as Browser from '@libs/Browser'; import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {AuthScreensParamList, RootStackParamList} from '@libs/Navigation/types'; +import type {ReportsSplitNavigatorParamList, RootStackParamList} from '@libs/Navigation/types'; import toggleTestToolsModal from '@userActions/TestTool'; import CONST from '@src/CONST'; import CustomDevMenu from './CustomDevMenu'; @@ -99,7 +99,7 @@ type ScreenWrapperProps = { * * This is required because transitionEnd event doesn't trigger in the testing environment. */ - navigation?: PlatformStackNavigationProp | PlatformStackNavigationProp; + navigation?: PlatformStackNavigationProp | PlatformStackNavigationProp; /** Whether to show offline indicator on wide screens */ shouldShowOfflineIndicatorInWideScreen?: boolean; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 4100b58c4173..0743e1798f79 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -24,6 +24,7 @@ import KeyboardShortcut from '@libs/KeyboardShortcut'; import Log from '@libs/Log'; import NavBarManager from '@libs/NavBarManager'; import getCurrentUrl from '@libs/Navigation/currentUrl'; +import {isOnboardingFlowName} from '@libs/Navigation/helpers'; import SIDEBAR_TO_SPLIT from '@libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation'; @@ -57,7 +58,6 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; -import {isOnboardingFlowName} from '../helpers'; import createResponsiveStackNavigator from './createResponsiveStackNavigator'; import defaultScreenOptions from './defaultScreenOptions'; import ExplanationModalNavigator from './Navigators/ExplanationModalNavigator'; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts index 94bb91fb5434..15aa6b0e9d14 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts @@ -68,7 +68,7 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { } if (isDismissModalAction(action)) { - return GetStateForActionHandlers.handleDismissModalAction(state, action, configOptions, stackRouter); + return GetStateForActionHandlers.handleDismissModalAction(state, configOptions, stackRouter); } if (isPushAction(action)) { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 4ddac42dd130..07ba941555e8 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1587,6 +1587,8 @@ type AuthScreensParamList = SharedScreensParamList & { type: ValueOf; accountID: string; isAuthTokenRequired?: string; + fileName?: string; + attachmentLink?: string; }; [SCREENS.PROFILE_AVATAR]: { accountID: string; diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index de66614c82c4..0f80147cbfa4 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -39,7 +39,7 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import shouldFetchReport from '@libs/shouldFetchReport'; import * as ValidationUtils from '@libs/ValidationUtils'; -import type {AuthScreensParamList} from '@navigation/types'; +import type {ReportsSplitNavigatorParamList} from '@navigation/types'; import * as ComposerActions from '@userActions/Composer'; import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; @@ -56,7 +56,7 @@ import ReportFooter from './report/ReportFooter'; import type {ActionListContextType, ReactionListRef, ScrollPosition} from './ReportScreenContext'; import {ActionListContext, ReactionListContext} from './ReportScreenContext'; -type ReportScreenNavigationProps = PlatformStackScreenProps; +type ReportScreenNavigationProps = PlatformStackScreenProps; type ReportScreenProps = CurrentReportIDContextValue & ReportScreenNavigationProps; diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx index ec14c55b36a6..9fa5c1e3f3f3 100644 --- a/src/pages/home/report/ReportActionsList.tsx +++ b/src/pages/home/report/ReportActionsList.tsx @@ -3,10 +3,10 @@ import {useIsFocused, useRoute} from '@react-navigation/native'; // eslint-disable-next-line lodash/import-scope import type {DebouncedFunc} from 'lodash'; import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react'; -import {DeviceEventEmitter, InteractionManager, View} from 'react-native'; import type {LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent, StyleProp, ViewStyle} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import {DeviceEventEmitter, InteractionManager, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; import InvertedFlatList from '@components/InvertedFlatList'; import {AUTOSCROLL_TO_TOP_THRESHOLD} from '@components/InvertedFlatList/BaseInvertedFlatList'; import {usePersonalDetails} from '@components/OnyxProvider'; @@ -26,7 +26,7 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportConnection from '@libs/ReportConnection'; import * as ReportUtils from '@libs/ReportUtils'; import Visibility from '@libs/Visibility'; -import type {AuthScreensParamList} from '@navigation/types'; +import type {ReportsSplitNavigatorParamList} from '@navigation/types'; import variables from '@styles/variables'; import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; @@ -158,7 +158,7 @@ function ReportActionsList({ const {preferredLocale} = useLocalize(); const {isOffline, lastOfflineAt, lastOnlineAt} = useNetworkWithOfflineStatus(); - const route = useRoute>(); + const route = useRoute>(); const reportScrollManager = useReportScrollManager(); const userActiveSince = useRef(DateUtils.getDBTime()); const lastMessageTime = useRef(null); diff --git a/src/pages/home/report/ReportActionsView.tsx b/src/pages/home/report/ReportActionsView.tsx index ee7c929acc7d..95a8bc677ad7 100755 --- a/src/pages/home/report/ReportActionsView.tsx +++ b/src/pages/home/report/ReportActionsView.tsx @@ -11,7 +11,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import DateUtils from '@libs/DateUtils'; import getIsReportFullyVisible from '@libs/getIsReportFullyVisible'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {AuthScreensParamList} from '@libs/Navigation/types'; +import type {ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; import * as NumberUtils from '@libs/NumberUtils'; import {generateNewRandomInt} from '@libs/NumberUtils'; import Performance from '@libs/Performance'; @@ -86,7 +86,7 @@ function ReportActionsView({ }: ReportActionsViewProps) { useCopySelectionHelper(); const reactionListRef = useContext(ReactionListContext); - const route = useRoute>(); + const route = useRoute>(); const [session] = useOnyx(ONYXKEYS.SESSION); const [transactionThreadReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID ?? -1}`, { selector: (reportActions: OnyxEntry) => diff --git a/src/pages/home/report/UserTypingEventListener.tsx b/src/pages/home/report/UserTypingEventListener.tsx index 73062902f63e..6609e48161b2 100644 --- a/src/pages/home/report/UserTypingEventListener.tsx +++ b/src/pages/home/report/UserTypingEventListener.tsx @@ -4,7 +4,7 @@ import {InteractionManager} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {AuthScreensParamList} from '@libs/Navigation/types'; +import type {ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; import * as Report from '@userActions/Report'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; @@ -19,7 +19,7 @@ function UserTypingEventListener({report}: UserTypingEventListenerProps) { const didSubscribeToReportTypingEvents = useRef(false); const reportID = report.reportID; const isFocused = useIsFocused(); - const route = useRoute>(); + const route = useRoute>(); useEffect( () => () => { From b15bccae514e61013d8e8070cde3e05dfcce0fdf Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 11 Dec 2024 10:40:20 +0100 Subject: [PATCH 206/257] Rename SplitStack to Split --- .../Navigators/ReportsSplitNavigator.tsx | 12 ++++++------ .../Navigators/SettingsSplitNavigator.tsx | 12 ++++++------ .../Navigators/WorkspaceSplitNavigator.tsx | 12 ++++++------ .../SplitRouter.ts} | 10 +++++----- .../getInitialSplitNavigatorState.ts | 0 .../index.tsx | 4 ++-- .../AppNavigator/createSplitNavigator/types.ts | 11 +++++++++++ .../useHandleScreenResize/index.native.ts | 0 .../useHandleScreenResize/index.ts | 0 .../usePrepareSplitStackNavigatorChildren.ts | 2 +- .../usePreserveSplitNavigatorState.ts | 0 .../createSplitStackNavigator/types.ts | 16 ---------------- src/libs/Navigation/Navigation.ts | 2 +- src/libs/Navigation/NavigationRoot.tsx | 2 +- .../helpers/getAdaptedStateFromPath.ts | 2 +- src/pages/home/sidebar/BottomTabAvatar.tsx | 2 +- 16 files changed, 41 insertions(+), 46 deletions(-) rename src/libs/Navigation/AppNavigator/{createSplitStackNavigator/SplitStackRouter.ts => createSplitNavigator/SplitRouter.ts} (95%) rename src/libs/Navigation/AppNavigator/{createSplitStackNavigator => createSplitNavigator}/getInitialSplitNavigatorState.ts (100%) rename src/libs/Navigation/AppNavigator/{createSplitStackNavigator => createSplitNavigator}/index.tsx (96%) create mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts rename src/libs/Navigation/AppNavigator/{createSplitStackNavigator => createSplitNavigator}/useHandleScreenResize/index.native.ts (100%) rename src/libs/Navigation/AppNavigator/{createSplitStackNavigator => createSplitNavigator}/useHandleScreenResize/index.ts (100%) rename src/libs/Navigation/AppNavigator/{createSplitStackNavigator => createSplitNavigator}/usePrepareSplitStackNavigatorChildren.ts (88%) rename src/libs/Navigation/AppNavigator/{createSplitStackNavigator => createSplitNavigator}/usePreserveSplitNavigatorState.ts (100%) delete mode 100644 src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts diff --git a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx index 73972199e7b7..277e1cda3398 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/ReportsSplitNavigator.tsx @@ -3,7 +3,7 @@ import React, {useRef} from 'react'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import usePermissions from '@hooks/usePermissions'; -import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; +import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import FreezeWrapper from '@libs/Navigation/AppNavigator/FreezeWrapper'; import useRootNavigatorOptions from '@libs/Navigation/AppNavigator/useRootNavigatorOptions'; import getCurrentUrl from '@libs/Navigation/currentUrl'; @@ -17,7 +17,7 @@ import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; const loadReportScreen = () => require('../../../../pages/home/ReportScreen').default; const loadSidebarScreen = () => require('@pages/home/sidebar/SidebarScreen').default; -const Stack = createSplitStackNavigator(); +const Split = createSplitNavigator(); function ReportsSplitNavigator() { const {canUseDefaultRooms} = usePermissions(); @@ -47,23 +47,23 @@ function ReportsSplitNavigator() { return ( - - - - + ); diff --git a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx index ca2aab050274..e55285986773 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/SettingsSplitNavigator.tsx @@ -1,7 +1,7 @@ import {useRoute} from '@react-navigation/native'; import React from 'react'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; -import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; +import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import useRootNavigatorOptions from '@libs/Navigation/AppNavigator/useRootNavigatorOptions'; import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation'; import type {PlatformStackNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types'; @@ -25,7 +25,7 @@ const CENTRAL_PANE_SETTINGS_SCREENS = { [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: () => require('../../../../pages/settings/Subscription/SubscriptionSettingsPage').default, } satisfies Screens; -const Stack = createSplitStackNavigator(); +const Split = createSplitNavigator(); function SettingsSplitNavigator() { const route = useRoute(); @@ -33,13 +33,13 @@ function SettingsSplitNavigator() { return ( - - ); })} - + ); } diff --git a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx index fd0c91757fa4..2d269e88ba16 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx @@ -1,7 +1,7 @@ import {useRoute} from '@react-navigation/native'; import React from 'react'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; -import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator'; +import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import useRootNavigatorOptions from '@libs/Navigation/AppNavigator/useRootNavigatorOptions'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; @@ -29,7 +29,7 @@ const CENTRAL_PANE_WORKSPACE_SCREENS = { [SCREENS.WORKSPACE.RULES]: () => require('../../../../pages/workspace/rules/PolicyRulesPage').default, } satisfies Screens; -const Stack = createSplitStackNavigator(); +const Split = createSplitNavigator(); function WorkspaceNavigator() { const route = useRoute(); @@ -37,25 +37,25 @@ function WorkspaceNavigator() { return ( - - {Object.entries(CENTRAL_PANE_WORKSPACE_SCREENS).map(([screenName, componentGetter]) => ( - ))} - + ); } diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts similarity index 95% rename from src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts rename to src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts index 3bc1e50717ec..454b13f59417 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts @@ -5,7 +5,7 @@ import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import {getParamsFromRoute} from '@libs/Navigation/helpers'; import navigationRef from '@libs/Navigation/navigationRef'; import SCREENS from '@src/SCREENS'; -import type {SplitStackNavigatorRouterOptions} from './types'; +import type {SplitNavigatorRouterOptions} from './types'; import {getPreservedSplitNavigatorState} from './usePreserveSplitNavigatorState'; type StackState = StackNavigationState | PartialState>; @@ -14,7 +14,7 @@ const isAtLeastOneInState = (state: StackState, screenName: string): boolean => type AdaptStateIfNecessaryArgs = { state: StackState; - options: SplitStackNavigatorRouterOptions; + options: SplitNavigatorRouterOptions; }; function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralScreen, parentRoute}}: AdaptStateIfNecessaryArgs) { @@ -83,14 +83,14 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc } } -function isPushingSidebarOnCentralPane(state: StackState, action: CommonActions.Action | StackActionType, options: SplitStackNavigatorRouterOptions) { +function isPushingSidebarOnCentralPane(state: StackState, action: CommonActions.Action | StackActionType, options: SplitNavigatorRouterOptions) { if (action.type === 'PUSH' && action.payload.name === options.sidebarScreen && state.routes.length > 1) { return true; } return false; } -function SplitStackRouter(options: SplitStackNavigatorRouterOptions) { +function SplitRouter(options: SplitNavigatorRouterOptions) { const stackRouter = StackRouter(options); return { ...stackRouter, @@ -134,4 +134,4 @@ function SplitStackRouter(options: SplitStackNavigatorRouterOptions) { }; } -export default SplitStackRouter; +export default SplitRouter; diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/getInitialSplitNavigatorState.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState.ts rename to src/libs/Navigation/AppNavigator/createSplitNavigator/getInitialSplitNavigatorState.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx similarity index 96% rename from src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx rename to src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx index 629b48beaeb3..f04f51fcff41 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/index.tsx @@ -11,7 +11,7 @@ import type { PlatformStackNavigationOptions, PlatformStackNavigationState, } from '@libs/Navigation/PlatformStackNavigation/types'; -import SplitStackRouter from './SplitStackRouter'; +import SplitRouter from './SplitRouter'; import usePreserveSplitNavigatorState from './usePreserveSplitNavigatorState'; function useCustomEffects(props: CustomEffectsHookProps) { @@ -35,7 +35,7 @@ function useCustomSplitNavigatorState({state}: CustomStateHookProps) { } const CustomFullScreenNavigatorComponent = createPlatformStackNavigatorComponent('CustomFullScreenNavigator', { - createRouter: SplitStackRouter, + createRouter: SplitRouter, useCustomEffects, defaultScreenOptions: defaultPlatformStackScreenOptions, useCustomState: useCustomSplitNavigatorState, diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts new file mode 100644 index 000000000000..36da86e8f51a --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/types.ts @@ -0,0 +1,11 @@ +import type {DefaultNavigatorOptions, ParamListBase, RouteProp, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; +import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; + +type SplitNavigatorRouterOptions = StackRouterOptions & {defaultCentralScreen: string; sidebarScreen: string; parentRoute: RouteProp}; + +type SplitNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> & { + defaultCentralScreen: Extract; + sidebarScreen: Extract; +}; + +export type {SplitNavigatorProps, SplitNavigatorRouterOptions}; diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useHandleScreenResize/index.native.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/useHandleScreenResize/index.native.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createSplitStackNavigator/useHandleScreenResize/index.native.ts rename to src/libs/Navigation/AppNavigator/createSplitNavigator/useHandleScreenResize/index.native.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/useHandleScreenResize/index.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/useHandleScreenResize/index.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createSplitStackNavigator/useHandleScreenResize/index.ts rename to src/libs/Navigation/AppNavigator/createSplitNavigator/useHandleScreenResize/index.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitStackNavigatorChildren.ts similarity index 88% rename from src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts rename to src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitStackNavigatorChildren.ts index 9609fa3ec994..4995f96bc1a4 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePrepareSplitStackNavigatorChildren.ts +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitStackNavigatorChildren.ts @@ -3,7 +3,7 @@ import type {StackNavigationOptions} from '@react-navigation/stack'; import {Children, isValidElement, useMemo} from 'react'; import type {ReactNode} from 'react'; -export default function usePrepareSplitStackNavigatorChildren(screensNode: ReactNode, sidebarScreenName: string, sidebarScreenOptions: StackNavigationOptions) { +export default function usePrepareSplitNavigatorChildren(screensNode: ReactNode, sidebarScreenName: string, sidebarScreenOptions: StackNavigationOptions) { return useMemo( () => Children.toArray(screensNode).map((screen: ReactNode) => { diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState.ts rename to src/libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState.ts diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts deleted file mode 100644 index cc9db03c75ae..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type {DefaultNavigatorOptions, ParamListBase, RouteProp, StackNavigationState, StackRouterOptions} from '@react-navigation/native'; -import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; - -type SplitStackNavigatorRouterOptions = StackRouterOptions & {defaultCentralScreen: string; sidebarScreen: string; parentRoute: RouteProp}; - -type SplitStackNavigatorProps = DefaultNavigatorOptions< - ParamListBase, - StackNavigationState, - StackNavigationOptions, - StackNavigationEventMap -> & { - defaultCentralScreen: Extract; - sidebarScreen: Extract; -}; - -export type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions}; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 865294ae0832..623ce67a3957 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -19,7 +19,7 @@ import ROUTES, {HYBRID_APP_ROUTES} from '@src/ROUTES'; import SCREENS, {PROTECTED_SCREENS} from '@src/SCREENS'; import type {Report} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import getInitialSplitNavigatorState from './AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState'; +import getInitialSplitNavigatorState from './AppNavigator/createSplitNavigator/getInitialSplitNavigatorState'; import { getMinimalAction, getPolicyIDFromState, diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 3181e2d60979..a8af25db8e62 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -22,7 +22,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import AppNavigator from './AppNavigator'; -import {cleanPreservedSplitNavigatorStates} from './AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState'; +import {cleanPreservedSplitNavigatorStates} from './AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; import {customGetPathFromState, getAdaptedStateFromPath, setupCustomAndroidBackHandler} from './helpers'; import linkingConfig from './linkingConfig'; import Navigation, {navigationRef} from './Navigation'; diff --git a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts index c7a712f0fd7a..8a2886c36f27 100644 --- a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts @@ -2,7 +2,7 @@ import type {NavigationState, PartialState, Route} from '@react-navigation/nativ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import pick from 'lodash/pick'; import {isAnonymousUser} from '@libs/actions/Session'; -import getInitialSplitNavigatorState from '@libs/Navigation/AppNavigator/createSplitStackNavigator/getInitialSplitNavigatorState'; +import getInitialSplitNavigatorState from '@libs/Navigation/AppNavigator/createSplitNavigator/getInitialSplitNavigatorState'; import config from '@libs/Navigation/linkingConfig/config'; import RELATIONS from '@libs/Navigation/linkingConfig/RELATIONS'; import type {NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index 0d93b3ff5a87..28712438aea9 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -8,7 +8,7 @@ import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; -import {getPreservedSplitNavigatorState} from '@libs/Navigation/AppNavigator/createSplitStackNavigator/usePreserveSplitNavigatorState'; +import {getPreservedSplitNavigatorState} from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import CONST from '@src/CONST'; From e69b8f0e8e84904691fe2a869ccea4f0d152b7a6 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 11 Dec 2024 11:08:45 +0100 Subject: [PATCH 207/257] Fix tests that use useActiveWorkspace --- tests/perf-test/SidebarLinks.perf-test.tsx | 2 +- tests/ui/LHNItemsPresence.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/perf-test/SidebarLinks.perf-test.tsx b/tests/perf-test/SidebarLinks.perf-test.tsx index b02d6e7e4640..3822afcfdee9 100644 --- a/tests/perf-test/SidebarLinks.perf-test.tsx +++ b/tests/perf-test/SidebarLinks.perf-test.tsx @@ -10,7 +10,7 @@ import wrapInAct from '../utils/wrapInActHelper'; import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates'; jest.mock('@libs/Permissions'); -jest.mock('@src/hooks/useActiveWorkspace', () => jest.fn(() => ({activeWorkspaceID: undefined}))); +jest.mock('@hooks/useActiveWorkspace', () => jest.fn(() => ({activeWorkspaceID: undefined}))); jest.mock('../../src/libs/Navigation/Navigation', () => ({ navigate: jest.fn(), isActiveRoute: jest.fn(), diff --git a/tests/ui/LHNItemsPresence.tsx b/tests/ui/LHNItemsPresence.tsx index 6693c90adaa0..0b85327caa83 100644 --- a/tests/ui/LHNItemsPresence.tsx +++ b/tests/ui/LHNItemsPresence.tsx @@ -16,7 +16,7 @@ import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatch // Be sure to include the mocked permissions library, as some components that are rendered // during the test depend on its methods. jest.mock('@libs/Permissions'); -jest.mock('@src/hooks/useActiveWorkspaceFromNavigationState'); +jest.mock('@hooks/useActiveWorkspace', () => jest.fn(() => ({activeWorkspaceID: undefined}))); type LazyLoadLHNTestUtils = { fakePersonalDetails: PersonalDetailsList; From 28960319e574e9caba11c989494d73b02c3ebcd6 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 11 Dec 2024 11:11:42 +0100 Subject: [PATCH 208/257] Fix mocking isSearchTopmostFullScreenRoute in IOUTest --- tests/actions/IOUTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/actions/IOUTest.ts b/tests/actions/IOUTest.ts index df37da0d15a0..65d2cc9de1db 100644 --- a/tests/actions/IOUTest.ts +++ b/tests/actions/IOUTest.ts @@ -34,7 +34,7 @@ jest.mock('@src/libs/Navigation/Navigation', () => ({ goBack: jest.fn(), })); -jest.mock('@src/libs/Navigation/isSearchTopmostFullScreenRoute', () => jest.fn()); +jest.mock('@libs/Navigation/helpers/isSearchTopmostFullScreenRoute', () => jest.fn()); const CARLOS_EMAIL = 'cmartins@expensifail.com'; const CARLOS_ACCOUNT_ID = 1; From 686dde6e15fcc8bf6c46a240f4bd83a441b0d151 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 11 Dec 2024 11:47:46 +0100 Subject: [PATCH 209/257] Update relations files and remove redundant mappings --- .../RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts | 66 ----- .../RELATIONS/SEARCH_RHP_SCREENS.ts | 26 -- .../RELATIONS/SETTINGS_TO_RHP.ts | 3 + .../WORKSPACE_SCREEN_TO_RHP_MAPPING.ts | 252 ------------------ .../RELATIONS/WORKSPACE_TO_RHP.ts | 36 ++- 5 files changed, 38 insertions(+), 345 deletions(-) delete mode 100755 src/libs/Navigation/linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts delete mode 100644 src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts delete mode 100755 src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_SCREEN_TO_RHP_MAPPING.ts diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts deleted file mode 100755 index ca22a325f2f5..000000000000 --- a/src/libs/Navigation/linkingConfig/RELATIONS/CENTRAL_PANE_TO_RHP_MAPPING.ts +++ /dev/null @@ -1,66 +0,0 @@ -// @TODO: Remove this file before merging to the main. -import type {SplitNavigatorScreenName} from '@libs/Navigation/types'; -import SCREENS from '@src/SCREENS'; -import WORKSPACE_SCREEN_TO_RHP_MAPPING from './WORKSPACE_SCREEN_TO_RHP_MAPPING'; - -const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = { - [SCREENS.SETTINGS.PROFILE.ROOT]: [ - SCREENS.SETTINGS.PROFILE.DISPLAY_NAME, - SCREENS.SETTINGS.PROFILE.CONTACT_METHODS, - SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS, - SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD, - SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER, - SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_DATE, - SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_TIME, - SCREENS.SETTINGS.PROFILE.STATUS, - SCREENS.SETTINGS.PROFILE.PRONOUNS, - SCREENS.SETTINGS.PROFILE.TIMEZONE, - SCREENS.SETTINGS.PROFILE.TIMEZONE_SELECT, - SCREENS.SETTINGS.PROFILE.LEGAL_NAME, - SCREENS.SETTINGS.PROFILE.DATE_OF_BIRTH, - SCREENS.SETTINGS.PROFILE.PHONE_NUMBER, - SCREENS.SETTINGS.PROFILE.ADDRESS, - SCREENS.SETTINGS.PROFILE.ADDRESS_COUNTRY, - SCREENS.SETTINGS.SHARE_CODE, - SCREENS.SETTINGS.EXIT_SURVEY.REASON, - SCREENS.SETTINGS.EXIT_SURVEY.RESPONSE, - SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM, - ], - [SCREENS.SETTINGS.PREFERENCES.ROOT]: [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE, SCREENS.SETTINGS.PREFERENCES.LANGUAGE, SCREENS.SETTINGS.PREFERENCES.THEME], - [SCREENS.SETTINGS.WALLET.ROOT]: [ - SCREENS.SETTINGS.WALLET.DOMAIN_CARD, - SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.NAME, - SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.PHONE, - SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.ADDRESS, - SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.CONFIRM, - SCREENS.SETTINGS.WALLET.TRANSFER_BALANCE, - SCREENS.SETTINGS.WALLET.CHOOSE_TRANSFER_ACCOUNT, - SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS, - SCREENS.SETTINGS.WALLET.CARD_ACTIVATE, - SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD, - SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS, - ], - [SCREENS.SETTINGS.SECURITY]: [ - SCREENS.SETTINGS.TWO_FACTOR_AUTH, - SCREENS.SETTINGS.CLOSE, - SCREENS.SETTINGS.DELEGATE.ADD_DELEGATE, - SCREENS.SETTINGS.DELEGATE.DELEGATE_ROLE, - SCREENS.SETTINGS.DELEGATE.UPDATE_DELEGATE_ROLE, - SCREENS.SETTINGS.DELEGATE.DELEGATE_CONFIRM, - SCREENS.SETTINGS.DELEGATE.UPDATE_DELEGATE_ROLE_MAGIC_CODE, - ], - [SCREENS.SETTINGS.ABOUT]: [SCREENS.SETTINGS.APP_DOWNLOAD_LINKS], - [SCREENS.SETTINGS.SAVE_THE_WORLD]: [SCREENS.I_KNOW_A_TEACHER, SCREENS.INTRO_SCHOOL_PRINCIPAL, SCREENS.I_AM_A_TEACHER], - [SCREENS.SETTINGS.TROUBLESHOOT]: [SCREENS.SETTINGS.CONSOLE], - [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: [ - SCREENS.SETTINGS.SUBSCRIPTION.ADD_PAYMENT_CARD, - SCREENS.SETTINGS.SUBSCRIPTION.SIZE, - SCREENS.SETTINGS.SUBSCRIPTION.DISABLE_AUTO_RENEW_SURVEY, - SCREENS.SETTINGS.SUBSCRIPTION.REQUEST_EARLY_CANCELLATION, - SCREENS.SETTINGS.SUBSCRIPTION.CHANGE_BILLING_CURRENCY, - SCREENS.SETTINGS.SUBSCRIPTION.CHANGE_PAYMENT_CURRENCY, - ], - ...WORKSPACE_SCREEN_TO_RHP_MAPPING, -}; - -export default CENTRAL_PANE_TO_RHP_MAPPING; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts deleted file mode 100644 index 48422f90a7bc..000000000000 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SEARCH_RHP_SCREENS.ts +++ /dev/null @@ -1,26 +0,0 @@ -// @TODO Remove this file before merging to the main. -import SCREENS from '@src/SCREENS'; - -const SEARCH_RHP_SCREENS: string[] = [ - SCREENS.SEARCH.REPORT_RHP, - SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_CURRENCY_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_DATE_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_DESCRIPTION_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_MERCHANT_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_REPORT_ID_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_AMOUNT_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_CATEGORY_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_KEYWORD_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_TAX_RATE_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_EXPENSE_TYPE_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_TAG_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_FROM_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_TO_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_IN_RHP, - SCREENS.SEARCH.ADVANCED_FILTERS_CARD_RHP, - SCREENS.SEARCH.SAVED_SEARCH_RENAME_RHP, -]; - -export default SEARCH_RHP_SCREENS; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts index 6e7c15ce3a16..1df3af0a6e86 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/SETTINGS_TO_RHP.ts @@ -17,6 +17,7 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = { - [SCREENS.WORKSPACE.PROFILE]: [ - SCREENS.WORKSPACE.NAME, - SCREENS.WORKSPACE.ADDRESS, - SCREENS.WORKSPACE.CURRENCY, - SCREENS.WORKSPACE.DESCRIPTION, - SCREENS.WORKSPACE.SHARE, - SCREENS.WORKSPACE.DOWNGRADE, - ], - [SCREENS.WORKSPACE.MEMBERS]: [ - SCREENS.WORKSPACE.INVITE, - SCREENS.WORKSPACE.INVITE_MESSAGE, - SCREENS.WORKSPACE.MEMBER_DETAILS, - SCREENS.WORKSPACE.MEMBER_NEW_CARD, - SCREENS.WORKSPACE.OWNER_CHANGE_CHECK, - SCREENS.WORKSPACE.OWNER_CHANGE_SUCCESS, - SCREENS.WORKSPACE.OWNER_CHANGE_ERROR, - SCREENS.WORKSPACE.OWNER_CHANGE_ERROR, - SCREENS.WORKSPACE.MEMBERS_IMPORT, - SCREENS.WORKSPACE.MEMBERS_IMPORTED, - ], - [SCREENS.WORKSPACE.WORKFLOWS]: [ - SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_NEW, - SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EDIT, - SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_EXPENSES_FROM, - SCREENS.WORKSPACE.WORKFLOWS_APPROVALS_APPROVER, - SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY, - SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET, - SCREENS.WORKSPACE.WORKFLOWS_PAYER, - ], - [SCREENS.WORKSPACE.ACCOUNTING.ROOT]: [ - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_IMPORT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CHART_OF_ACCOUNTS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CLASSES, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_TAXES, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_LOCATIONS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CUSTOMERS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_DATE_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_INVOICE_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_COMPANY_CARD_EXPENSE_ACCOUNT_COMPANY_CARD_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_PREFERRED_EXPORTER, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_NON_REIMBURSABLE_DEFAULT_VENDOR_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ADVANCED, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_ACCOUNT_SELECTOR, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CLASSES_DISPLAYED_AS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_CUSTOMERS_DISPLAYED_AS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_LOCATIONS_DISPLAYED_AS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT_COMPANY_CARD_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_COMPANY_CARD_EXPENSE_ACCOUNT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_NON_REIMBURSABLE_DEFAULT_VENDOR_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_ADVANCED, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_EXPORT_DATE_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_EXPORT_PREFERRED_EXPORTER, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_EXPORT_OUT_OF_POCKET_EXPENSES, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_EXPORT_OUT_OF_POCKET_EXPENSES_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_EXPORT_OUT_OF_POCKET_EXPENSES_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_EXPORT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_SETUP_MODAL, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_SETUP_REQUIRED_DEVICE_MODAL, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_TRIGGER_FIRST_SYNC, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_IMPORT, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_CHART_OF_ACCOUNTS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_CLASSES, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_CLASSES_DISPLAYED_AS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_CUSTOMERS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_CUSTOMERS_DISPLAYED_AS, - SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_ITEMS, - SCREENS.WORKSPACE.ACCOUNTING.XERO_IMPORT, - SCREENS.WORKSPACE.ACCOUNTING.XERO_CHART_OF_ACCOUNTS, - SCREENS.WORKSPACE.ACCOUNTING.XERO_ORGANIZATION, - SCREENS.WORKSPACE.ACCOUNTING.XERO_CUSTOMER, - SCREENS.WORKSPACE.ACCOUNTING.XERO_TAXES, - SCREENS.WORKSPACE.ACCOUNTING.XERO_TRACKING_CATEGORIES, - SCREENS.WORKSPACE.ACCOUNTING.XERO_MAP_TRACKING_CATEGORY, - SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT, - SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_PURCHASE_BILL_DATE_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.XERO_ADVANCED, - SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_STATUS_SELECTOR, - SCREENS.WORKSPACE.ACCOUNTING.XERO_INVOICE_ACCOUNT_SELECTOR, - SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_PREFERRED_EXPORTER_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.XERO_BILL_PAYMENT_ACCOUNT_SELECTOR, - SCREENS.WORKSPACE.ACCOUNTING.XERO_EXPORT_BANK_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_SUBSIDIARY_SELECTOR, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_REUSE_EXISTING_CONNECTIONS, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_TOKEN_INPUT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_MAPPING, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_VIEW, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_FIELD_EDIT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_LIST_ADD, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOM_SEGMENT_ADD, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_IMPORT_CUSTOMERS_OR_PROJECTS_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_PREFERRED_EXPORTER_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_DATE_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_DESTINATION_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_VENDOR_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_PAYABLE_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPORT_EXPENSES_JOURNAL_POSTING_PREFERENCE_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_RECEIVABLE_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_INVOICE_ITEM_PREFERENCE_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_INVOICE_ITEM_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_TAX_POSTING_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_PROVINCIAL_TAX_POSTING_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_ADVANCED, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_REIMBURSEMENT_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_COLLECTION_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_EXPENSE_REPORT_APPROVAL_LEVEL_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_VENDOR_BILL_APPROVAL_LEVEL_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_JOURNAL_ENTRY_APPROVAL_LEVEL_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_APPROVAL_ACCOUNT_SELECT, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_CUSTOM_FORM_ID, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_AUTO_SYNC, - SCREENS.WORKSPACE.ACCOUNTING.NETSUITE_ACCOUNTING_METHOD, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PREREQUISITES, - SCREENS.WORKSPACE.ACCOUNTING.ENTER_SAGE_INTACCT_CREDENTIALS, - SCREENS.WORKSPACE.ACCOUNTING.EXISTING_SAGE_INTACCT_CONNECTIONS, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ENTITY, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_IMPORT, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_MAPPING_TYPE, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_TOGGLE_MAPPING, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_USER_DIMENSIONS, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ADD_USER_DIMENSION, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EDIT_USER_DIMENSION, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EXPORT, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PREFERRED_EXPORTER, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_EXPORT_DATE, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_REIMBURSABLE_EXPENSES, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_EXPENSES, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_REIMBURSABLE_DESTINATION, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_DESTINATION, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_DEFAULT_VENDOR, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_NON_REIMBURSABLE_CREDIT_CARD_ACCOUNT, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_ADVANCED, - SCREENS.WORKSPACE.ACCOUNTING.SAGE_INTACCT_PAYMENT_ACCOUNT, - SCREENS.WORKSPACE.ACCOUNTING.CARD_RECONCILIATION, - SCREENS.WORKSPACE.ACCOUNTING.RECONCILIATION_ACCOUNT_SETTINGS, - ], - [SCREENS.WORKSPACE.TAXES]: [ - SCREENS.WORKSPACE.TAXES_SETTINGS, - SCREENS.WORKSPACE.TAX_CREATE, - SCREENS.WORKSPACE.TAXES_SETTINGS_CUSTOM_TAX_NAME, - SCREENS.WORKSPACE.TAXES_SETTINGS_FOREIGN_CURRENCY_DEFAULT, - SCREENS.WORKSPACE.TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT, - SCREENS.WORKSPACE.TAX_CREATE, - SCREENS.WORKSPACE.TAX_EDIT, - SCREENS.WORKSPACE.TAX_NAME, - SCREENS.WORKSPACE.TAX_VALUE, - SCREENS.WORKSPACE.TAX_CODE, - ], - [SCREENS.WORKSPACE.TAGS]: [ - SCREENS.WORKSPACE.TAGS_SETTINGS, - SCREENS.WORKSPACE.TAGS_EDIT, - SCREENS.WORKSPACE.TAG_CREATE, - SCREENS.WORKSPACE.TAG_SETTINGS, - SCREENS.WORKSPACE.TAG_EDIT, - SCREENS.WORKSPACE.TAG_LIST_VIEW, - SCREENS.WORKSPACE.TAG_GL_CODE, - SCREENS.WORKSPACE.TAG_APPROVER, - SCREENS.WORKSPACE.TAGS_IMPORT, - SCREENS.WORKSPACE.TAGS_IMPORTED, - ], - [SCREENS.WORKSPACE.CATEGORIES]: [ - SCREENS.WORKSPACE.CATEGORY_CREATE, - SCREENS.WORKSPACE.CATEGORY_SETTINGS, - SCREENS.WORKSPACE.CATEGORIES_IMPORT, - SCREENS.WORKSPACE.CATEGORIES_IMPORTED, - SCREENS.WORKSPACE.CATEGORIES_SETTINGS, - SCREENS.WORKSPACE.CATEGORY_EDIT, - SCREENS.WORKSPACE.CATEGORY_GL_CODE, - SCREENS.WORKSPACE.CATEGORY_PAYROLL_CODE, - SCREENS.WORKSPACE.CATEGORY_DEFAULT_TAX_RATE, - SCREENS.WORKSPACE.CATEGORY_FLAG_AMOUNTS_OVER, - SCREENS.WORKSPACE.CATEGORY_DESCRIPTION_HINT, - SCREENS.WORKSPACE.CATEGORY_APPROVER, - SCREENS.WORKSPACE.CATEGORY_REQUIRE_RECEIPTS_OVER, - ], - [SCREENS.WORKSPACE.DISTANCE_RATES]: [ - SCREENS.WORKSPACE.CREATE_DISTANCE_RATE, - SCREENS.WORKSPACE.DISTANCE_RATES_SETTINGS, - SCREENS.WORKSPACE.DISTANCE_RATE_EDIT, - SCREENS.WORKSPACE.DISTANCE_RATE_TAX_RECLAIMABLE_ON_EDIT, - SCREENS.WORKSPACE.DISTANCE_RATE_TAX_RATE_EDIT, - SCREENS.WORKSPACE.DISTANCE_RATE_DETAILS, - ], - [SCREENS.WORKSPACE.REPORT_FIELDS]: [ - SCREENS.WORKSPACE.REPORT_FIELDS_CREATE, - SCREENS.WORKSPACE.REPORT_FIELDS_SETTINGS, - SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES, - SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE, - SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS, - SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE, - SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE, - ], - [SCREENS.WORKSPACE.INVOICES]: [SCREENS.WORKSPACE.INVOICES_COMPANY_NAME, SCREENS.WORKSPACE.INVOICES_COMPANY_WEBSITE], - [SCREENS.WORKSPACE.COMPANY_CARDS]: [ - SCREENS.WORKSPACE.COMPANY_CARDS_SELECT_FEED, - SCREENS.WORKSPACE.COMPANY_CARDS_ADD_NEW, - SCREENS.WORKSPACE.COMPANY_CARDS_TYPE, - SCREENS.WORKSPACE.COMPANY_CARDS_INSTRUCTIONS, - SCREENS.WORKSPACE.COMPANY_CARDS_NAME, - SCREENS.WORKSPACE.COMPANY_CARDS_DETAILS, - SCREENS.WORKSPACE.COMPANY_CARDS_SELECT_FEED, - SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS, - SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS_FEED_NAME, - SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS, - SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS_FEED_NAME, - SCREENS.WORKSPACE.COMPANY_CARDS_ASSIGN_CARD, - SCREENS.WORKSPACE.COMPANY_CARD_DETAILS, - SCREENS.WORKSPACE.COMPANY_CARD_NAME, - SCREENS.WORKSPACE.COMPANY_CARD_EXPORT, - ], - [SCREENS.WORKSPACE.EXPENSIFY_CARD]: [ - SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW, - SCREENS.WORKSPACE.EXPENSIFY_CARD_BANK_ACCOUNT, - SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS, - SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_ACCOUNT, - SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_FREQUENCY, - SCREENS.WORKSPACE.EXPENSIFY_CARD_DETAILS, - SCREENS.WORKSPACE.EXPENSIFY_CARD_NAME, - SCREENS.WORKSPACE.EXPENSIFY_CARD_LIMIT, - SCREENS.WORKSPACE.EXPENSIFY_CARD_LIMIT_TYPE, - ], - [SCREENS.WORKSPACE.RULES]: [ - SCREENS.WORKSPACE.RULES_CUSTOM_NAME, - SCREENS.WORKSPACE.RULES_AUTO_APPROVE_REPORTS_UNDER, - SCREENS.WORKSPACE.RULES_RANDOM_REPORT_AUDIT, - SCREENS.WORKSPACE.RULES_AUTO_PAY_REPORTS_UNDER, - SCREENS.WORKSPACE.RULES_RECEIPT_REQUIRED_AMOUNT, - SCREENS.WORKSPACE.RULES_MAX_EXPENSE_AMOUNT, - SCREENS.WORKSPACE.RULES_MAX_EXPENSE_AGE, - SCREENS.WORKSPACE.RULES_BILLABLE_DEFAULT, - ], - [SCREENS.WORKSPACE.PER_DIEM]: [SCREENS.WORKSPACE.PER_DIEM_IMPORT, SCREENS.WORKSPACE.PER_DIEM_IMPORTED, SCREENS.WORKSPACE.PER_DIEM_SETTINGS], -}; - -export default WORKSPACE_SCREEN_TO_RHP_MAPPING; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts index fd492cd85800..1c4f684a9aed 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts @@ -3,7 +3,14 @@ import SCREENS from '@src/SCREENS'; // This file is used to define relation between workspace split navigator's central screens and RHP screens. const WORKSPACE_TO_RHP: Partial> = { - [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.ADDRESS, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE], + [SCREENS.WORKSPACE.PROFILE]: [ + SCREENS.WORKSPACE.NAME, + SCREENS.WORKSPACE.ADDRESS, + SCREENS.WORKSPACE.CURRENCY, + SCREENS.WORKSPACE.DESCRIPTION, + SCREENS.WORKSPACE.SHARE, + SCREENS.WORKSPACE.DOWNGRADE, + ], [SCREENS.WORKSPACE.MEMBERS]: [ SCREENS.WORKSPACE.INVITE, SCREENS.WORKSPACE.INVITE_MESSAGE, @@ -46,6 +53,30 @@ const WORKSPACE_TO_RHP: Partial Date: Wed, 11 Dec 2024 13:00:58 +0100 Subject: [PATCH 210/257] Add popToTop method to Navigation.ts --- src/libs/Navigation/Navigation.ts | 30 +++++++++---------- .../navigateAfterJoinRequest/index.desktop.ts | 2 +- src/libs/navigateAfterJoinRequest/index.ts | 2 +- .../navigateAfterJoinRequest/index.web.ts | 2 +- .../AddBankAccount/AddBankAccount.tsx | 4 +-- src/pages/EnablePayments/EnablePayments.tsx | 2 +- src/pages/home/ReportScreen.tsx | 4 +-- src/pages/workspace/WorkspaceJoinUserPage.tsx | 2 +- 8 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 623ce67a3957..81daa35e5768 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -202,17 +202,10 @@ type GoBackOptions = { * In that case we want to goUp to a country picker with any params so we don't compare them. */ compareParams?: boolean; - - /** - * Specifies whether goBack should pop to top when invoked. - * Additionaly, to execute popToTop, set the value of the global variable ShouldPopAllStateOnUP to true using the setShouldPopAllStateOnUP function. - */ - shouldPopToTop?: boolean; }; const defaultGoBackOptions: Required = { compareParams: true, - shouldPopToTop: false, }; /** @@ -274,21 +267,13 @@ function goUp(fallbackRoute: Route, options?: GoBackOptions) { /** * @param fallbackRoute - Fallback route if pop/goBack action should, but is not possible within RHP - * @param options - Optional configuration that affects navigation logic, e.g. whether goBack should popToTop. + * @param options - Optional configuration that affects navigation logic. */ function goBack(fallbackRoute?: Route, options?: GoBackOptions) { if (!canNavigate('goBack')) { return; } - if (options?.shouldPopToTop) { - if (shouldPopAllStateOnUP) { - shouldPopAllStateOnUP = false; - navigationRef.current?.dispatch(StackActions.popToTop()); - return; - } - } - if (fallbackRoute) { goUp(fallbackRoute, options); return; @@ -485,6 +470,18 @@ const dismissModalWithReport = (report: OnyxEntry) => { isNavigationReady().then(() => navigateToReportWithPolicyCheck({report})); }; +/** + * Returns to the first screen in the stack, dismissing all the others, only if the global variable shouldPopAllStateOnUP is set to true. + */ +function popToTop() { + if (!shouldPopAllStateOnUP) { + return; + } + + shouldPopAllStateOnUP = false; + navigationRef.current?.dispatch(StackActions.popToTop()); +} + export default { setShouldPopAllStateOnUP, navigate, @@ -508,6 +505,7 @@ export default { closeRHPFlow, setNavigationActionToMicrotaskQueue, navigateToReportWithPolicyCheck, + popToTop, }; export {navigationRef}; diff --git a/src/libs/navigateAfterJoinRequest/index.desktop.ts b/src/libs/navigateAfterJoinRequest/index.desktop.ts index 9b72ee30de57..461f5376e6c1 100644 --- a/src/libs/navigateAfterJoinRequest/index.desktop.ts +++ b/src/libs/navigateAfterJoinRequest/index.desktop.ts @@ -4,7 +4,7 @@ import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { // @TODO: Check if this method works the same as on the main branch - Navigation.goBack(undefined, {shouldPopToTop: true}); + Navigation.popToTop(); if (getIsSmallScreenWidth()) { Navigation.navigate(ROUTES.SETTINGS); } diff --git a/src/libs/navigateAfterJoinRequest/index.ts b/src/libs/navigateAfterJoinRequest/index.ts index a3ac50cd59be..91b2fdade606 100644 --- a/src/libs/navigateAfterJoinRequest/index.ts +++ b/src/libs/navigateAfterJoinRequest/index.ts @@ -3,7 +3,7 @@ import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { // @TODO: Check if this method works the same as on the main branch - Navigation.goBack(undefined, {shouldPopToTop: true}); + Navigation.popToTop(); Navigation.navigate(ROUTES.SETTINGS); Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); }; diff --git a/src/libs/navigateAfterJoinRequest/index.web.ts b/src/libs/navigateAfterJoinRequest/index.web.ts index 9b72ee30de57..461f5376e6c1 100644 --- a/src/libs/navigateAfterJoinRequest/index.web.ts +++ b/src/libs/navigateAfterJoinRequest/index.web.ts @@ -4,7 +4,7 @@ import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { // @TODO: Check if this method works the same as on the main branch - Navigation.goBack(undefined, {shouldPopToTop: true}); + Navigation.popToTop(); if (getIsSmallScreenWidth()) { Navigation.navigate(ROUTES.SETTINGS); } diff --git a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx index 060d5664ac93..a273b210efa9 100644 --- a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx +++ b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx @@ -52,7 +52,7 @@ function AddBankAccount() { PaymentMethods.continueSetup(onSuccessFallbackRoute); return; } - Navigation.goBack(ROUTES.SETTINGS_WALLET, {shouldPopToTop: true}); + Navigation.goBack(ROUTES.SETTINGS_WALLET); }; const handleBackButtonPress = () => { @@ -63,7 +63,7 @@ function AddBankAccount() { if (screenIndex === 0) { BankAccounts.clearPersonalBankAccount(); Wallet.updateCurrentStep(null); - Navigation.goBack(ROUTES.SETTINGS_WALLET, {shouldPopToTop: true}); + Navigation.goBack(ROUTES.SETTINGS_WALLET); return; } prevScreen(); diff --git a/src/pages/EnablePayments/EnablePayments.tsx b/src/pages/EnablePayments/EnablePayments.tsx index b8aeb4103a59..742202e43bb3 100644 --- a/src/pages/EnablePayments/EnablePayments.tsx +++ b/src/pages/EnablePayments/EnablePayments.tsx @@ -46,7 +46,7 @@ function EnablePaymentsPage() { > Navigation.goBack(ROUTES.SETTINGS_WALLET, {shouldPopToTop: true})} + onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_WALLET)} /> diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 0f80147cbfa4..be0b049e67d0 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -295,7 +295,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro return; } // @TODO: Check if this method works the same as on the main branch - Navigation.goBack(undefined, {shouldPopToTop: true}); + Navigation.popToTop(); }, [isInNarrowPaneModal]); let headerView = ( @@ -592,7 +592,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro if (Navigation.getTopmostReportId() === prevOnyxReportID) { Navigation.setShouldPopAllStateOnUP(true); // @TODO: Check if this method works the same as on the main branch - Navigation.goBack(undefined, {shouldPopToTop: true}); + Navigation.popToTop(); } if (prevReport?.parentReportID) { // Prevent navigation to the IOU/Expense Report if it is pending deletion. diff --git a/src/pages/workspace/WorkspaceJoinUserPage.tsx b/src/pages/workspace/WorkspaceJoinUserPage.tsx index 66caff7263ef..6e8333d75451 100644 --- a/src/pages/workspace/WorkspaceJoinUserPage.tsx +++ b/src/pages/workspace/WorkspaceJoinUserPage.tsx @@ -47,7 +47,7 @@ function WorkspaceJoinUserPage({route, policy}: WorkspaceJoinUserPageProps) { Navigation.isNavigationReady().then(() => { // @TODO: Check if this method works the same as on the main branch // NOTE: It probably doesn't need any params. When this method is called, shouldPopAllStateOnUP is always false - Navigation.goBack(undefined, {shouldPopToTop: true}); + Navigation.popToTop(); Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID ?? '-1')); }); return; From 097d3c5a024ae14fa38279f32b5067032d73036b Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 11 Dec 2024 13:23:33 +0100 Subject: [PATCH 211/257] Unification of comments in Navigation.ts --- src/libs/Navigation/Navigation.ts | 95 +++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 25 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 81daa35e5768..94b2df4aa957 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -36,15 +36,6 @@ import RELATIONS from './linkingConfig/RELATIONS'; import navigationRef from './navigationRef'; import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, State} from './types'; -// Get the sidebar screen parameters from the split navigator passed as a param -function getSidebarScreenParams(splitNavigatorRoute: NavigationStateRoute) { - if (splitNavigatorRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - return splitNavigatorRoute.state?.routes?.at(0)?.params; - } - - return undefined; -} - let resolveNavigationIsReadyPromise: () => void; const navigationIsReadyPromise = new Promise((resolve) => { resolveNavigationIsReadyPromise = resolve; @@ -61,6 +52,21 @@ function setShouldPopAllStateOnUP(shouldPopAllStateFlag: boolean) { shouldPopAllStateOnUP = shouldPopAllStateFlag; } +/** + * @private + * Get the sidebar screen parameters from the split navigator passed as a param. + */ +function getSidebarScreenParams(splitNavigatorRoute: NavigationStateRoute) { + if (splitNavigatorRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { + return splitNavigatorRoute.state?.routes?.at(0)?.params; + } + + return undefined; +} + +/** + * Checks if the navigationRef is ready to perform a method. + */ function canNavigate(methodName: string, params: Record = {}): boolean { if (navigationRef.isReady()) { return true; @@ -69,16 +75,24 @@ function canNavigate(methodName: string, params: Record = {}): return false; } -// Extracts from the topmost report its id. +/** + * Extracts from the topmost report its id. + */ const getTopmostReportId = (state = navigationRef.getState()) => getTopmostReportParams(state)?.reportID; -// Extracts from the topmost report its action id. +/** + * Extracts from the topmost report its action id. + */ const getTopmostReportActionId = (state = navigationRef.getState()) => getTopmostReportParams(state)?.reportActionID; -// Re-exporting the closeRHPFlow here to fill in default value for navigationRef. The closeRHPFlow isn't defined in this file to avoid cyclic dependencies. +/** + * Re-exporting the closeRHPFlow here to fill in default value for navigationRef. The closeRHPFlow isn't defined in this file to avoid cyclic dependencies. + */ const closeRHPFlow = (ref = navigationRef) => originalCloseRHPFlow(ref); -// Function that generates dynamic urls from paths passed from OldDot. +/** + * Function that generates dynamic urls from paths passed from OldDot. + */ function parseHybridAppUrl(url: HybridAppRoute | Route): Route { switch (url) { case HYBRID_APP_ROUTES.MONEY_REQUEST_CREATE_TAB_MANUAL: @@ -93,7 +107,9 @@ function parseHybridAppUrl(url: HybridAppRoute | Route): Route { } } -// Returns the current active route. +/** + * Returns the current active route. + */ function getActiveRoute(): string { const currentRoute = navigationRef.current && navigationRef.current.getCurrentRoute(); if (!currentRoute?.name) { @@ -108,7 +124,9 @@ function getActiveRoute(): string { return ''; } -// Returns the route of a report opened in RHP. +/** + * Returns the route of a report opened in RHP. + */ function getReportRHPActiveRoute(): string { if (isReportOpenInRHP(navigationRef.getRootState())) { return getActiveRoute(); @@ -155,11 +173,18 @@ function navigate(route: Route = ROUTES.HOME, type?: string) { */ const routeParamsIgnore = ['path', 'initial', 'params', 'state', 'screen', 'policyID']; -// If we use destructuring, we will get an error if any of the ignored properties are not present in the object. +/** + * @private + * If we use destructuring, we will get an error if any of the ignored properties are not present in the object. + */ function getRouteParamsToCompare(routeParams: Record) { return omit(routeParams, routeParamsIgnore); } +/** + * @private + * Private method used in goUp to determine whether a target route is present in the navigation state. + */ function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | NavigationPartialRoute, minimalAction: Writable, compareParams: boolean) { if (!minimalAction.payload) { return false; @@ -189,7 +214,10 @@ function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | Navi return shallowCompare(routeParams, minimalActionParams); } -// Checks whether the given state is the root navigator state +/** + * @private + * Checks whether the given state is the root navigator state + */ function isRootNavigatorState(state: State): state is State { return state.key === navigationRef.current?.getRootState().key; } @@ -209,6 +237,7 @@ const defaultGoBackOptions: Required = { }; /** + * @private * Navigate to the given fallbackRoute taking into account whether it is possible to go back to this screen. Within one nested navigator, we can go back by any number * of screens, but if as a result of going back we would have to remove more than one screen from the rootState, * replace is performed so as not to lose the visited pages. @@ -267,7 +296,7 @@ function goUp(fallbackRoute: Route, options?: GoBackOptions) { /** * @param fallbackRoute - Fallback route if pop/goBack action should, but is not possible within RHP - * @param options - Optional configuration that affects navigation logic. + * @param options - Optional configuration that affects navigation logic */ function goBack(fallbackRoute?: Route, options?: GoBackOptions) { if (!canNavigate('goBack')) { @@ -305,7 +334,9 @@ function goBack(fallbackRoute?: Route, options?: GoBackOptions) { navigationRef.current?.goBack(); } -// Reset the navigation state to Home page +/** + * Reset the navigation state to Home page. + */ function resetToHome() { const isNarrowLayout = getIsNarrowLayout(); const rootState = navigationRef.getRootState(); @@ -319,7 +350,9 @@ function resetToHome() { navigationRef.dispatch({payload, type: 'REPLACE', target: rootState.key}); } -// Update route params for the specified route. +/** + * Update route params for the specified route. + */ function setParams(params: Record, routeKey = '') { navigationRef.current?.dispatch({ ...CommonActions.setParams(params), @@ -327,12 +360,16 @@ function setParams(params: Record, routeKey = '') { }); } -// Returns the current active route without the URL params. +/** + * Returns the current active route without the URL params. + */ function getActiveRouteWithoutParams(): string { return getActiveRoute().replace(/\?.*/, ''); } -// Returns the active route name from a state event from the navigationRef. +/** + * Returns the active route name from a state event from the navigationRef. + */ function getRouteNameFromStateEvent(event: EventArg<'state', false, NavigationContainerEventMap['state']['data']>): string | undefined { if (!event.data.state) { return; @@ -346,6 +383,7 @@ function getRouteNameFromStateEvent(event: EventArg<'state', false, NavigationCo } /** + * @private * Navigate to the route that we originally intended to go to * but the NavigationContainer was not ready when navigate() was called */ @@ -368,6 +406,7 @@ function setIsNavigationReady() { } /** + * @private * Checks if the navigation state contains routes that are protected (over the auth wall). * * @param state - react-navigation state object @@ -412,7 +451,9 @@ function waitForProtectedRoutes() { }); } -// Changes the currently selected policy in the app. +/** + * Changes the currently selected policy in the app. + */ function switchPolicyID(policyID?: string) { navigationRef.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID, payload: {policyID}}); } @@ -455,7 +496,9 @@ function navigateToReportWithPolicyCheck({report, reportID, reportActionID, refe ); } -// Closes the modal navigator (RHP, LHP, onboarding). +/** + * Closes the modal navigator (RHP, LHP, onboarding). + */ const dismissModal = (reportID?: string, ref = navigationRef) => { ref.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL}); if (!reportID) { @@ -464,7 +507,9 @@ const dismissModal = (reportID?: string, ref = navigationRef) => { isNavigationReady().then(() => navigateToReportWithPolicyCheck({reportID})); }; -// Dismisses the modal and opens the given report. +/** + * Dismisses the modal and opens the given report. + */ const dismissModalWithReport = (report: OnyxEntry) => { dismissModal(); isNavigationReady().then(() => navigateToReportWithPolicyCheck({report})); From 0ae4aac4184dc1f420bd5a91b83beec5eefb830c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 11 Dec 2024 13:56:26 +0100 Subject: [PATCH 212/257] Fix goBack in navigateToConciergeChatAndDeleteReport --- src/libs/actions/Report.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index e62891dba5cb..8e675fd9fee2 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2418,11 +2418,13 @@ function deleteReport(reportID: string, shouldDeleteChildReports = false) { */ function navigateToConciergeChatAndDeleteReport(reportID: string, shouldPopToTop = false, shouldDeleteChildReports = false) { // Dismiss the current report screen and replace it with Concierge Chat + // @TODO: Check if this method works the same as on the main branch if (shouldPopToTop) { Navigation.setShouldPopAllStateOnUP(true); + Navigation.popToTop(); + } else { + Navigation.goBack(); } - // @TODO: Check if this method works the same as on the main branch - Navigation.goBack(undefined, {shouldPopToTop}); navigateToConciergeChat(); InteractionManager.runAfterInteractions(() => { deleteReport(reportID, shouldDeleteChildReports); From 27c6f925b59384c2a496efa27d08c06883a55718 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 12 Dec 2024 10:18:45 +0100 Subject: [PATCH 213/257] Simplify ActiveWorkspaceContextProvider --- .../ActiveWorkspaceProvider/index.tsx | 35 ++++--------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index b9e5f34d5389..0e9a23108483 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -1,41 +1,18 @@ import {useNavigationState} from '@react-navigation/native'; import React, {useEffect, useMemo, useState} from 'react'; import ActiveWorkspaceContext from '@components/ActiveWorkspace/ActiveWorkspaceContext'; -import * as SearchQueryUtils from '@libs/SearchQueryUtils'; -import NAVIGATORS from '@src/NAVIGATORS'; -import SCREENS from '@src/SCREENS'; +import {getPolicyIDFromState} from '@libs/Navigation/helpers'; +import type {RootStackParamList, State} from '@libs/Navigation/types'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; function ActiveWorkspaceContextProvider({children}: ChildrenProps) { - const [activeWorkspaceID, setActiveWorkspaceID] = useState(undefined); + const policyID = useNavigationState((state) => getPolicyIDFromState(state as State)); - const lastPolicyRoute = useNavigationState((state) => - state?.routes?.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.CENTRAL_PANE), - ); - - const policyIDFromRouteParam = lastPolicyRoute?.params && 'policyID' in lastPolicyRoute.params ? (lastPolicyRoute?.params?.policyID as string) : ''; - const queryFromRouteParam = lastPolicyRoute?.params && 'q' in lastPolicyRoute.params ? (lastPolicyRoute.params.q as string) : ''; + const [activeWorkspaceID, setActiveWorkspaceID] = useState(policyID); useEffect(() => { - if (policyIDFromRouteParam) { - setActiveWorkspaceID(policyIDFromRouteParam); - return; - } - - if (!queryFromRouteParam) { - setActiveWorkspaceID(undefined); - return; - } - - const queryJSON = SearchQueryUtils.buildSearchQueryJSON(queryFromRouteParam); - - if (!queryJSON) { - setActiveWorkspaceID(undefined); - return; - } - - setActiveWorkspaceID(SearchQueryUtils.getPolicyIDFromSearchQuery(queryJSON)); - }, [policyIDFromRouteParam, queryFromRouteParam, setActiveWorkspaceID]); + setActiveWorkspaceID(policyID); + }, [policyID, setActiveWorkspaceID]); const value = useMemo( () => ({ From 96289b156681d1b2b40993de0872084a5b5f5ccc Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 12 Dec 2024 13:00:26 +0100 Subject: [PATCH 214/257] Adjust BaseSidebarScreen workspace reset hook to split navigators --- .../SidebarScreen/BaseSidebarScreen.tsx | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx index e7b7725815c0..7dd4ce14acc3 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx @@ -1,3 +1,4 @@ +import {useRoute} from '@react-navigation/native'; import React, {useEffect, useRef} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; @@ -10,10 +11,14 @@ import {updateLastAccessedWorkspace} from '@libs/actions/Policy/Policy'; import * as Browser from '@libs/Browser'; import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import TopBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar'; +import getInitialSplitNavigatorState from '@libs/Navigation/AppNavigator/createSplitNavigator/getInitialSplitNavigatorState'; +import {getPreservedSplitNavigatorState} from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; +import navigationRef from '@libs/Navigation/navigationRef'; import Performance from '@libs/Performance'; import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData'; import Timing from '@userActions/Timing'; import CONST from '@src/CONST'; +import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import SCREENS from '@src/SCREENS'; @@ -23,6 +28,7 @@ function BaseSidebarScreen() { const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const [activeWorkspace] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activeWorkspaceID ?? -1}`); + const currentRoute = useRoute(); useEffect(() => { Performance.markStart(CONST.TIMING.SIDEBAR_LOADED); @@ -47,8 +53,26 @@ function BaseSidebarScreen() { return; } + const topmostReport = navigationRef.getRootState()?.routes.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + + if (!topmostReport) { + return; + } + + // Switching workspace to global should only be performed from the currently opened sidebar screen + const topmostReportState = topmostReport?.state ?? getPreservedSplitNavigatorState(topmostReport?.key); + const isCurrentSidebar = topmostReportState?.routes.some((route) => currentRoute.key === route.key); + + if (!isCurrentSidebar) { + return; + } + isSwitchingWorkspace.current = true; - // Navigation.navigateWithSwitchPolicyID({policyID: undefined}); + navigationRef.current?.dispatch({ + target: navigationRef.current.getRootState().key, + payload: getInitialSplitNavigatorState({name: SCREENS.HOME}, {name: SCREENS.REPORT}), + type: CONST.NAVIGATION.ACTION_TYPE.REPLACE, + }); updateLastAccessedWorkspace(undefined); }, [activeWorkspace, activeWorkspaceID]); From 18ad376c236d6e4a920241a289244029b286cd9f Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 12 Dec 2024 13:05:44 +0100 Subject: [PATCH 215/257] Remove Navigation.switchPolicyID --- src/libs/Navigation/Navigation.ts | 8 -------- src/pages/WorkspaceSwitcherPage/index.tsx | 4 ++-- src/pages/workspace/WorkspaceProfilePage.tsx | 7 +------ src/pages/workspace/WorkspacesListPage.tsx | 5 ----- 4 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 94b2df4aa957..75d61a8a2d7f 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -451,13 +451,6 @@ function waitForProtectedRoutes() { }); } -/** - * Changes the currently selected policy in the app. - */ -function switchPolicyID(policyID?: string) { - navigationRef.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID, payload: {policyID}}); -} - type NavigateToReportWithPolicyCheckPayload = {report?: OnyxEntry; reportID?: string; reportActionID?: string; referrer?: string; policyIDToCheck?: string}; /** @@ -545,7 +538,6 @@ export default { getTopmostReportActionId, waitForProtectedRoutes, parseHybridAppUrl, - switchPolicyID, resetToHome, closeRHPFlow, setNavigationActionToMicrotaskQueue, diff --git a/src/pages/WorkspaceSwitcherPage/index.tsx b/src/pages/WorkspaceSwitcherPage/index.tsx index 6c8660c46a75..e5312d763e04 100644 --- a/src/pages/WorkspaceSwitcherPage/index.tsx +++ b/src/pages/WorkspaceSwitcherPage/index.tsx @@ -11,7 +11,7 @@ import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; -import Navigation from '@libs/Navigation/Navigation'; +import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import {sortWorkspacesBySelected} from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -86,7 +86,7 @@ function WorkspaceSwitcherPage() { Navigation.goBack(); if (policyID !== activeWorkspaceID) { - Navigation.switchPolicyID(newPolicyID); + navigationRef.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID, payload: {policyID: newPolicyID}}); } }, [activeWorkspaceID, isFocused], diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index fd82df407145..e3407939741a 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -135,12 +135,7 @@ function WorkspaceProfilePage({policyDraft, policy: policyProp, route}: Workspac Policy.deleteWorkspace(policy?.id, policyName); setIsDeleteModalOpen(false); - - // If the workspace being deleted is the active workspace, switch to the "All Workspaces" view - if (activeWorkspaceID === policy?.id) { - Navigation.switchPolicyID(undefined); - } - }, [policy?.id, policyName, activeWorkspaceID]); + }, [policy?.id, policyName]); return ( Date: Thu, 12 Dec 2024 17:02:13 +0100 Subject: [PATCH 216/257] Adjust createInverseRelation, fix SPLIT_TO_SIDEBAR --- src/libs/Navigation/linkingConfig/RELATIONS/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/index.ts b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts index 3c4c9140d2d8..eed5e8d78b39 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/index.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts @@ -4,11 +4,11 @@ import SIDEBAR_TO_RHP from './SIDEBAR_TO_RHP'; import SIDEBAR_TO_SPLIT from './SIDEBAR_TO_SPLIT'; import WORKSPACE_TO_RHP from './WORKSPACE_TO_RHP'; -function createInverseRelation(relations: Partial>): Record { +function createInverseRelation(relations: Partial>): Record { const reversedRelations = {} as Record; Object.entries(relations).forEach(([key, values]) => { - const valuesWithType = values as K[]; + const valuesWithType = (Array.isArray(values) ? values : [values]) as K[]; valuesWithType.forEach((value: K) => { reversedRelations[value] = key as T; }); @@ -25,5 +25,5 @@ export default { SIDEBAR_TO_RHP, WORKSPACE_TO_RHP, SIDEBAR_TO_SPLIT, - SPLIT_TO_SIDEBAR: createInverseRelation(SIDEBAR_TO_RHP), + SPLIT_TO_SIDEBAR: createInverseRelation(SIDEBAR_TO_SPLIT), }; From 0a11e294e36aaf739a2e8ac8ee4260a2f292716a Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 12 Dec 2024 17:02:48 +0100 Subject: [PATCH 217/257] Fix Navigation.popToTop --- src/libs/Navigation/Navigation.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 75d61a8a2d7f..4f9115c82128 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -513,6 +513,7 @@ const dismissModalWithReport = (report: OnyxEntry) => { */ function popToTop() { if (!shouldPopAllStateOnUP) { + goBack(); return; } From 5117a9f383e55e93d9588157b92fcfff8b881a0e Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 13 Dec 2024 12:04:05 +0100 Subject: [PATCH 218/257] Adjust ResizeScreenTests to SplitNavigator structure --- tests/ui/ResizeScreenTests.tsx | 203 +++++++++++++++++---------------- 1 file changed, 106 insertions(+), 97 deletions(-) diff --git a/tests/ui/ResizeScreenTests.tsx b/tests/ui/ResizeScreenTests.tsx index 552e84b31155..15b83413bc68 100644 --- a/tests/ui/ResizeScreenTests.tsx +++ b/tests/ui/ResizeScreenTests.tsx @@ -1,97 +1,106 @@ -// @TODO: Adjust this test to the SplitNavigator structure - -// import {NavigationContainer} from '@react-navigation/native'; -// import {render, renderHook} from '@testing-library/react-native'; -// import React from 'react'; -// import useResponsiveLayout from '@hooks/useResponsiveLayout'; -// import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; -// import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -// import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator'; -// import BottomTabNavigator from '@libs/Navigation/AppNavigator/Navigators/BottomTabNavigator'; -// import useNavigationResetRootOnLayoutChange from '@libs/Navigation/AppNavigator/useNavigationResetRootOnLayoutChange'; -// import navigationRef from '@libs/Navigation/navigationRef'; -// import type {AuthScreensParamList} from '@libs/Navigation/types'; -// import ProfilePage from '@pages/settings/Profile/ProfilePage'; -// import NAVIGATORS from '@src/NAVIGATORS'; -// import SCREENS from '@src/SCREENS'; - -// const RootStack = createResponsiveStackNavigator(); - -// jest.mock('@hooks/useResponsiveLayout', () => jest.fn()); -// jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); - -// jest.mock('@pages/settings/InitialSettingsPage'); -// jest.mock('@pages/settings/Profile/ProfilePage'); -// jest.mock('@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'); - -// const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: ResponsiveLayoutResult = { -// shouldUseNarrowLayout: true, -// isSmallScreenWidth: true, -// isInNarrowPaneModal: false, -// isExtraSmallScreenHeight: false, -// isMediumScreenWidth: false, -// isLargeScreenWidth: false, -// isExtraSmallScreenWidth: false, -// isSmallScreen: false, -// onboardingIsMediumOrLargerScreenWidth: false, -// }; - -// const INITIAL_STATE = { -// routes: [ -// { -// name: NAVIGATORS.BOTTOM_TAB_NAVIGATOR, -// state: { -// index: 1, -// routes: [{name: SCREENS.HOME}, {name: SCREENS.SETTINGS.ROOT}], -// }, -// }, -// ], -// }; - -// const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; -// const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; - -// describe('Resize screen', () => { -// it('Should display the settings profile after resizing the screen with the settings page opened to the wide layout', () => { -// // Given the initialized navigation on the narrow layout with the settings screen -// mockedGetIsNarrowLayout.mockReturnValue(true); -// mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); - -// const {rerender} = renderHook(() => useNavigationResetRootOnLayoutChange()); - -// render( -// -// -// - -// -// -// , -// ); - -// const rootStateBeforeResize = navigationRef.current?.getRootState(); - -// expect(rootStateBeforeResize?.routes.at(0)?.name).toBe(NAVIGATORS.BOTTOM_TAB_NAVIGATOR); -// expect(rootStateBeforeResize?.routes.at(1)).toBeUndefined(); - -// // When resizing the screen to the wide layout -// mockedGetIsNarrowLayout.mockReturnValue(false); -// mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: false}); -// rerender({}); - -// const rootStateAfterResize = navigationRef.current?.getRootState(); - -// // Then the settings profile page should be displayed on the screen -// expect(rootStateAfterResize?.routes.at(0)?.name).toBe(NAVIGATORS.BOTTOM_TAB_NAVIGATOR); -// expect(rootStateAfterResize?.routes.at(1)?.name).toBe(SCREENS.SETTINGS.PROFILE.ROOT); -// }); -// }); +import type {ParamListBase} from '@react-navigation/native'; +import {NavigationContainer} from '@react-navigation/native'; +import {render, renderHook} from '@testing-library/react-native'; +import React from 'react'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; +import getIsNarrowLayout from '@libs/getIsNarrowLayout'; +import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; +import useNavigationResetOnLayoutChange from '@libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange'; +import navigationRef from '@libs/Navigation/navigationRef'; +import type {CustomEffectsHookProps} from '@libs/Navigation/PlatformStackNavigation/types'; +import type {SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; +import InitialSettingsPage from '@pages/settings/InitialSettingsPage'; +import ProfilePage from '@pages/settings/Profile/ProfilePage'; +import SCREENS from '@src/SCREENS'; + +const Split = createSplitNavigator(); + +jest.mock('@hooks/useResponsiveLayout', () => jest.fn()); +jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); + +jest.mock('@pages/settings/InitialSettingsPage'); +jest.mock('@pages/settings/Profile/ProfilePage'); + +const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: ResponsiveLayoutResult = { + shouldUseNarrowLayout: true, + isSmallScreenWidth: true, + isInNarrowPaneModal: false, + isExtraSmallScreenHeight: false, + isMediumScreenWidth: false, + isLargeScreenWidth: false, + isExtraSmallScreenWidth: false, + isSmallScreen: false, + onboardingIsMediumOrLargerScreenWidth: false, +}; + +const INITIAL_STATE = { + index: 0, + routes: [ + { + name: SCREENS.SETTINGS.ROOT, + }, + ], +}; + +const PARENT_ROUTE = {key: 'parentRouteKey', name: 'ParentNavigator'}; + +const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; +const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; + +describe('Resize screen', () => { + it('Should display the settings profile after resizing the screen with the settings page opened to the wide layout', () => { + // Given the initialized navigation on the narrow layout with the settings screen + mockedGetIsNarrowLayout.mockReturnValue(true); + mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); + + render( + + + + + + , + ); + + const {rerender} = renderHook(() => + useNavigationResetOnLayoutChange({ + navigation: navigationRef.current as unknown as CustomEffectsHookProps['navigation'], + displayName: 'SplitNavigator', + descriptors: {}, + state: navigationRef.current?.getState() as CustomEffectsHookProps['state'], + }), + ); + + const rootStateBeforeResize = navigationRef.current?.getRootState(); + + expect(rootStateBeforeResize?.routes.at(0)?.name).toBe(SCREENS.SETTINGS.ROOT); + expect(rootStateBeforeResize?.routes.at(1)).toBeUndefined(); + expect(rootStateBeforeResize?.index).toBe(0); + + // When resizing the screen to the wide layout + mockedGetIsNarrowLayout.mockReturnValue(false); + mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: false}); + rerender({}); + + const rootStateAfterResize = navigationRef.current?.getRootState(); + + // Then the settings profile page should be displayed on the screen + expect(rootStateAfterResize?.routes.at(0)?.name).toBe(SCREENS.SETTINGS.ROOT); + expect(rootStateAfterResize?.routes.at(1)?.name).toBe(SCREENS.SETTINGS.PROFILE.ROOT); + expect(rootStateAfterResize?.index).toBe(1); + }); +}); From 08f5c9d1f52c40a98836f7f1afe39190d00e9540 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 13 Dec 2024 12:05:31 +0100 Subject: [PATCH 219/257] Fix goBack types --- src/libs/Navigation/Navigation.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 4f9115c82128..4d4370a3ab9d 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -34,7 +34,7 @@ import { import linkingConfig from './linkingConfig'; import RELATIONS from './linkingConfig/RELATIONS'; import navigationRef from './navigationRef'; -import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, State} from './types'; +import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, SplitNavigatorName, State} from './types'; let resolveNavigationIsReadyPromise: () => void; const navigationIsReadyPromise = new Promise((resolve) => { @@ -314,10 +314,10 @@ function goBack(fallbackRoute?: Route, options?: GoBackOptions) { const canGoBack = navigationRef.current?.canGoBack(); if (!canGoBack && isSplitNavigatorName(lastRoute?.name) && lastRoute?.state?.routes?.length === 1) { - const name = RELATIONS.SPLIT_TO_SIDEBAR[lastRoute.name]; + const name = RELATIONS.SPLIT_TO_SIDEBAR[lastRoute.name as SplitNavigatorName]; const params = getSidebarScreenParams(lastRoute); navigationRef.dispatch({ - type: 'REPLACE', + type: CONST.NAVIGATION.ACTION_TYPE.REPLACE, payload: { name, params, From 579608e8a7e0be09db7084298508ec801f5eeffe Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 13 Dec 2024 12:05:49 +0100 Subject: [PATCH 220/257] Remove useNavigationResetRootOnLayoutChange --- .../useNavigationResetRootOnLayoutChange.ts | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100644 src/libs/Navigation/AppNavigator/useNavigationResetRootOnLayoutChange.ts diff --git a/src/libs/Navigation/AppNavigator/useNavigationResetRootOnLayoutChange.ts b/src/libs/Navigation/AppNavigator/useNavigationResetRootOnLayoutChange.ts deleted file mode 100644 index 03caac57410f..000000000000 --- a/src/libs/Navigation/AppNavigator/useNavigationResetRootOnLayoutChange.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {useEffect} from 'react'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import navigationRef from '@libs/Navigation/navigationRef'; - -/** - * This hook resets the navigation root state when changing the layout size, resetting the state calls the getRehydredState method in CustomRouter.ts. - * When the screen size is changed, it is necessary to check whether the application displays the content correctly. - * When the app is opened on a small layout and the user resizes it to wide, a second screen has to be present in the navigation state to fill the space. - */ -function useNavigationResetRootOnLayoutChange() { - const {shouldUseNarrowLayout} = useResponsiveLayout(); - - useEffect(() => { - if (!navigationRef.isReady()) { - return; - } - navigationRef.resetRoot(navigationRef.getRootState()); - }, [shouldUseNarrowLayout]); -} - -export default useNavigationResetRootOnLayoutChange; From 79202d17e5b71b823676e7f86b7ad96f4a1cef14 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 17 Dec 2024 11:09:19 +0100 Subject: [PATCH 221/257] Fix go back using swipe from not found policy page --- .../createSplitNavigator/SplitRouter.ts | 37 +++++++++++++- src/libs/Navigation/Navigation.ts | 50 ++++++------------- .../workspace/AccessOrNotFoundWrapper.tsx | 9 ++++ 3 files changed, 60 insertions(+), 36 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts index 454b13f59417..e923569ccbb1 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts @@ -1,9 +1,13 @@ import type {CommonActions, ParamListBase, PartialState, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; import {StackActions, StackRouter} from '@react-navigation/native'; import pick from 'lodash/pick'; +import Onyx from 'react-native-onyx'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import {getParamsFromRoute} from '@libs/Navigation/helpers'; import navigationRef from '@libs/Navigation/navigationRef'; +import type {NavigationPartialRoute} from '@libs/Navigation/types'; +import * as PolicyUtils from '@libs/PolicyUtils'; +import ONYXKEYS from '@src/ONYXKEYS'; import SCREENS from '@src/SCREENS'; import type {SplitNavigatorRouterOptions} from './types'; import {getPreservedSplitNavigatorState} from './usePreserveSplitNavigatorState'; @@ -17,15 +21,44 @@ type AdaptStateIfNecessaryArgs = { options: SplitNavigatorRouterOptions; }; +let isLoadingReportData = true; +Onyx.connect({ + key: ONYXKEYS.IS_LOADING_REPORT_DATA, + initWithStoredValues: false, + callback: (value) => (isLoadingReportData = value ?? false), +}); + +function isInvalidPolicyPage(route: NavigationPartialRoute) { + const hasRoutePolicyID = route?.params && 'policyID' in route.params; + + if (!hasRoutePolicyID) { + return false; + } + + const policyID = route?.params?.policyID as string; + const policy = PolicyUtils.getPolicy(policyID); + + if (!policy) { + return false; + } + + return !PolicyUtils.isPolicyAccessible(policy) && !isLoadingReportData; +} + function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralScreen, parentRoute}}: AdaptStateIfNecessaryArgs) { const isNarrowLayout = getIsNarrowLayout(); - const lastRoute = state.routes.at(-1); + const lastRoute = state.routes.at(-1) as NavigationPartialRoute; + + // If invalid policy page is displayed on narrow layout, sidebar screen should not be pushed to the navigation state to avoid adding reduntant not found page + if (isNarrowLayout && isInvalidPolicyPage(lastRoute)) { + return; + } // If the screen is wide, there should be at least two screens inside: // - sidebarScreen to cover left pane. // - defaultCentralScreen to cover central pane. - if (!isAtLeastOneInState(state, sidebarScreen) && !isNarrowLayout) { + if (!isAtLeastOneInState(state, sidebarScreen)) { const paramsFromRoute = getParamsFromRoute(sidebarScreen); let params = pick(lastRoute?.params, paramsFromRoute); diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 4d4370a3ab9d..9bf0375a8d74 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -26,15 +26,13 @@ import { getStateFromPath, getTopmostReportParams, isReportOpenInRHP, - isSplitNavigatorName, linkTo, closeRHPFlow as originalCloseRHPFlow, setNavigationActionToMicrotaskQueue, } from './helpers'; import linkingConfig from './linkingConfig'; -import RELATIONS from './linkingConfig/RELATIONS'; import navigationRef from './navigationRef'; -import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, SplitNavigatorName, State} from './types'; +import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, State} from './types'; let resolveNavigationIsReadyPromise: () => void; const navigationIsReadyPromise = new Promise((resolve) => { @@ -52,18 +50,6 @@ function setShouldPopAllStateOnUP(shouldPopAllStateFlag: boolean) { shouldPopAllStateOnUP = shouldPopAllStateFlag; } -/** - * @private - * Get the sidebar screen parameters from the split navigator passed as a param. - */ -function getSidebarScreenParams(splitNavigatorRoute: NavigationStateRoute) { - if (splitNavigatorRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - return splitNavigatorRoute.state?.routes?.at(0)?.params; - } - - return undefined; -} - /** * Checks if the navigationRef is ready to perform a method. */ @@ -308,25 +294,7 @@ function goBack(fallbackRoute?: Route, options?: GoBackOptions) { return; } - const rootState = navigationRef.current?.getRootState(); - const lastRoute = rootState?.routes.at(-1); - - const canGoBack = navigationRef.current?.canGoBack(); - - if (!canGoBack && isSplitNavigatorName(lastRoute?.name) && lastRoute?.state?.routes?.length === 1) { - const name = RELATIONS.SPLIT_TO_SIDEBAR[lastRoute.name as SplitNavigatorName]; - const params = getSidebarScreenParams(lastRoute); - navigationRef.dispatch({ - type: CONST.NAVIGATION.ACTION_TYPE.REPLACE, - payload: { - name, - params, - }, - }); - return; - } - - if (!canGoBack) { + if (!navigationRef.current?.canGoBack()) { Log.hmmm('[Navigation] Unable to go back'); return; } @@ -521,6 +489,19 @@ function popToTop() { navigationRef.current?.dispatch(StackActions.popToTop()); } +function removeScreenFromNavigationState(screen: string) { + isNavigationReady().then(() => { + navigationRef.current?.dispatch((state) => { + const routes = state.routes?.filter((item) => item.name !== screen); + return CommonActions.reset({ + ...state, + routes, + index: routes.length < state.routes.length ? state.index - 1 : state.index, + }); + }); + }); +} + export default { setShouldPopAllStateOnUP, navigate, @@ -544,6 +525,7 @@ export default { setNavigationActionToMicrotaskQueue, navigateToReportWithPolicyCheck, popToTop, + removeScreenFromNavigationState, }; export {navigationRef}; diff --git a/src/pages/workspace/AccessOrNotFoundWrapper.tsx b/src/pages/workspace/AccessOrNotFoundWrapper.tsx index 39ac7b2f9451..ff15dcdeffbd 100644 --- a/src/pages/workspace/AccessOrNotFoundWrapper.tsx +++ b/src/pages/workspace/AccessOrNotFoundWrapper.tsx @@ -17,6 +17,7 @@ import type {IOUType} from '@src/CONST'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import type {PolicyFeatureName} from '@src/types/onyx/Policy'; import callOrReturn from '@src/types/utils/callOrReturn'; @@ -165,6 +166,14 @@ function AccessOrNotFoundWrapper({ setIsPolicyFeatureEnabled(isFeatureEnabled); }, [pendingField, isOffline, isFeatureEnabled]); + useEffect(() => { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + if (isLoadingReportData || !isPolicyNotAccessible) { + return; + } + Navigation.removeScreenFromNavigationState(SCREENS.WORKSPACE.INITIAL); + }, [isLoadingReportData, isPolicyNotAccessible]); + if (shouldShowFullScreenLoadingIndicator) { return ; } From 9f5bccbb0dcb99742d5028e141ab1ff96f72c08c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 17 Dec 2024 11:29:58 +0100 Subject: [PATCH 222/257] Hide bottom tab on workspace initial page when policy is not found --- src/pages/workspace/WorkspaceInitialPage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index a0c4d9844eb4..7f99e7e9eca8 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -390,11 +390,13 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac }; }, [policy]); + const shouldShowBottomTab = !shouldShowNotFoundPage; + return ( } + bottomContent={shouldShowBottomTab ? : null} > Date: Tue, 17 Dec 2024 17:00:39 +0100 Subject: [PATCH 223/257] Simplify getAdaptedState --- src/libs/Navigation/NavigationRoot.tsx | 6 ++-- .../helpers/getAdaptedStateFromPath.ts | 30 ++++++------------- src/libs/Navigation/linkingConfig/index.ts | 7 +---- src/libs/actions/Welcome/OnboardingFlow.ts | 2 +- 4 files changed, 13 insertions(+), 32 deletions(-) diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index a8af25db8e62..b2d85e13efba 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -103,8 +103,7 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh // If the user haven't completed the flow, we want to always redirect them to the onboarding flow. // We also make sure that the user is authenticated. if (!NativeModules.HybridAppModule && !isOnboardingCompleted && authenticated && !shouldShowRequire2FAModal) { - const {adaptedState} = getAdaptedStateFromPath(getOnboardingInitialPath(), linkingConfig.config); - return adaptedState; + return getAdaptedStateFromPath(getOnboardingInitialPath(), linkingConfig.config); } // If there is no lastVisitedPath, we can do early return. We won't modify the default behavior. @@ -122,8 +121,7 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh } // Otherwise we want to redirect the user to the last visited path. - const {adaptedState} = getAdaptedStateFromPath(lastVisitedPath, linkingConfig.config); - return adaptedState; + return getAdaptedStateFromPath(lastVisitedPath, linkingConfig.config); // The initialState value is relevant only on the first render. // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps diff --git a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts index 8a2886c36f27..dda5fb85e519 100644 --- a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts @@ -16,9 +16,7 @@ import getParamsFromRoute from './getParamsFromRoute'; import {isFullScreenName} from './isNavigatorName'; import replacePathInNestedState from './replacePathInNestedState'; -type GetAdaptedStateReturnType = { - adaptedState: ReturnType; -}; +type GetAdaptedStateReturnType = ReturnType; type GetAdaptedStateFromPath = (...args: [...Parameters, shouldReplacePathInNestedState?: boolean]) => GetAdaptedStateReturnType; @@ -161,19 +159,17 @@ function getOnboardingAdaptedState(state: PartialState): Partia function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { const fullScreenRoute = state.routes.find((route) => isFullScreenName(route.name)); - const reportsSplitNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); const onboardingNavigator = state.routes.find((route) => route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR); + const isReportSplitNavigator = fullScreenRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; // If policyID is defined, it should be passed to the reportNavigator params. - if (reportsSplitNavigator && policyID) { + if (isReportSplitNavigator && policyID) { const routes = []; - const reportNavigatorWithPolicyID = {...reportsSplitNavigator}; + const reportNavigatorWithPolicyID = {...fullScreenRoute}; reportNavigatorWithPolicyID.params = {...reportNavigatorWithPolicyID.params, policyID}; routes.push(reportNavigatorWithPolicyID); - return { - adaptedState: getRoutesWithIndex(routes), - }; + return getRoutesWithIndex(routes); } // If there is no full screen route in the root, we want to add it. @@ -184,9 +180,7 @@ function getAdaptedState(state: PartialState const matchingRootRoute = getMatchingFullScreenRoute(focusedRoute, policyID); // If there is a matching root route, add it to the state. if (matchingRootRoute) { - return { - adaptedState: getRoutesWithIndex([matchingRootRoute, ...state.routes]), - }; + return getRoutesWithIndex([matchingRootRoute, ...state.routes]); } } @@ -199,20 +193,14 @@ function getAdaptedState(state: PartialState state: getOnboardingAdaptedState(onboardingNavigator.state), }; - return { - adaptedState: getRoutesWithIndex([defaultFullScreenRoute, adaptedOnboardingNavigator]), - }; + return getRoutesWithIndex([defaultFullScreenRoute, adaptedOnboardingNavigator]); } // If not, add the default full screen route. - return { - adaptedState: getRoutesWithIndex([defaultFullScreenRoute, ...state.routes]), - }; + return getRoutesWithIndex([defaultFullScreenRoute, ...state.routes]); } - return { - adaptedState: state, - }; + return state; } const getAdaptedStateFromPath: GetAdaptedStateFromPath = (path, options, shouldReplacePathInNestedState = true) => { diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index dcdd14241cff..483928e7011d 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -7,12 +7,7 @@ import config from './config'; import prefixes from './prefixes'; const linkingConfig: LinkingOptions = { - getStateFromPath: (...args) => { - const {adaptedState} = getAdaptedStateFromPath(...args); - - // ResultState | undefined is the type this function expect. - return adaptedState; - }, + getStateFromPath: getAdaptedStateFromPath, getPathFromState: customGetPathFromState, prefixes, config, diff --git a/src/libs/actions/Welcome/OnboardingFlow.ts b/src/libs/actions/Welcome/OnboardingFlow.ts index 3908f372b891..9de902c5792d 100644 --- a/src/libs/actions/Welcome/OnboardingFlow.ts +++ b/src/libs/actions/Welcome/OnboardingFlow.ts @@ -39,7 +39,7 @@ Onyx.connect({ */ function startOnboardingFlow() { const currentRoute = navigationRef.getCurrentRoute(); - const {adaptedState} = getAdaptedStateFromPath(getOnboardingInitialPath(), linkingConfig.config, false); + const adaptedState = getAdaptedStateFromPath(getOnboardingInitialPath(), linkingConfig.config, false); const focusedRoute = findFocusedRoute(adaptedState as PartialState>); if (focusedRoute?.name === currentRoute?.name) { return; From e7a51507f5ce7bde985310d59e8b3aa528329b7d Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 18 Dec 2024 10:58:42 +0100 Subject: [PATCH 224/257] Add comment to NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR linking config --- src/libs/Navigation/linkingConfig/config.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 18965cf94b62..7b9702de229c 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1514,6 +1514,8 @@ const config: LinkingOptions['config'] = { }, [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: { + // The path given as initialRouteName does not have route params. + // initialRouteName is not defined in this split navigator because in this case the initial route requires a policyID defined in its route params. screens: { [SCREENS.WORKSPACE.INITIAL]: { path: ROUTES.WORKSPACE_INITIAL.route, From 49c49f961ced438c0099b78b356b85689046e920 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 18 Dec 2024 11:37:16 +0100 Subject: [PATCH 225/257] Handle adding SettingsSplit under WorkspaceSplit in getAdaptedState --- .../Navigation/helpers/getAdaptedStateFromPath.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts index dda5fb85e519..b480557e6dc0 100644 --- a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts @@ -161,6 +161,7 @@ function getAdaptedState(state: PartialState const fullScreenRoute = state.routes.find((route) => isFullScreenName(route.name)); const onboardingNavigator = state.routes.find((route) => route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR); const isReportSplitNavigator = fullScreenRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; + const isWorkspaceSplitNavigator = fullScreenRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR; // If policyID is defined, it should be passed to the reportNavigator params. if (isReportSplitNavigator && policyID) { @@ -172,15 +173,26 @@ function getAdaptedState(state: PartialState return getRoutesWithIndex(routes); } + if (isWorkspaceSplitNavigator) { + const settingsSplitRoute = getInitialSplitNavigatorState({name: SCREENS.SETTINGS.ROOT}, {name: SCREENS.SETTINGS.WORKSPACES}); + return getRoutesWithIndex([settingsSplitRoute, ...state.routes]); + } + // If there is no full screen route in the root, we want to add it. if (!fullScreenRoute) { const focusedRoute = findFocusedRoute(state); if (focusedRoute) { const matchingRootRoute = getMatchingFullScreenRoute(focusedRoute, policyID); + // If there is a matching root route, add it to the state. if (matchingRootRoute) { - return getRoutesWithIndex([matchingRootRoute, ...state.routes]); + const routes = [matchingRootRoute, ...state.routes]; + if (matchingRootRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { + const settingsSplitRoute = getInitialSplitNavigatorState({name: SCREENS.SETTINGS.ROOT}, {name: SCREENS.SETTINGS.WORKSPACES}); + routes.unshift(settingsSplitRoute); + } + return getRoutesWithIndex(routes); } } From 4620ac7a9d6cc8a17f4376886bfef638610d60b3 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 18 Dec 2024 12:41:08 +0100 Subject: [PATCH 226/257] Add shouldDisplayPolicyNotFoundPage --- .../createSplitNavigator/SplitRouter.ts | 27 ++++++------------- src/libs/PolicyUtils.ts | 19 +++++++++++++ 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts index e923569ccbb1..80b85a071e4f 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts @@ -21,38 +21,27 @@ type AdaptStateIfNecessaryArgs = { options: SplitNavigatorRouterOptions; }; -let isLoadingReportData = true; -Onyx.connect({ - key: ONYXKEYS.IS_LOADING_REPORT_DATA, - initWithStoredValues: false, - callback: (value) => (isLoadingReportData = value ?? false), -}); - -function isInvalidPolicyPage(route: NavigationPartialRoute) { +function getRoutePolicyID(route: NavigationPartialRoute): string | undefined { const hasRoutePolicyID = route?.params && 'policyID' in route.params; if (!hasRoutePolicyID) { - return false; + return undefined; } - const policyID = route?.params?.policyID as string; - const policy = PolicyUtils.getPolicy(policyID); - - if (!policy) { - return false; - } - - return !PolicyUtils.isPolicyAccessible(policy) && !isLoadingReportData; + return route?.params?.policyID as string; } function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralScreen, parentRoute}}: AdaptStateIfNecessaryArgs) { const isNarrowLayout = getIsNarrowLayout(); const lastRoute = state.routes.at(-1) as NavigationPartialRoute; + const routePolicyID = getRoutePolicyID(lastRoute); // If invalid policy page is displayed on narrow layout, sidebar screen should not be pushed to the navigation state to avoid adding reduntant not found page - if (isNarrowLayout && isInvalidPolicyPage(lastRoute)) { - return; + if (isNarrowLayout && !!routePolicyID) { + if (PolicyUtils.shouldDisplayPolicyNotFoundPage(routePolicyID)) { + return; + } } // If the screen is wide, there should be at least two screens inside: diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index f6b277d69d6b..52b43deae5f0 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -55,6 +55,7 @@ type ConnectionWithLastSyncData = { let allPolicies: OnyxCollection; let activePolicyId: OnyxEntry; +let isLoadingReportData = true; Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY, @@ -67,6 +68,12 @@ Onyx.connect({ callback: (value) => (activePolicyId = value), }); +Onyx.connect({ + key: ONYXKEYS.IS_LOADING_REPORT_DATA, + initWithStoredValues: false, + callback: (value) => (isLoadingReportData = value ?? false), +}); + /** * Filter out the active policies, which will exclude policies with pending deletion * These are policies that we can use to create reports with in NewDot. @@ -1131,6 +1138,17 @@ function areAllGroupPoliciesExpenseChatDisabled(policies = allPolicies) { return !groupPolicies.some((policy) => !!policy?.isPolicyExpenseChatEnabled); } +// eslint-disable-next-line rulesdir/no-negated-variables +function shouldDisplayPolicyNotFoundPage(policyID: string): boolean { + const policy = getPolicy(policyID); + + if (!policy) { + return false; + } + + return !isPolicyAccessible(policy) && !isLoadingReportData; +} + export { canEditTaxRate, extractPolicyIDFromPath, @@ -1254,6 +1272,7 @@ export { getActivePolicy, isPolicyAccessible, areAllGroupPoliciesExpenseChatDisabled, + shouldDisplayPolicyNotFoundPage, }; export type {MemberEmailsToAccountIDs}; From f405f7eb3acb1590d43c43acea2e6e397cdf1f82 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 18 Dec 2024 12:43:09 +0100 Subject: [PATCH 227/257] Simplify getRoutePolicyID --- .../AppNavigator/createSplitNavigator/SplitRouter.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts index 80b85a071e4f..44ef672f45a4 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts @@ -22,13 +22,7 @@ type AdaptStateIfNecessaryArgs = { }; function getRoutePolicyID(route: NavigationPartialRoute): string | undefined { - const hasRoutePolicyID = route?.params && 'policyID' in route.params; - - if (!hasRoutePolicyID) { - return undefined; - } - - return route?.params?.policyID as string; + return (route?.params as Record | undefined)?.policyID; } function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralScreen, parentRoute}}: AdaptStateIfNecessaryArgs) { From 2e08e1ef4bb34580d36217502c9d6c705aa8b138 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 18 Dec 2024 12:47:33 +0100 Subject: [PATCH 228/257] Remove backTo param from Workspace Initial Page --- .../AppNavigator/createSplitNavigator/SplitRouter.ts | 9 --------- src/libs/Navigation/types.ts | 1 - src/pages/workspace/WorkspaceInitialPage.tsx | 9 +-------- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts index 44ef672f45a4..077dcdf56fe4 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts @@ -45,15 +45,6 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc const paramsFromRoute = getParamsFromRoute(sidebarScreen); let params = pick(lastRoute?.params, paramsFromRoute); - // On a wide screen the backTo param has to be passed to the sidebar screen (SCREENS.WORKSPACE.INITIAL), because the back action is performed from this page - if (lastRoute?.name === SCREENS.WORKSPACE.PROFILE) { - const hasRouteBackToParam = lastRoute?.params && 'backTo' in lastRoute.params; - - if (hasRouteBackToParam) { - params = {...params, backTo: lastRoute.params.backTo}; - } - } - // @ts-expect-error Updating read only property // noinspection JSConstantReassignment state.stale = true; // eslint-disable-line diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 6662633e8336..8628007af5b1 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1422,7 +1422,6 @@ type SettingsSplitNavigatorParamList = { type WorkspaceSplitNavigatorParamList = { [SCREENS.WORKSPACE.INITIAL]: { policyID: string; - backTo?: string; }; [SCREENS.WORKSPACE.PROFILE]: { policyID: string; diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 7f99e7e9eca8..008077e013fa 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -406,14 +406,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac > { - if (route.params?.backTo) { - Navigation.goBack(ROUTES.HOME); - Navigation.isNavigationReady().then(() => Navigation.navigate(route.params?.backTo as Route)); - } else { - Navigation.goBack(ROUTES.SETTINGS_WORKSPACES); - } - }} + onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_WORKSPACES)} policyAvatar={policyAvatar} style={styles.headerBarDesktopHeight} /> From c611aa2e4587990e67038bbcc23bed93d76f6007 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Wed, 18 Dec 2024 18:25:02 +0100 Subject: [PATCH 229/257] fix copying params for sidebar in adaptStateIfNecessary --- .../AppNavigator/createSplitNavigator/SplitRouter.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts index 077dcdf56fe4..cef5dd95c418 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts @@ -1,14 +1,12 @@ import type {CommonActions, ParamListBase, PartialState, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native'; import {StackActions, StackRouter} from '@react-navigation/native'; +import isEmpty from 'lodash/isEmpty'; import pick from 'lodash/pick'; -import Onyx from 'react-native-onyx'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import {getParamsFromRoute} from '@libs/Navigation/helpers'; import navigationRef from '@libs/Navigation/navigationRef'; import type {NavigationPartialRoute} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; -import ONYXKEYS from '@src/ONYXKEYS'; -import SCREENS from '@src/SCREENS'; import type {SplitNavigatorRouterOptions} from './types'; import {getPreservedSplitNavigatorState} from './usePreserveSplitNavigatorState'; @@ -43,7 +41,10 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc // - defaultCentralScreen to cover central pane. if (!isAtLeastOneInState(state, sidebarScreen)) { const paramsFromRoute = getParamsFromRoute(sidebarScreen); - let params = pick(lastRoute?.params, paramsFromRoute); + const copiedParams = pick(lastRoute?.params, paramsFromRoute); + + // We don't want to get an empty object as params because it breaks some navigation logic when comparing if routes are the same. + const params = isEmpty(copiedParams) ? undefined : copiedParams; // @ts-expect-error Updating read only property // noinspection JSConstantReassignment From 7438d337b7ba43f6c6d6d3e33a3abb68753bbe83 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 20 Dec 2024 12:28:57 +0100 Subject: [PATCH 230/257] implement TopLevelBottomTabBar and proper animations --- src/CONST.ts | 1 + .../Navigation/AppNavigator/AuthScreens.tsx | 28 ++--- .../Navigators/SettingsSplitNavigator.tsx | 9 -- .../Navigators/WorkspaceSplitNavigator.tsx | 33 ++++-- .../BottomTabBar.tsx | 102 ++++++++++++++++-- .../CustomRouter.ts | 19 +++- .../GetStateForActionHandlers.ts | 53 ++++++++- .../TopLevelBottomTabBar.tsx | 49 +++++++++ .../createResponsiveStackNavigator/index.tsx | 4 +- .../createResponsiveStackNavigator/types.ts | 15 ++- src/pages/Search/SearchPage.tsx | 6 +- src/pages/Search/SearchPageBottomTab.tsx | 5 +- src/pages/home/sidebar/BottomTabAvatar.tsx | 75 ++----------- .../SidebarScreen/BaseSidebarScreen.tsx | 7 +- src/pages/settings/InitialSettingsPage.tsx | 5 +- src/pages/workspace/WorkspaceInitialPage.tsx | 5 +- src/pages/workspace/WorkspacesListPage.tsx | 10 +- src/styles/index.ts | 7 ++ 18 files changed, 298 insertions(+), 135 deletions(-) create mode 100644 src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/TopLevelBottomTabBar.tsx diff --git a/src/CONST.ts b/src/CONST.ts index 0ba7cce2d972..05259e2180b2 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -4621,6 +4621,7 @@ const CONST = { /** These action types are custom for RootNavigator */ SWITCH_POLICY_ID: 'SWITCH_POLICY_ID', DISMISS_MODAL: 'DISMISS_MODAL', + OPEN_WORKSPACE_SPLIT: 'OPEN_WORKSPACE_SPLIT', }, }, TIME_PERIOD: { diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index f8331eade1e0..a003ecd60423 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -25,7 +25,6 @@ import Log from '@libs/Log'; import NavBarManager from '@libs/NavBarManager'; import getCurrentUrl from '@libs/Navigation/currentUrl'; import {isOnboardingFlowName} from '@libs/Navigation/helpers'; -import SIDEBAR_TO_SPLIT from '@libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation'; import Presentation from '@libs/Navigation/PlatformStackNavigation/navigationOptions/presentation'; @@ -59,6 +58,7 @@ import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; import createResponsiveStackNavigator from './createResponsiveStackNavigator'; +import {workspaceSplitsWithoutEnteringAnimation} from './createResponsiveStackNavigator/GetStateForActionHandlers'; import defaultScreenOptions from './defaultScreenOptions'; import ExplanationModalNavigator from './Navigators/ExplanationModalNavigator'; import FeatureTrainingModalNavigator from './Navigators/FeatureTrainingModalNavigator'; @@ -367,21 +367,23 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie }, []); // Animation is disabled when navigating to the sidebar screen - const getSplitNavigatorOptions = (route: RouteProp) => { - if (!shouldUseNarrowLayout || !route?.params) { + const getWorkspaceSplitNavigatorOptions = ({route}: {route: RouteProp}) => { + // We don't need to do anything special for the wide screen. + if (!shouldUseNarrowLayout) { return rootNavigatorOptions.fullScreen; } - const screenName = 'screen' in route.params ? route.params.screen : undefined; - - if (!screenName) { - return rootNavigatorOptions.fullScreen; - } - - const animationEnabled = !Object.keys(SIDEBAR_TO_SPLIT).includes(screenName); + // On the narrow screen, we want to animate this navigator if it is opened from the settings split. + // If it is opened from other tab, we don't want to animate it on the entry. + // There is a hook inside the workspace navigator that changes animation to SLIDE_FROM_RIGHT after entering. + // This way it can be animated properly when going back to the settings split. + const animationEnabled = !workspaceSplitsWithoutEnteringAnimation.has(route.key); return { ...rootNavigatorOptions.fullScreen, + + // Allow swipe to go back from this split navigator to the settings navigator. + gestureEnabled: true, animation: animationEnabled ? Animations.SLIDE_FROM_RIGHT : Animations.NONE, }; }; @@ -393,12 +395,12 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie {/* This have to be the first navigator in auth screens. */} getSplitNavigatorOptions(route)} + options={rootNavigatorOptions.fullScreen} getComponent={loadReportSplitNavigator} /> getSplitNavigatorOptions(route)} + options={rootNavigatorOptions.fullScreen} getComponent={loadSettingsSplitNavigator} /> getSplitNavigatorOptions(route)} + options={getWorkspaceSplitNavigatorOptions} getComponent={loadWorkspaceSplitNavigator} /> {Object.entries(CENTRAL_PANE_SETTINGS_SCREENS).map(([screenName, componentGetter]) => { - const options: PlatformStackNavigationOptions = {animation: undefined}; - - if (screenName === SCREENS.SETTINGS.WORKSPACES) { - options.animation = Animations.NONE; - } - return ( ); })} diff --git a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx index 2d269e88ba16..4e93f95ec837 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx @@ -1,9 +1,12 @@ -import {useRoute} from '@react-navigation/native'; -import React from 'react'; +import React, {useEffect} from 'react'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; +import {workspaceSplitsWithoutEnteringAnimation} from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers'; import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import useRootNavigatorOptions from '@libs/Navigation/AppNavigator/useRootNavigatorOptions'; -import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; +import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation'; +import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; +import type {AuthScreensParamList, WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; +import type NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; @@ -31,10 +34,26 @@ const CENTRAL_PANE_WORKSPACE_SCREENS = { const Split = createSplitNavigator(); -function WorkspaceNavigator() { - const route = useRoute(); +function WorkspaceSplitNavigator({route, navigation}: PlatformStackScreenProps) { const rootNavigatorOptions = useRootNavigatorOptions(); + useEffect(() => { + const unsubscribe = navigation.addListener('transitionEnd', () => { + // We want to call this function only once. + unsubscribe(); + + // If we open this screen from a different tab, then it won't have animation. + if (!workspaceSplitsWithoutEnteringAnimation.has(route.key)) { + return; + } + + // We want ot set animation after mounting so it will animate on going UP to the settings split. + navigation.setOptions({animation: Animations.SLIDE_FROM_RIGHT}); + }); + + return unsubscribe; + }, [navigation, route.key]); + return ( ; + type BottomTabBarProps = { - selectedTab: string | undefined; + selectedTab: BottomTabs; }; /** @@ -73,6 +86,7 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS); const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const [chatTabBrickRoad, setChatTabBrickRoad] = useState(() => getChatTabBrickRoad(activeWorkspaceID, currentReportID, reports, betas, policies, priorityMode, transactionViolations), ); @@ -84,7 +98,7 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { }, [activeWorkspaceID, transactionViolations, reports, reportActions, betas, policies, priorityMode, currentReportID]); const navigateToChats = useCallback(() => { - if (selectedTab === SCREENS.HOME) { + if (selectedTab === BOTTOM_TABS.HOME) { return; } @@ -92,7 +106,7 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { }, [selectedTab]); const navigateToSearch = useCallback(() => { - if (selectedTab === SCREENS.SEARCH.CENTRAL_PANE) { + if (selectedTab === BOTTOM_TABS.SEARCH) { return; } interceptAnonymousUser(() => { @@ -119,6 +133,65 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { }); }, [activeWorkspaceID, selectedTab]); + const showSettingsPage = useCallback(() => { + const rootState = navigationRef.getRootState(); + const topmostFullScreenRoute = rootState.routes.findLast((route) => isFullScreenName(route.name)); + + if (!topmostFullScreenRoute) { + return; + } + + const lastRouteOfTopmostFullScreenRoute = 'state' in topmostFullScreenRoute ? topmostFullScreenRoute.state?.routes.at(-1) : undefined; + + if (lastRouteOfTopmostFullScreenRoute && lastRouteOfTopmostFullScreenRoute.name === SCREENS.SETTINGS.WORKSPACES && shouldUseNarrowLayout) { + Navigation.goBack(ROUTES.SETTINGS); + return; + } + + if (topmostFullScreenRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { + Navigation.goBack(ROUTES.SETTINGS); + return; + } + + interceptAnonymousUser(() => { + const lastSettingsOrWorkspaceNavigatorRoute = rootState.routes.findLast( + (rootRoute) => rootRoute.name === NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR || rootRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, + ); + + // If there is a workspace navigator route, then we should open the workspace initial screen as it should be "remembered". + if (lastSettingsOrWorkspaceNavigatorRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { + const state = lastSettingsOrWorkspaceNavigatorRoute.state ?? getPreservedSplitNavigatorState(lastSettingsOrWorkspaceNavigatorRoute.key); + const params = state?.routes.at(0)?.params as WorkspaceSplitNavigatorParamList[typeof SCREENS.WORKSPACE.INITIAL]; + + // Screens of this navigator should always have policyID + if (params.policyID) { + // This action will put settings split under the workspace split to make sure that we can swipe back to settings split. + navigationRef.dispatch({ + type: CONST.NAVIGATION.ACTION_TYPE.OPEN_WORKSPACE_SPLIT, + payload: { + policyID: params.policyID, + }, + }); + } + return; + } + + // If there is settings workspace screen in the settings navigator, then we should open the settings workspaces as it should be "remembered". + if ( + lastSettingsOrWorkspaceNavigatorRoute && + lastSettingsOrWorkspaceNavigatorRoute.state && + lastSettingsOrWorkspaceNavigatorRoute.state.routes.at(-1)?.name === SCREENS.SETTINGS.WORKSPACES + ) { + Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); + return; + } + + // Otherwise we should simply open the settings navigator. + // This case also covers if there is no route to remember. + Navigation.navigate(ROUTES.SETTINGS); + }); + }, [shouldUseNarrowLayout]); + return ( <> {!!user?.isDebugModeEnabled && ( @@ -145,7 +218,7 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { @@ -154,7 +227,13 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { )} {translate('common.inbox')} @@ -169,7 +248,7 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { @@ -179,14 +258,17 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { styles.textSmall, styles.textAlignCenter, styles.mt1Half, - selectedTab === SCREENS.SEARCH.CENTRAL_PANE ? styles.textBold : styles.textSupporting, + selectedTab === BOTTOM_TABS.SEARCH ? styles.textBold : styles.textSupporting, styles.bottomTabBarLabel, ]} > {translate('common.search')} - + @@ -198,3 +280,5 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { BottomTabBar.displayName = 'BottomTabBar'; export default memo(BottomTabBar); +export {BOTTOM_TABS}; +export type {BottomTabs}; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts index 15aa6b0e9d14..f656f43ac06b 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts @@ -10,7 +10,19 @@ import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import * as GetStateForActionHandlers from './GetStateForActionHandlers'; import syncBrowserHistory from './syncBrowserHistory'; -import type {CustomRouterAction, CustomRouterActionType, DismissModalActionType, PushActionType, ResponsiveStackNavigatorRouterOptions, SwitchPolicyIdActionType} from './types'; +import type { + CustomRouterAction, + CustomRouterActionType, + DismissModalActionType, + OpenWorkspaceSplitActionType, + PushActionType, + ResponsiveStackNavigatorRouterOptions, + SwitchPolicyIdActionType, +} from './types'; + +function isOpenWorkspaceSplitAction(action: CustomRouterAction): action is OpenWorkspaceSplitActionType { + return action.type === CONST.NAVIGATION.ACTION_TYPE.OPEN_WORKSPACE_SPLIT; +} function isSwitchPolicyIdAction(action: CustomRouterAction): action is SwitchPolicyIdActionType { return action.type === CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID; @@ -59,10 +71,13 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { const stackRouter = StackRouter(options); const {setActiveWorkspaceID} = useActiveWorkspace(); - // @TODO: Make sure that everything works fine without compareAndAdaptState function. Probably with getMatchingFullScreenRoute. return { ...stackRouter, getStateForAction(state: StackNavigationState, action: CustomRouterAction, configOptions: RouterConfigOptions) { + if (isOpenWorkspaceSplitAction(action)) { + return GetStateForActionHandlers.handleOpenWorkspaceSplitAction(state, action, configOptions, stackRouter); + } + if (isSwitchPolicyIdAction(action)) { return GetStateForActionHandlers.handleSwitchPolicyID(state, action, configOptions, stackRouter, setActiveWorkspaceID); } diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts index 1a952c0c6caa..b2dea13fbd4d 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts @@ -7,7 +7,7 @@ import type {RootStackParamList, State} from '@libs/Navigation/types'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -import type {PushActionType, SwitchPolicyIdActionType} from './types'; +import type {OpenWorkspaceSplitActionType, PushActionType, SwitchPolicyIdActionType} from './types'; const MODAL_ROUTES_TO_DISMISS: string[] = [ NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, @@ -24,6 +24,55 @@ const MODAL_ROUTES_TO_DISMISS: string[] = [ SCREENS.CONCIERGE, ]; +const workspaceSplitsWithoutEnteringAnimation = new Set(); + +/** + * Handles the OPEN_WORKSPACE_SPLIT action. + * If the user is on other tab than settings and the workspace split is "remembered", this action will called after pressing the settings tab. + * It will push the settings split navigator first and then push the workspace split navigator. + * This allows the user to swipe back on the iOS to the settings split navigator underneath. + */ +function handleOpenWorkspaceSplitAction( + state: StackNavigationState, + action: OpenWorkspaceSplitActionType, + configOptions: RouterConfigOptions, + stackRouter: Router, CommonActions.Action | StackActionType>, +) { + const actionToPushSettingsSplitNavigator = StackActions.push(NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, { + screen: SCREENS.SETTINGS.WORKSPACES, + }); + + const actionToPushWorkspaceSplitNavigator = StackActions.push(NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, { + screen: SCREENS.WORKSPACE.INITIAL, + params: { + policyID: action.payload.policyID, + }, + }); + + const stateWithSettingsSplitNavigator = stackRouter.getStateForAction(state, actionToPushSettingsSplitNavigator, configOptions); + + if (!stateWithSettingsSplitNavigator) { + return null; + } + + const rehydratedStateWithSettingsSplitNavigator = stackRouter.getRehydratedState(stateWithSettingsSplitNavigator, configOptions); + const stateWithWorkspaceSplitNavigator = stackRouter.getStateForAction(rehydratedStateWithSettingsSplitNavigator, actionToPushWorkspaceSplitNavigator, configOptions); + + if (!stateWithWorkspaceSplitNavigator) { + return null; + } + + const lastFullScreenRoute = stateWithWorkspaceSplitNavigator.routes.at(-1); + + if (lastFullScreenRoute?.key) { + // If the user opened the workspace split navigator from a different tab, we don't want to animate the entering transition. + // To make it feel like bottom tab navigator. + workspaceSplitsWithoutEnteringAnimation.add(lastFullScreenRoute.key); + } + + return stateWithWorkspaceSplitNavigator; +} + function handleSwitchPolicyID( state: StackNavigationState, action: SwitchPolicyIdActionType, @@ -151,4 +200,4 @@ function handleDismissModalAction( return stackRouter.getStateForAction(state, newAction, configOptions); } -export {handleDismissModalAction, handlePushReportAction, handlePushSearchPageAction, handleSwitchPolicyID}; +export {handleOpenWorkspaceSplitAction, handleDismissModalAction, handlePushReportAction, handlePushSearchPageAction, handleSwitchPolicyID, workspaceSplitsWithoutEnteringAnimation}; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/TopLevelBottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/TopLevelBottomTabBar.tsx new file mode 100644 index 000000000000..af50b0c2a258 --- /dev/null +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/TopLevelBottomTabBar.tsx @@ -0,0 +1,49 @@ +import {findFocusedRoute, useNavigationState} from '@react-navigation/native'; +import React from 'react'; +import {View} from 'react-native'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets'; +import useThemeStyles from '@hooks/useThemeStyles'; +import BottomTabBar, {BOTTOM_TABS} from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; +import {isFullScreenName} from '@libs/Navigation/helpers'; +import SIDEBAR_TO_SPLIT from '@libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT'; +import type {FullScreenName} from '@libs/Navigation/types'; +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; + +const FULLSCREEN_TO_TAB = { + [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: BOTTOM_TABS.HOME, + [SCREENS.SEARCH.CENTRAL_PANE]: BOTTOM_TABS.SEARCH, + [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: BOTTOM_TABS.SETTINGS, + [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: BOTTOM_TABS.SETTINGS, +}; + +const SCREENS_WITH_BOTTOM_TAB_BAR = [...Object.keys(SIDEBAR_TO_SPLIT), SCREENS.SEARCH.CENTRAL_PANE, SCREENS.SETTINGS.WORKSPACES]; + +/** + * Currently we are using the hybrid approach for the bottom tab bar. + * On wide screen we are using per screen bottom tab bar. It gives us more flexibility. We can display the bottom tab bar on any screen without any navigation structure constraints. + * On narrow layout we display the top level bottom tab bar. It allows us to implement proper animations between screens. + */ +function TopLevelBottomTabBar() { + const styles = useThemeStyles(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); + const topmostFullScreenRoute = useNavigationState((state) => state?.routes.findLast((route) => isFullScreenName(route.name))); + const {paddingBottom} = useStyledSafeAreaInsets(); + + // Home as fallback selected tab. + const selectedTab = FULLSCREEN_TO_TAB[(topmostFullScreenRoute?.name as FullScreenName) ?? NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]; + + // There always should be a focused screen. + const isScreenWithBottomTabFocused = useNavigationState((state) => SCREENS_WITH_BOTTOM_TAB_BAR.includes(findFocusedRoute(state)?.name ?? '')); + + const shouldDisplayTopLevelBottomTabBar = isScreenWithBottomTabFocused && shouldUseNarrowLayout; + + return ( + + + + ); +} + +export default TopLevelBottomTabBar; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx index 5662b394339c..ab479bf0e773 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx @@ -1,11 +1,12 @@ -import type {ParamListBase} from '@react-navigation/native'; import {createNavigatorFactory} from '@react-navigation/native'; +import type {ParamListBase} from '@react-navigation/native'; import useNavigationResetOnLayoutChange from '@libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange'; import {isFullScreenName} from '@libs/Navigation/helpers'; import createPlatformStackNavigatorComponent from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent'; import defaultPlatformStackScreenOptions from '@libs/Navigation/PlatformStackNavigation/defaultPlatformStackScreenOptions'; import type {CustomStateHookProps, PlatformStackNavigationEventMap, PlatformStackNavigationOptions, PlatformStackNavigationState} from '@libs/Navigation/PlatformStackNavigation/types'; import CustomRouter from './CustomRouter'; +import TopLevelBottomTabBar from './TopLevelBottomTabBar'; function useCustomRouterState({state}: CustomStateHookProps) { const lastSplitIndex = state.routes.findLastIndex((route) => isFullScreenName(route.name)); @@ -19,6 +20,7 @@ const ResponsiveStackNavigatorComponent = createPlatformStackNavigatorComponent( defaultScreenOptions: defaultPlatformStackScreenOptions, useCustomEffects: useNavigationResetOnLayoutChange, useCustomState: useCustomRouterState, + ExtraContent: TopLevelBottomTabBar, }); function createResponsiveStackNavigator() { diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/types.ts b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/types.ts index 9f19ede081cd..7c0071773495 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/types.ts +++ b/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/types.ts @@ -9,7 +9,19 @@ type CustomRouterActionType = policyID: string; }; } - | {type: typeof CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL}; + | { + type: typeof CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL; + } + | { + type: typeof CONST.NAVIGATION.ACTION_TYPE.OPEN_WORKSPACE_SPLIT; + payload: { + policyID: string; + }; + }; + +type OpenWorkspaceSplitActionType = CustomRouterActionType & { + type: typeof CONST.NAVIGATION.ACTION_TYPE.OPEN_WORKSPACE_SPLIT; +}; type SwitchPolicyIdActionType = CustomRouterActionType & { type: typeof CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID; @@ -33,6 +45,7 @@ type ResponsiveStackNavigatorProps = DefaultNavigatorOptions )} - + } + bottomContent={} > {!selectionMode?.isEnabled ? ( <> diff --git a/src/pages/home/sidebar/BottomTabAvatar.tsx b/src/pages/home/sidebar/BottomTabAvatar.tsx index 28712438aea9..095e1fdb40df 100644 --- a/src/pages/home/sidebar/BottomTabAvatar.tsx +++ b/src/pages/home/sidebar/BottomTabAvatar.tsx @@ -1,94 +1,31 @@ -import {useRoute} from '@react-navigation/native'; -import React, {useCallback} from 'react'; +import React from 'react'; import {useOnyx} from 'react-native-onyx'; import {PressableWithFeedback} from '@components/Pressable'; import Text from '@components/Text'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import interceptAnonymousUser from '@libs/interceptAnonymousUser'; -import {getPreservedSplitNavigatorState} from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; -import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; -import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import CONST from '@src/CONST'; -import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; import AvatarWithDelegateAvatar from './AvatarWithDelegateAvatar'; import AvatarWithOptionalStatus from './AvatarWithOptionalStatus'; import ProfileAvatarWithIndicator from './ProfileAvatarWithIndicator'; type BottomTabAvatarProps = { - /** Whether the create menu is open or not */ - isCreateMenuOpen?: boolean; - /** Whether the avatar is selected */ isSelected?: boolean; + + /** Function to call when the avatar is pressed */ + onPress: () => void; }; -function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomTabAvatarProps) { +function BottomTabAvatar({onPress, isSelected = false}: BottomTabAvatarProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const [account] = useOnyx(ONYXKEYS.ACCOUNT); const delegateEmail = account?.delegatedAccess?.delegate ?? ''; - const route = useRoute(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const emojiStatus = currentUserPersonalDetails?.status?.emojiCode ?? ''; - const {shouldUseNarrowLayout} = useResponsiveLayout(); - - const showSettingsPage = useCallback(() => { - if (isCreateMenuOpen) { - // Prevent opening Settings page when click profile avatar quickly after clicking FAB icon - return; - } - - if (route.name === SCREENS.SETTINGS.WORKSPACES && shouldUseNarrowLayout) { - Navigation.goBack(ROUTES.SETTINGS); - return; - } - - if (route.name === SCREENS.WORKSPACE.INITIAL) { - Navigation.goBack(ROUTES.SETTINGS); - if (shouldUseNarrowLayout) { - Navigation.navigate(ROUTES.SETTINGS, CONST.NAVIGATION.ACTION_TYPE.REPLACE); - } - return; - } - - interceptAnonymousUser(() => { - const rootState = navigationRef.getRootState(); - const lastSettingsOrWorkspaceNavigatorRoute = rootState.routes.findLast( - (rootRoute) => rootRoute.name === NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR || rootRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, - ); - - // If there is a workspace navigator route, then we should open the workspace initial screen as it should be "remembered". - if (lastSettingsOrWorkspaceNavigatorRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - const state = lastSettingsOrWorkspaceNavigatorRoute.state ?? getPreservedSplitNavigatorState(lastSettingsOrWorkspaceNavigatorRoute.key); - const params = state?.routes.at(0)?.params as WorkspaceSplitNavigatorParamList[typeof SCREENS.WORKSPACE.INITIAL]; - // Screens of this navigator should always have policyID - if (params.policyID) { - Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(params.policyID)); - } - return; - } - - // If there is settings workspace screen in the settings navigator, then we should open the settings workspaces as it should be "remembered". - if ( - lastSettingsOrWorkspaceNavigatorRoute && - lastSettingsOrWorkspaceNavigatorRoute.state && - lastSettingsOrWorkspaceNavigatorRoute.state.routes.at(-1)?.name === SCREENS.SETTINGS.WORKSPACES - ) { - Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); - return; - } - - // Otherwise we should simply open the settings navigator. - // This case also covers if there is no route to remember. - Navigation.navigate(ROUTES.SETTINGS); - }); - }, [isCreateMenuOpen, shouldUseNarrowLayout, route.name]); let children; @@ -119,7 +56,7 @@ function BottomTabAvatar({isCreateMenuOpen = false, isSelected = false}: BottomT return ( { // Whether the active workspace or the "Everything" page is loaded const isWorkspaceOrEverythingLoaded = !!activeWorkspace || activeWorkspaceID === undefined; @@ -74,7 +75,7 @@ function BaseSidebarScreen() { type: CONST.NAVIGATION.ACTION_TYPE.REPLACE, }); updateLastAccessedWorkspace(undefined); - }, [activeWorkspace, activeWorkspaceID]); + }, [activeWorkspace, activeWorkspaceID, currentRoute.key]); const shouldDisplaySearch = shouldUseNarrowLayout; @@ -83,7 +84,7 @@ function BaseSidebarScreen() { shouldEnableKeyboardAvoidingView={false} style={[styles.sidebar, Browser.isMobile() ? styles.userSelectNone : {}]} testID={BaseSidebarScreen.displayName} - bottomContent={} + bottomContent={} > {({insets}) => ( <> diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 77397737cb33..4e5b05b5321e 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -32,7 +32,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import {resetExitSurveyForm} from '@libs/actions/ExitSurvey'; import * as CurrencyUtils from '@libs/CurrencyUtils'; -import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; +import BottomTabBar, {BOTTOM_TABS} from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import getTopmostRouteName from '@libs/Navigation/helpers/getTopmostRouteName'; import Navigation from '@libs/Navigation/Navigation'; import * as SubscriptionUtils from '@libs/SubscriptionUtils'; @@ -50,7 +50,6 @@ import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; -import SCREENS from '@src/SCREENS'; import type {Icon as TIcon} from '@src/types/onyx/OnyxCommon'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type IconAsset from '@src/types/utils/IconAsset'; @@ -428,7 +427,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr } + bottomContent={} shouldEnableKeyboardAvoidingView={false} > {headerContent} diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 008077e013fa..adcd8f7981cf 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -23,7 +23,7 @@ import useWaitForNavigation from '@hooks/useWaitForNavigation'; import {isConnectionInProgress} from '@libs/actions/connections'; import * as CardUtils from '@libs/CardUtils'; import * as CurrencyUtils from '@libs/CurrencyUtils'; -import BottomTabBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; +import BottomTabBar, {BOTTOM_TABS} from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import getTopmostRouteName from '@libs/Navigation/helpers/getTopmostRouteName'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; @@ -36,7 +36,6 @@ import * as ReimbursementAccount from '@userActions/ReimbursementAccount'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; import type {PendingAction} from '@src/types/onyx/OnyxCommon'; @@ -396,7 +395,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac : null} + bottomContent={shouldShowBottomTab ? : null} > (); const [policyNameToDelete, setPolicyNameToDelete] = useState(); @@ -406,7 +402,7 @@ function WorkspacesListPage() { shouldEnableMaxHeight testID={WorkspacesListPage.displayName} shouldShowOfflineIndicatorInWideScreen - bottomContent={shouldUseNarrowLayout && } + bottomContent={shouldUseNarrowLayout && } > } + bottomContent={shouldUseNarrowLayout && } > borderRadius: variables.componentBorderRadiusLarge, }, + topLevelBottomTabBar: (shouldDisplayTopLevelBottomTabBar: boolean, bottomSafeAreaOffset: number) => ({ + position: 'absolute', + width: '100%', + paddingBottom: bottomSafeAreaOffset, + bottom: shouldDisplayTopLevelBottomTabBar ? 0 : -(bottomSafeAreaOffset + variables.bottomTabHeight), + }), + bottomTabBarContainer: { flexDirection: 'row', height: variables.bottomTabHeight, From 99fc24752ea5d678c0477e4d4f75566f7f1ecba1 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 20 Dec 2024 16:10:49 +0100 Subject: [PATCH 231/257] Fix lint --- .../subscribePushNotification/index.ts | 12 +----------- src/pages/workspace/WorkspaceInitialPage.tsx | 2 +- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/libs/Notification/PushNotification/subscribePushNotification/index.ts b/src/libs/Notification/PushNotification/subscribePushNotification/index.ts index 2cb31dae0304..504ac353d1c4 100644 --- a/src/libs/Notification/PushNotification/subscribePushNotification/index.ts +++ b/src/libs/Notification/PushNotification/subscribePushNotification/index.ts @@ -1,6 +1,5 @@ import {NativeModules} from 'react-native'; import Onyx from 'react-native-onyx'; -import type {OnyxCollection} from 'react-native-onyx'; import applyOnyxUpdatesReliably from '@libs/actions/applyOnyxUpdatesReliably'; import * as ActiveClientManager from '@libs/ActiveClientManager'; import Log from '@libs/Log'; @@ -13,7 +12,7 @@ import * as Modal from '@userActions/Modal'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {OnyxUpdatesFromServer, Report} from '@src/types/onyx'; +import type {OnyxUpdatesFromServer} from '@src/types/onyx'; import PushNotification from '..'; let lastVisitedPath: string | undefined; @@ -27,15 +26,6 @@ Onyx.connect({ }, }); -let allReports: OnyxCollection; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT, - waitForCollectionCallback: true, - callback: (value) => { - allReports = value; - }, -}); - function getLastUpdateIDAppliedToClient(): Promise { return new Promise((resolve) => { Onyx.connect({ diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index a3e818630744..da652940f921 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -450,7 +450,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac title={getReportName(currentUserPolicyExpenseChat)} description={translate('workspace.common.workspace')} icon={getIcons(currentUserPolicyExpenseChat, personalDetails)} - onPress={() => Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(currentUserPolicyExpenseChat?.reportID ?? '-1'), CONST.NAVIGATION.TYPE.UP)} + onPress={() => Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(currentUserPolicyExpenseChat?.reportID ?? '-1'), CONST.NAVIGATION.ACTION_TYPE.REPLACE)} shouldShowRightIcon wrapperStyle={[styles.br2, styles.pl2, styles.pr0, styles.pv3, styles.mt1, styles.alignItemsCenter]} shouldShowSubscriptAvatar From 17759f4836a314ca47a8b720038edba9ab720ad5 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 20 Dec 2024 16:23:39 +0100 Subject: [PATCH 232/257] Remove Navigation.popToTop and add shouldPopToTop to GoBackOptions --- src/libs/Navigation/Navigation.ts | 15 +++++++++++++++ src/libs/actions/Report.ts | 2 +- .../navigateAfterJoinRequest/index.desktop.ts | 2 +- src/libs/navigateAfterJoinRequest/index.ts | 2 +- src/libs/navigateAfterJoinRequest/index.web.ts | 2 +- src/pages/home/ReportScreen.tsx | 4 ++-- src/pages/workspace/WorkspaceJoinUserPage.tsx | 2 +- 7 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 9b3413f13eb5..48e6094dd897 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -225,10 +225,17 @@ type GoBackOptions = { * In that case we want to goUp to a country picker with any params so we don't compare them. */ compareParams?: boolean; + + /** + * Specifies whether goBack should pop to top when invoked. + * Additionaly, to execute popToTop, set the value of the global variable ShouldPopAllStateOnUP to true using the setShouldPopAllStateOnUP function. + */ + shouldPopToTop?: boolean; }; const defaultGoBackOptions: Required = { compareParams: true, + shouldPopToTop: false, }; /** @@ -298,6 +305,14 @@ function goBack(fallbackRoute?: Route, options?: GoBackOptions) { return; } + if (options?.shouldPopToTop) { + if (shouldPopAllStateOnUP) { + shouldPopAllStateOnUP = false; + navigationRef.current?.dispatch(StackActions.popToTop()); + return; + } + } + if (fallbackRoute) { goUp(fallbackRoute, options); return; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 6ba6af1dbf55..29b30552ae0b 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2468,7 +2468,7 @@ function navigateToConciergeChatAndDeleteReport(reportID: string, shouldPopToTop // @TODO: Check if this method works the same as on the main branch if (shouldPopToTop) { Navigation.setShouldPopAllStateOnUP(true); - Navigation.popToTop(); + Navigation.goBack(undefined, {shouldPopToTop: true}); } else { Navigation.goBack(); } diff --git a/src/libs/navigateAfterJoinRequest/index.desktop.ts b/src/libs/navigateAfterJoinRequest/index.desktop.ts index 461f5376e6c1..9b72ee30de57 100644 --- a/src/libs/navigateAfterJoinRequest/index.desktop.ts +++ b/src/libs/navigateAfterJoinRequest/index.desktop.ts @@ -4,7 +4,7 @@ import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { // @TODO: Check if this method works the same as on the main branch - Navigation.popToTop(); + Navigation.goBack(undefined, {shouldPopToTop: true}); if (getIsSmallScreenWidth()) { Navigation.navigate(ROUTES.SETTINGS); } diff --git a/src/libs/navigateAfterJoinRequest/index.ts b/src/libs/navigateAfterJoinRequest/index.ts index 91b2fdade606..a3ac50cd59be 100644 --- a/src/libs/navigateAfterJoinRequest/index.ts +++ b/src/libs/navigateAfterJoinRequest/index.ts @@ -3,7 +3,7 @@ import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { // @TODO: Check if this method works the same as on the main branch - Navigation.popToTop(); + Navigation.goBack(undefined, {shouldPopToTop: true}); Navigation.navigate(ROUTES.SETTINGS); Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); }; diff --git a/src/libs/navigateAfterJoinRequest/index.web.ts b/src/libs/navigateAfterJoinRequest/index.web.ts index 461f5376e6c1..9b72ee30de57 100644 --- a/src/libs/navigateAfterJoinRequest/index.web.ts +++ b/src/libs/navigateAfterJoinRequest/index.web.ts @@ -4,7 +4,7 @@ import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { // @TODO: Check if this method works the same as on the main branch - Navigation.popToTop(); + Navigation.goBack(undefined, {shouldPopToTop: true}); if (getIsSmallScreenWidth()) { Navigation.navigate(ROUTES.SETTINGS); } diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index bfa0f87d8395..3d8985451033 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -303,7 +303,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro return; } // @TODO: Handle popToTop here - Navigation.goBack(ROUTES.HOME); + Navigation.goBack(ROUTES.HOME, {shouldPopToTop: true}); }, [isInNarrowPaneModal]); let headerView = ( @@ -609,7 +609,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro if (Navigation.getTopmostReportId() === prevOnyxReportID) { Navigation.setShouldPopAllStateOnUP(true); // @TODO: Check if this method works the same as on the main branch - Navigation.popToTop(); + Navigation.goBack(undefined, {shouldPopToTop: true}); } if (prevReport?.parentReportID) { // Prevent navigation to the IOU/Expense Report if it is pending deletion. diff --git a/src/pages/workspace/WorkspaceJoinUserPage.tsx b/src/pages/workspace/WorkspaceJoinUserPage.tsx index 6e8333d75451..66caff7263ef 100644 --- a/src/pages/workspace/WorkspaceJoinUserPage.tsx +++ b/src/pages/workspace/WorkspaceJoinUserPage.tsx @@ -47,7 +47,7 @@ function WorkspaceJoinUserPage({route, policy}: WorkspaceJoinUserPageProps) { Navigation.isNavigationReady().then(() => { // @TODO: Check if this method works the same as on the main branch // NOTE: It probably doesn't need any params. When this method is called, shouldPopAllStateOnUP is always false - Navigation.popToTop(); + Navigation.goBack(undefined, {shouldPopToTop: true}); Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID ?? '-1')); }); return; From 14807235058937e54afb77f8b8789771f2683104 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 20 Dec 2024 16:26:37 +0100 Subject: [PATCH 233/257] Fix types in getAdaptedStateFromPath --- src/libs/Navigation/helpers/getAdaptedStateFromPath.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts index fc427032f705..3ab638f6808c 100644 --- a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts @@ -12,6 +12,7 @@ import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import SCREENS from '@src/SCREENS'; +import type {Report} from '@src/types/onyx'; import extractPolicyIDFromQuery from './extractPolicyIDFromQuery'; import getParamsFromRoute from './getParamsFromRoute'; import {isFullScreenName} from './isNavigatorName'; From af2058d84d67f31cff2b6e3425af55bcc133b420 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 30 Dec 2024 13:27:57 +0100 Subject: [PATCH 234/257] Add splitNavigator to RootNavigatorOptions --- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 10 +++++----- .../Navigation/AppNavigator/useRootNavigatorOptions.ts | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index adda145fb5ff..cc3cd9343b57 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -369,7 +369,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie const getWorkspaceSplitNavigatorOptions = ({route}: {route: RouteProp}) => { // We don't need to do anything special for the wide screen. if (!shouldUseNarrowLayout) { - return rootNavigatorOptions.fullScreen; + return rootNavigatorOptions.splitNavigator; } // On the narrow screen, we want to animate this navigator if it is opened from the settings split. @@ -379,7 +379,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie const animationEnabled = !workspaceSplitsWithoutEnteringAnimation.has(route.key); return { - ...rootNavigatorOptions.fullScreen, + ...rootNavigatorOptions.splitNavigator, // Allow swipe to go back from this split navigator to the settings navigator. gestureEnabled: true, @@ -394,17 +394,17 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie {/* This have to be the first navigator in auth screens. */} diff --git a/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts b/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts index a2d609eb5d4b..e8467c2e02fe 100644 --- a/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts +++ b/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts @@ -14,11 +14,11 @@ type RootNavigatorOptions = { rightModalNavigator: PlatformStackNavigationOptions; basicModalNavigator: PlatformStackNavigationOptions; leftModalNavigator: PlatformStackNavigationOptions; + splitNavigator: PlatformStackNavigationOptions; homeScreen: PlatformStackNavigationOptions; fullScreen: PlatformStackNavigationOptions; centralPaneNavigator: PlatformStackNavigationOptions; bottomTab: PlatformStackNavigationOptions; - searchPage: PlatformStackNavigationOptions; }; const commonScreenOptions: PlatformStackNavigationOptions = { @@ -107,7 +107,7 @@ const useRootNavigatorOptions = () => { }, }, - fullScreen: { + splitNavigator: { ...commonScreenOptions, // We need to turn off animation for the full screen to avoid delay when closing screens. animation: Animations.NONE, @@ -119,7 +119,7 @@ const useRootNavigatorOptions = () => { }, }, - searchPage: { + fullScreen: { ...commonScreenOptions, // We need to turn off animation for the full screen to avoid delay when closing screens. animation: Animations.NONE, From 4b2949d174e28ecc9574dd80f6ed2c1ae6def7ac Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 9 Jan 2025 14:51:34 +0100 Subject: [PATCH 235/257] Add resetPolicyIDInNavigationState --- src/libs/Navigation/helpers/index.ts | 1 + .../helpers/resetPolicyIDInNavigationState.ts | 34 +++++++++++++++++++ src/pages/workspace/WorkspaceProfilePage.tsx | 11 ++++-- src/pages/workspace/WorkspacesListPage.tsx | 8 +++++ 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 src/libs/Navigation/helpers/resetPolicyIDInNavigationState.ts diff --git a/src/libs/Navigation/helpers/index.ts b/src/libs/Navigation/helpers/index.ts index 85f8779031e3..508b40c6b948 100644 --- a/src/libs/Navigation/helpers/index.ts +++ b/src/libs/Navigation/helpers/index.ts @@ -24,3 +24,4 @@ export {default as setNavigationActionToMicrotaskQueue} from './setNavigationAct export {default as setupCustomAndroidBackHandler} from './setupCustomAndroidBackHandler'; export {default as shouldOpenOnAdminRoom} from './shouldOpenOnAdminRoom'; export {default as shouldPreventDeeplinkPrompt} from './shouldPreventDeeplinkPrompt'; +export {default as resetPolicyIDInNavigationState} from './resetPolicyIDInNavigationState'; diff --git a/src/libs/Navigation/helpers/resetPolicyIDInNavigationState.ts b/src/libs/Navigation/helpers/resetPolicyIDInNavigationState.ts new file mode 100644 index 000000000000..99db40720c72 --- /dev/null +++ b/src/libs/Navigation/helpers/resetPolicyIDInNavigationState.ts @@ -0,0 +1,34 @@ +import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; +import type {AuthScreensParamList} from '@libs/Navigation/types'; +import * as SearchQueryUtils from '@libs/SearchQueryUtils'; +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; + +/** + * Reset the policyID stored in the navigation state to undefined. + * It is necessary to reset this id after deleting the policy which is currently selected in the app. + */ +function resetPolicyIDInNavigationState() { + const rootState = navigationRef.getRootState(); + const lastPolicyRoute = rootState?.routes?.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.CENTRAL_PANE); + + if (!lastPolicyRoute) { + return; + } + + if (lastPolicyRoute.params && 'policyID' in lastPolicyRoute.params) { + Navigation.setParams({policyID: undefined}, lastPolicyRoute.key); + return; + } + + const {q, ...rest} = lastPolicyRoute.params as AuthScreensParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; + const queryJSON = SearchQueryUtils.buildSearchQueryJSON(q); + if (!queryJSON || !queryJSON.policyID) { + return; + } + + delete queryJSON.policyID; + Navigation.setParams({q: SearchQueryUtils.buildSearchQueryString(queryJSON), ...rest}, lastPolicyRoute.key); +} + +export default resetPolicyIDInNavigationState; diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index 8a0d51a99b95..21faf9924c53 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -12,6 +12,7 @@ import * as Illustrations from '@components/Icon/Illustrations'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import Section from '@components/Section'; +import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import usePermissions from '@hooks/usePermissions'; @@ -19,6 +20,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeIllustrations from '@hooks/useThemeIllustrations'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; +import {resetPolicyIDInNavigationState} from '@libs/Navigation/helpers'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; @@ -45,7 +47,7 @@ function WorkspaceProfilePage({policyDraft, policy: policyProp, route}: Workspac const {shouldUseNarrowLayout} = useResponsiveLayout(); const illustrations = useThemeIllustrations(); const {canUseSpotnanaTravel} = usePermissions(); - + const {activeWorkspaceID, setActiveWorkspaceID} = useActiveWorkspace(); const [currencyList = {}] = useOnyx(ONYXKEYS.CURRENCY_LIST); const [currentUserAccountID = -1] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.accountID}); @@ -164,7 +166,12 @@ function WorkspaceProfilePage({policyDraft, policy: policyProp, route}: Workspac Policy.deleteWorkspace(policy.id, policyName); setIsDeleteModalOpen(false); - }, [policy?.id, policyName]); + + if (policy.id === activeWorkspaceID) { + setActiveWorkspaceID(undefined); + resetPolicyIDInNavigationState(); + } + }, [activeWorkspaceID, policy?.id, policyName, setActiveWorkspaceID]); return ( Date: Thu, 9 Jan 2025 14:52:22 +0100 Subject: [PATCH 236/257] add final review adjustments --- contributingGuides/APPLE_GOOGLE_SIGNIN.md | 2 +- src/SCREENS.ts | 2 +- .../ActiveWorkspaceContext.tsx | 8 ++++- .../ActiveWorkspaceProvider/index.tsx | 7 ++-- src/components/FloatingActionButton.tsx | 2 +- .../FocusTrapForScreen/index.web.tsx | 2 +- .../FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts | 2 +- .../MentionReportRenderer/index.tsx | 2 +- .../Navigation}/BottomTabBar.tsx | 14 ++++---- .../Navigation}/DebugTabView.tsx | 0 .../Navigation}/TopBar.tsx | 0 src/components/PromotedActionsBar.tsx | 2 +- src/components/ScreenWrapper.tsx | 6 ++-- src/components/Search/index.tsx | 2 +- src/components/withNavigation.tsx | 4 +-- .../withNavigationTransitionEnd.tsx | 4 +-- src/hooks/useActiveWorkspace.ts | 3 +- .../Navigation/AppNavigator/AuthScreens.tsx | 10 +++--- .../Navigators/ReportsSplitNavigator.tsx | 20 ++++------- .../Navigators/WorkspaceSplitNavigator.tsx | 2 +- .../GetStateForActionHandlers.ts | 34 ++++++++++++++----- .../RootStackRouter.ts} | 34 +++++++------------ .../TopLevelBottomTabBar.tsx | 13 ++----- .../index.tsx | 19 ++++++----- .../syncBrowserHistory/index.ts | 0 .../syncBrowserHistory/index.web.ts | 0 .../types.ts | 27 +++++++-------- .../createSplitNavigator/SplitRouter.ts | 3 +- .../getInitialSplitNavigatorState.ts | 2 +- .../useHandleScreenResize/index.native.ts | 1 - .../useHandleScreenResize/index.ts | 17 ---------- .../usePrepareSplitStackNavigatorChildren.ts | 1 - src/libs/Navigation/Navigation.ts | 10 +++--- src/libs/Navigation/helpers/closeRHPFlow.ts | 4 +-- .../helpers/getAdaptedStateFromPath.ts | 32 ++++++++--------- .../helpers/getPolicyIDFromState.ts | 6 ++-- .../helpers/getTopmostReportParams.ts | 4 +-- .../Navigation/helpers/isNavigatorName.ts | 8 ++--- .../helpers/isReportTopmostSplitNavigator.ts | 4 +-- .../helpers/isSearchTopmostFullScreenRoute.ts | 6 ++-- src/libs/Navigation/helpers/linkTo/index.ts | 10 +++--- .../helpers/replacePathInNestedState.ts | 4 +-- .../RELATIONS/FULLSCREEN_TO_TAB.ts | 14 ++++++++ .../linkingConfig/RELATIONS/index.ts | 18 ++++------ src/libs/Navigation/linkingConfig/config.ts | 34 ++----------------- src/libs/Navigation/linkingConfig/index.ts | 4 +-- src/libs/Navigation/linkingConfig/prefixes.ts | 4 +-- src/libs/Navigation/types.ts | 27 ++++++--------- src/libs/ReportUtils.ts | 2 +- src/libs/actions/IOU.ts | 1 - src/libs/actions/Session/index.ts | 1 - src/libs/actions/Welcome/OnboardingFlow.ts | 4 +-- .../navigateAfterJoinRequest/index.desktop.ts | 1 - src/libs/navigateAfterJoinRequest/index.ts | 1 - .../navigateAfterJoinRequest/index.web.ts | 1 - src/pages/EditReportFieldPage.tsx | 2 +- src/pages/Search/SearchPage.tsx | 11 +++--- ...PageBottomTab.tsx => SearchPageNarrow.tsx} | 14 ++++---- src/pages/TransactionReceiptPage.tsx | 4 +-- src/pages/WorkspaceSwitcherPage/index.tsx | 2 +- src/pages/home/ReportScreen.tsx | 1 - .../SidebarScreen/BaseSidebarScreen.tsx | 4 +-- src/pages/settings/InitialSettingsPage.tsx | 4 +-- src/pages/workspace/WorkspaceInitialPage.tsx | 2 +- .../workspace/WorkspaceInviteMessagePage.tsx | 1 - src/pages/workspace/WorkspaceJoinUserPage.tsx | 2 -- src/pages/workspace/WorkspacesListPage.tsx | 2 +- src/types/modules/react-navigation.d.ts | 4 +-- tests/ui/WorkspaceCategoriesTest.tsx | 14 ++++---- tests/ui/WorkspaceUpgradeTest.tsx | 10 +++--- 70 files changed, 235 insertions(+), 287 deletions(-) rename src/{libs/Navigation/AppNavigator/createCustomBottomTabNavigator => components/Navigation}/BottomTabBar.tsx (97%) rename src/{libs/Navigation/AppNavigator/createCustomBottomTabNavigator => components/Navigation}/DebugTabView.tsx (100%) rename src/{libs/Navigation/AppNavigator/createCustomBottomTabNavigator => components/Navigation}/TopBar.tsx (100%) rename src/libs/Navigation/AppNavigator/{createResponsiveStackNavigator => createRootStackNavigator}/GetStateForActionHandlers.ts (85%) rename src/libs/Navigation/AppNavigator/{createResponsiveStackNavigator/CustomRouter.ts => createRootStackNavigator/RootStackRouter.ts} (78%) rename src/libs/Navigation/AppNavigator/{createResponsiveStackNavigator => createRootStackNavigator}/TopLevelBottomTabBar.tsx (78%) rename src/libs/Navigation/AppNavigator/{createResponsiveStackNavigator => createRootStackNavigator}/index.tsx (70%) rename src/libs/Navigation/AppNavigator/{createResponsiveStackNavigator => createRootStackNavigator}/syncBrowserHistory/index.ts (100%) rename src/libs/Navigation/AppNavigator/{createResponsiveStackNavigator => createRootStackNavigator}/syncBrowserHistory/index.web.ts (100%) rename src/libs/Navigation/AppNavigator/{createResponsiveStackNavigator => createRootStackNavigator}/types.ts (59%) delete mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/useHandleScreenResize/index.native.ts delete mode 100644 src/libs/Navigation/AppNavigator/createSplitNavigator/useHandleScreenResize/index.ts create mode 100644 src/libs/Navigation/linkingConfig/RELATIONS/FULLSCREEN_TO_TAB.ts rename src/pages/Search/{SearchPageBottomTab.tsx => SearchPageNarrow.tsx} (92%) diff --git a/contributingGuides/APPLE_GOOGLE_SIGNIN.md b/contributingGuides/APPLE_GOOGLE_SIGNIN.md index cc3e256be399..dbbd7a564d7b 100644 --- a/contributingGuides/APPLE_GOOGLE_SIGNIN.md +++ b/contributingGuides/APPLE_GOOGLE_SIGNIN.md @@ -157,7 +157,7 @@ index 4286a26033..850f8944ca 100644 index ca2da6f56b..2c191598f0 100644 --- a/src/libs/Navigation/linkingConfig/prefixes.ts +++ b/src/libs/Navigation/linkingConfig/prefixes.ts - @@ -8,6 +8,7 @@ const prefixes: LinkingOptions['prefixes'] = [ + @@ -8,6 +8,7 @@ const prefixes: LinkingOptions['prefixes'] = [ 'https://www.expensify.cash', 'https://staging.expensify.cash', 'https://dev.new.expensify.com', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 836f16b43479..6ac35016c928 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -31,7 +31,7 @@ const SCREENS = { TRIP_DETAILS: 'Travel_TripDetails', }, SEARCH: { - CENTRAL_PANE: 'Search_Central_Pane', + ROOT: 'Search_Root', REPORT_RHP: 'Search_Report_RHP', ADVANCED_FILTERS_RHP: 'Search_Advanced_Filters_RHP', ADVANCED_FILTERS_DATE_RHP: 'Search_Advanced_Filters_Date_RHP', diff --git a/src/components/ActiveWorkspace/ActiveWorkspaceContext.tsx b/src/components/ActiveWorkspace/ActiveWorkspaceContext.tsx index 8e336a421b92..140c21ff8dd4 100644 --- a/src/components/ActiveWorkspace/ActiveWorkspaceContext.tsx +++ b/src/components/ActiveWorkspace/ActiveWorkspaceContext.tsx @@ -1,8 +1,14 @@ import {createContext} from 'react'; -const ActiveWorkspaceContext = createContext<{activeWorkspaceID: string | undefined; setActiveWorkspaceID: (workspaceID: string | undefined) => void}>({ +type ActiveWorkspaceContextType = { + activeWorkspaceID: string | undefined; + setActiveWorkspaceID: (workspaceID: string | undefined) => void; +}; + +const ActiveWorkspaceContext = createContext({ activeWorkspaceID: undefined, setActiveWorkspaceID: () => {}, }); export default ActiveWorkspaceContext; +export type {ActiveWorkspaceContextType}; diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index 0e9a23108483..07d414f47ba3 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -2,11 +2,11 @@ import {useNavigationState} from '@react-navigation/native'; import React, {useEffect, useMemo, useState} from 'react'; import ActiveWorkspaceContext from '@components/ActiveWorkspace/ActiveWorkspaceContext'; import {getPolicyIDFromState} from '@libs/Navigation/helpers'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; +import type {RootNavigatorParamList, State} from '@libs/Navigation/types'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; function ActiveWorkspaceContextProvider({children}: ChildrenProps) { - const policyID = useNavigationState((state) => getPolicyIDFromState(state as State)); + const policyID = useNavigationState((state) => getPolicyIDFromState(state as State)); const [activeWorkspaceID, setActiveWorkspaceID] = useState(policyID); @@ -17,6 +17,8 @@ function ActiveWorkspaceContextProvider({children}: ChildrenProps) { const value = useMemo( () => ({ activeWorkspaceID, + + // We are exporting setActiveWorkspace to speedup updating this value after changing activeWorkspaceID to avoid flickering of workspace avatar. setActiveWorkspaceID, }), [activeWorkspaceID, setActiveWorkspaceID], @@ -26,4 +28,3 @@ function ActiveWorkspaceContextProvider({children}: ChildrenProps) { } export default ActiveWorkspaceContextProvider; -export {}; diff --git a/src/components/FloatingActionButton.tsx b/src/components/FloatingActionButton.tsx index 103458a6ffc6..bfd7e00aa383 100644 --- a/src/components/FloatingActionButton.tsx +++ b/src/components/FloatingActionButton.tsx @@ -1,12 +1,12 @@ import {useIsFocused, useNavigationState} from '@react-navigation/native'; import type {ForwardedRef} from 'react'; import React, {forwardRef, useEffect, useRef} from 'react'; +// eslint-disable-next-line no-restricted-imports import type {GestureResponderEvent, Role, Text, View} from 'react-native'; import {Platform} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Animated, {createAnimatedPropAdapter, Easing, interpolateColor, processColor, useAnimatedProps, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; import Svg, {Path} from 'react-native-svg'; -// eslint-disable-next-line no-restricted-imports import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; diff --git a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx index 2a5fb850066c..f6e08e3e505f 100644 --- a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx +++ b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx @@ -18,7 +18,7 @@ function FocusTrapForScreen({children, focusTrapSettings}: FocusTrapProps) { if (typeof focusTrapSettings?.active !== 'undefined') { return focusTrapSettings.active; } - // Focus trap can't be active on bottom tab screens because it would block access to the tab bar. + // Focus trap can't be active on sidebar screens because it would block access to the tab bar. if (isSidebarScreenName(route.name)) { return false; } diff --git a/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts b/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts index b98809a14f7c..7941c2c575a9 100644 --- a/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts +++ b/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts @@ -29,7 +29,7 @@ const WIDE_LAYOUT_INACTIVE_SCREENS: string[] = [ SCREENS.WORKSPACE.EXPENSIFY_CARD, SCREENS.WORKSPACE.COMPANY_CARDS, SCREENS.WORKSPACE.DISTANCE_RATES, - SCREENS.SEARCH.CENTRAL_PANE, + SCREENS.SEARCH.ROOT, SCREENS.SETTINGS.TROUBLESHOOT, SCREENS.SETTINGS.SAVE_THE_WORLD, SCREENS.WORKSPACE.RULES, diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx index 7dd36d372d96..e1bfdd29d791 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx @@ -10,7 +10,7 @@ import Text from '@components/Text'; import useCurrentReportID from '@hooks/useCurrentReportID'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; +import {isSearchTopmostFullScreenRoute} from '@libs/Navigation/helpers'; import Navigation from '@navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/components/Navigation/BottomTabBar.tsx similarity index 97% rename from src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx rename to src/components/Navigation/BottomTabBar.tsx index e3c716e40fbf..1b4be6bbae7f 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/components/Navigation/BottomTabBar.tsx @@ -21,7 +21,7 @@ import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import {getPreservedSplitNavigatorState} from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; import {isFullScreenName} from '@libs/Navigation/helpers'; import Navigation from '@libs/Navigation/Navigation'; -import type {AuthScreensParamList, RootStackParamList, State, WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; +import type {AuthScreensParamList, RootNavigatorParamList, State, WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; import type {BrickRoad} from '@libs/WorkspacesSettingsUtils'; @@ -43,10 +43,10 @@ const BOTTOM_TABS = { SETTINGS: 'SETTINGS', } as const; -type BottomTabs = ValueOf; +type BottomTabName = ValueOf; type BottomTabBarProps = { - selectedTab: BottomTabs; + selectedTab: BottomTabName; }; /** @@ -121,11 +121,11 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { return; } interceptAnonymousUser(() => { - const rootState = navigationRef.getRootState() as State; - const lastSearchRoute = rootState.routes.filter((route) => route.name === SCREENS.SEARCH.CENTRAL_PANE).at(-1); + const rootState = navigationRef.getRootState() as State; + const lastSearchRoute = rootState.routes.filter((route) => route.name === SCREENS.SEARCH.ROOT).at(-1); if (lastSearchRoute) { - const {q, ...rest} = lastSearchRoute.params as AuthScreensParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; + const {q, ...rest} = lastSearchRoute.params as AuthScreensParamList[typeof SCREENS.SEARCH.ROOT]; const cleanedQuery = handleQueryWithPolicyID(q, activeWorkspaceID); Navigation.navigate( @@ -304,4 +304,4 @@ BottomTabBar.displayName = 'BottomTabBar'; export default memo(BottomTabBar); export {BOTTOM_TABS}; -export type {BottomTabs}; +export type {BottomTabName}; diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/DebugTabView.tsx b/src/components/Navigation/DebugTabView.tsx similarity index 100% rename from src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/DebugTabView.tsx rename to src/components/Navigation/DebugTabView.tsx diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx b/src/components/Navigation/TopBar.tsx similarity index 100% rename from src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx rename to src/components/Navigation/TopBar.tsx diff --git a/src/components/PromotedActionsBar.tsx b/src/components/PromotedActionsBar.tsx index be4c734608c7..1102b99ba0dc 100644 --- a/src/components/PromotedActionsBar.tsx +++ b/src/components/PromotedActionsBar.tsx @@ -5,7 +5,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as HeaderUtils from '@libs/HeaderUtils'; import * as Localize from '@libs/Localize'; -import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; +import {isSearchTopmostFullScreenRoute} from '@libs/Navigation/helpers'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as ReportActions from '@userActions/Report'; diff --git a/src/components/ScreenWrapper.tsx b/src/components/ScreenWrapper.tsx index 9488b57f302d..7f969e846fa5 100644 --- a/src/components/ScreenWrapper.tsx +++ b/src/components/ScreenWrapper.tsx @@ -14,7 +14,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import * as Browser from '@libs/Browser'; import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {ReportsSplitNavigatorParamList, RootStackParamList} from '@libs/Navigation/types'; +import type {ReportsSplitNavigatorParamList, RootNavigatorParamList} from '@libs/Navigation/types'; import toggleTestToolsModal from '@userActions/TestTool'; import CONST from '@src/CONST'; import CustomDevMenu from './CustomDevMenu'; @@ -98,7 +98,7 @@ type ScreenWrapperProps = { * * This is required because transitionEnd event doesn't trigger in the testing environment. */ - navigation?: PlatformStackNavigationProp | PlatformStackNavigationProp; + navigation?: PlatformStackNavigationProp | PlatformStackNavigationProp; /** Whether to show offline indicator on wide screens */ shouldShowOfflineIndicatorInWideScreen?: boolean; @@ -148,7 +148,7 @@ function ScreenWrapper( * so in other places where ScreenWrapper is used, we need to * fallback to useNavigation. */ - const navigationFallback = useNavigation>(); + const navigationFallback = useNavigation>(); const navigation = navigationProp ?? navigationFallback; const isFocused = useIsFocused(); const {windowHeight} = useWindowDimensions(shouldUseCachedViewportHeight); diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 8d78211aa747..4fc8f41aa53d 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -19,7 +19,7 @@ import * as SearchActions from '@libs/actions/Search'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Log from '@libs/Log'; import memoize from '@libs/memoize'; -import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; +import {isSearchTopmostFullScreenRoute} from '@libs/Navigation/helpers'; import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types'; import * as ReportUtils from '@libs/ReportUtils'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; diff --git a/src/components/withNavigation.tsx b/src/components/withNavigation.tsx index 1d9b2a5f5cb0..32892cc51f54 100644 --- a/src/components/withNavigation.tsx +++ b/src/components/withNavigation.tsx @@ -3,10 +3,10 @@ import {useNavigation} from '@react-navigation/native'; import type {ComponentType, ForwardedRef, RefAttributes} from 'react'; import React from 'react'; import getComponentDisplayName from '@libs/getComponentDisplayName'; -import type {RootStackParamList} from '@libs/Navigation/types'; +import type {RootNavigatorParamList} from '@libs/Navigation/types'; type WithNavigationProps = { - navigation: NavigationProp; + navigation: NavigationProp; }; export default function withNavigation( diff --git a/src/components/withNavigationTransitionEnd.tsx b/src/components/withNavigationTransitionEnd.tsx index 69e04ff22e35..0bb6f1ffa448 100644 --- a/src/components/withNavigationTransitionEnd.tsx +++ b/src/components/withNavigationTransitionEnd.tsx @@ -3,14 +3,14 @@ import type {ComponentType, ForwardedRef, RefAttributes} from 'react'; import React, {useEffect, useState} from 'react'; import getComponentDisplayName from '@libs/getComponentDisplayName'; import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {RootStackParamList} from '@libs/Navigation/types'; +import type {RootNavigatorParamList} from '@libs/Navigation/types'; type WithNavigationTransitionEndProps = {didScreenTransitionEnd: boolean}; export default function (WrappedComponent: ComponentType>): React.ComponentType> { function WithNavigationTransitionEnd(props: TProps, ref: ForwardedRef) { const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false); - const navigation = useNavigation>(); + const navigation = useNavigation>(); useEffect(() => { const unsubscribeTransitionEnd = navigation.addListener('transitionEnd', () => { diff --git a/src/hooks/useActiveWorkspace.ts b/src/hooks/useActiveWorkspace.ts index 568f1d73727c..0ba5426895e1 100644 --- a/src/hooks/useActiveWorkspace.ts +++ b/src/hooks/useActiveWorkspace.ts @@ -1,7 +1,8 @@ import {useContext} from 'react'; +import type {ActiveWorkspaceContextType} from '@components/ActiveWorkspace/ActiveWorkspaceContext'; import ActiveWorkspaceContext from '@components/ActiveWorkspace/ActiveWorkspaceContext'; -function useActiveWorkspace(): {activeWorkspaceID: string | undefined; setActiveWorkspaceID: (workspaceID: string | undefined) => void} { +function useActiveWorkspace(): ActiveWorkspaceContextType { return useContext(ActiveWorkspaceContext); } diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index bf753a4f607b..e34d6b7f6a61 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -56,8 +56,8 @@ import type * as OnyxTypes from '@src/types/onyx'; import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import type ReactComponentModule from '@src/types/utils/ReactComponentModule'; -import createResponsiveStackNavigator from './createResponsiveStackNavigator'; -import {workspaceSplitsWithoutEnteringAnimation} from './createResponsiveStackNavigator/GetStateForActionHandlers'; +import createRootStackNavigator from './createRootStackNavigator'; +import {workspaceSplitsWithoutEnteringAnimation} from './createRootStackNavigator/GetStateForActionHandlers'; import defaultScreenOptions from './defaultScreenOptions'; import ExplanationModalNavigator from './Navigators/ExplanationModalNavigator'; import FeatureTrainingModalNavigator from './Navigators/FeatureTrainingModalNavigator'; @@ -174,7 +174,7 @@ function handleNetworkReconnect() { } } -const RootStack = createResponsiveStackNavigator(); +const RootStack = createRootStackNavigator(); // We want to delay the re-rendering for components(e.g. ReportActionCompose) // that depends on modal visibility until Modal is completely closed and its focused // When modal screen is focused, update modal visibility in Onyx @@ -388,7 +388,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie - {/* This have to be the first navigator in auth screens. */} + {/* This has to be the first navigator in auth screens. */} require('../../../../pages/home/ReportScreen').default; +const loadReportScreen = () => require('@pages/home/ReportScreen').default; const loadSidebarScreen = () => require('@pages/home/sidebar/SidebarScreen').default; const Split = createSplitNavigator(); @@ -24,23 +24,17 @@ function ReportsSplitNavigator() { const {activeWorkspaceID} = useActiveWorkspace(); const rootNavigatorOptions = useRootNavigatorOptions(); const route = useRoute(); - let initialReportID: string | undefined; - const isInitialRender = useRef(true); - // TODO: Figure out if compiler affects this code. - // eslint-disable-next-line react-compiler/react-compiler - if (isInitialRender.current) { + const [initialReportID] = useState(() => { const currentURL = getCurrentUrl(); const reportIdFromPath = currentURL && new URL(currentURL).pathname.match(CONST.REGEX.REPORT_ID_FROM_PATH)?.at(1); if (reportIdFromPath) { - initialReportID = reportIdFromPath; - } else { - initialReportID = ReportUtils.findLastAccessedReport(!canUseDefaultRooms, shouldOpenOnAdminRoom(), activeWorkspaceID)?.reportID ?? ''; + return reportIdFromPath; } - // eslint-disable-next-line react-compiler/react-compiler - isInitialRender.current = false; - } + const initialReport = ReportUtils.findLastAccessedReport(!canUseDefaultRooms, shouldOpenOnAdminRoom(), activeWorkspaceID); + return initialReport?.reportID; + }); return ( diff --git a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx index 4e93f95ec837..f6b9d06edd78 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/WorkspaceSplitNavigator.tsx @@ -1,6 +1,6 @@ import React, {useEffect} from 'react'; import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen'; -import {workspaceSplitsWithoutEnteringAnimation} from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers'; +import {workspaceSplitsWithoutEnteringAnimation} from '@libs/Navigation/AppNavigator/createRootStackNavigator/GetStateForActionHandlers'; import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import useRootNavigatorOptions from '@libs/Navigation/AppNavigator/useRootNavigatorOptions'; import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation'; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts b/src/libs/Navigation/AppNavigator/createRootStackNavigator/GetStateForActionHandlers.ts similarity index 85% rename from src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts rename to src/libs/Navigation/AppNavigator/createRootStackNavigator/GetStateForActionHandlers.ts index b2dea13fbd4d..c57a79af8196 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers.ts +++ b/src/libs/Navigation/AppNavigator/createRootStackNavigator/GetStateForActionHandlers.ts @@ -3,7 +3,7 @@ import {StackActions} from '@react-navigation/native'; import type {ParamListBase, Router} from '@react-navigation/routers'; import Log from '@libs/Log'; import getPolicyIDFromState from '@libs/Navigation/helpers/getPolicyIDFromState'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; +import type {RootNavigatorParamList, State} from '@libs/Navigation/types'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; @@ -81,8 +81,8 @@ function handleSwitchPolicyID( setActiveWorkspaceID: (workspaceID: string | undefined) => void, ) { const lastRoute = state.routes.at(-1); - if (lastRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { - const currentParams = lastRoute.params as RootStackParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; + if (lastRoute?.name === SCREENS.SEARCH.ROOT) { + const currentParams = lastRoute.params as RootNavigatorParamList[typeof SCREENS.SEARCH.ROOT]; const queryJSON = SearchQueryUtils.buildSearchQueryJSON(currentParams.q); if (!queryJSON) { return null; @@ -94,7 +94,7 @@ function handleSwitchPolicyID( delete queryJSON.policyID; } - const newAction = StackActions.push(SCREENS.SEARCH.CENTRAL_PANE, { + const newAction = StackActions.push(SCREENS.SEARCH.ROOT, { ...currentParams, q: SearchQueryUtils.buildSearchQueryString(queryJSON), }); @@ -127,7 +127,7 @@ function handlePushReportAction( policyID = (action.payload.params as Record)?.policyID; setActiveWorkspaceID(policyID); } else { - policyID = getPolicyIDFromState(state as State); + policyID = getPolicyIDFromState(state as State); } const modifiedAction = { @@ -151,7 +151,7 @@ function handlePushSearchPageAction( stackRouter: Router, CommonActions.Action | StackActionType>, setActiveWorkspaceID: (workspaceID: string | undefined) => void, ) { - const currentParams = action.payload.params as RootStackParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; + const currentParams = action.payload.params as RootNavigatorParamList[typeof SCREENS.SEARCH.ROOT]; const queryJSON = SearchQueryUtils.buildSearchQueryJSON(currentParams.q); if (!queryJSON) { @@ -159,7 +159,7 @@ function handlePushSearchPageAction( } if (!queryJSON.policyID) { - const policyID = getPolicyIDFromState(state as State); + const policyID = getPolicyIDFromState(state as State); if (policyID) { queryJSON.policyID = policyID; @@ -200,4 +200,22 @@ function handleDismissModalAction( return stackRouter.getStateForAction(state, newAction, configOptions); } -export {handleOpenWorkspaceSplitAction, handleDismissModalAction, handlePushReportAction, handlePushSearchPageAction, handleSwitchPolicyID, workspaceSplitsWithoutEnteringAnimation}; +function handleNavigatingToModalFromModal( + state: StackNavigationState, + action: PushActionType, + configOptions: RouterConfigOptions, + stackRouter: Router, CommonActions.Action | StackActionType>, +) { + const modifiedState = {...state, routes: state.routes.slice(0, -1), index: state.index !== 0 ? state.index - 1 : 0}; + return stackRouter.getStateForAction(modifiedState, action, configOptions); +} + +export { + handleOpenWorkspaceSplitAction, + handleDismissModalAction, + handlePushReportAction, + handlePushSearchPageAction, + handleSwitchPolicyID, + handleNavigatingToModalFromModal, + workspaceSplitsWithoutEnteringAnimation, +}; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createRootStackNavigator/RootStackRouter.ts similarity index 78% rename from src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts rename to src/libs/Navigation/AppNavigator/createRootStackNavigator/RootStackRouter.ts index f656f43ac06b..ea5160a2862b 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/CustomRouter.ts +++ b/src/libs/Navigation/AppNavigator/createRootStackNavigator/RootStackRouter.ts @@ -10,29 +10,21 @@ import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import * as GetStateForActionHandlers from './GetStateForActionHandlers'; import syncBrowserHistory from './syncBrowserHistory'; -import type { - CustomRouterAction, - CustomRouterActionType, - DismissModalActionType, - OpenWorkspaceSplitActionType, - PushActionType, - ResponsiveStackNavigatorRouterOptions, - SwitchPolicyIdActionType, -} from './types'; - -function isOpenWorkspaceSplitAction(action: CustomRouterAction): action is OpenWorkspaceSplitActionType { +import type {DismissModalActionType, OpenWorkspaceSplitActionType, PushActionType, RootStackNavigatorAction, RootStackNavigatorRouterOptions, SwitchPolicyIdActionType} from './types'; + +function isOpenWorkspaceSplitAction(action: RootStackNavigatorAction): action is OpenWorkspaceSplitActionType { return action.type === CONST.NAVIGATION.ACTION_TYPE.OPEN_WORKSPACE_SPLIT; } -function isSwitchPolicyIdAction(action: CustomRouterAction): action is SwitchPolicyIdActionType { +function isSwitchPolicyIdAction(action: RootStackNavigatorAction): action is SwitchPolicyIdActionType { return action.type === CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID; } -function isPushAction(action: CustomRouterAction): action is PushActionType { +function isPushAction(action: RootStackNavigatorAction): action is PushActionType { return action.type === CONST.NAVIGATION.ACTION_TYPE.PUSH; } -function isDismissModalAction(action: CustomRouterAction): action is DismissModalActionType { +function isDismissModalAction(action: RootStackNavigatorAction): action is DismissModalActionType { return action.type === CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL; } @@ -52,7 +44,7 @@ function shouldPreventReset(state: StackNavigationState, action: return false; } -function isNavigatingToModalFromModal(state: StackNavigationState, action: CommonActions.Action | StackActionType) { +function isNavigatingToModalFromModal(state: StackNavigationState, action: CommonActions.Action | StackActionType): action is PushActionType { if (action.type !== CONST.NAVIGATION.ACTION_TYPE.PUSH) { return false; } @@ -67,13 +59,13 @@ function isNavigatingToModalFromModal(state: StackNavigationState return false; } -function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { +function RootStackRouter(options: RootStackNavigatorRouterOptions) { const stackRouter = StackRouter(options); const {setActiveWorkspaceID} = useActiveWorkspace(); return { ...stackRouter, - getStateForAction(state: StackNavigationState, action: CustomRouterAction, configOptions: RouterConfigOptions) { + getStateForAction(state: StackNavigationState, action: RootStackNavigatorAction, configOptions: RouterConfigOptions) { if (isOpenWorkspaceSplitAction(action)) { return GetStateForActionHandlers.handleOpenWorkspaceSplitAction(state, action, configOptions, stackRouter); } @@ -91,7 +83,7 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { return GetStateForActionHandlers.handlePushReportAction(state, action, configOptions, stackRouter, setActiveWorkspaceID); } - if (action.payload.name === SCREENS.SEARCH.CENTRAL_PANE) { + if (action.payload.name === SCREENS.SEARCH.ROOT) { return GetStateForActionHandlers.handlePushSearchPageAction(state, action, configOptions, stackRouter, setActiveWorkspaceID); } } @@ -103,8 +95,7 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { } if (isNavigatingToModalFromModal(state, action)) { - const modifiedState = {...state, routes: state.routes.slice(0, -1), index: state.index !== 0 ? state.index - 1 : 0}; - return stackRouter.getStateForAction(modifiedState, action, configOptions); + return GetStateForActionHandlers.handleNavigatingToModalFromModal(state, action, configOptions, stackRouter); } return stackRouter.getStateForAction(state, action, configOptions); @@ -112,5 +103,4 @@ function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) { }; } -export default CustomRouter; -export type {CustomRouterActionType}; +export default RootStackRouter; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/TopLevelBottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createRootStackNavigator/TopLevelBottomTabBar.tsx similarity index 78% rename from src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/TopLevelBottomTabBar.tsx rename to src/libs/Navigation/AppNavigator/createRootStackNavigator/TopLevelBottomTabBar.tsx index af50b0c2a258..9c24f145790a 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/TopLevelBottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createRootStackNavigator/TopLevelBottomTabBar.tsx @@ -1,24 +1,17 @@ import {findFocusedRoute, useNavigationState} from '@react-navigation/native'; import React from 'react'; import {View} from 'react-native'; +import BottomTabBar from '@components/Navigation/BottomTabBar'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets'; import useThemeStyles from '@hooks/useThemeStyles'; -import BottomTabBar, {BOTTOM_TABS} from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import {isFullScreenName} from '@libs/Navigation/helpers'; -import SIDEBAR_TO_SPLIT from '@libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT'; +import {FULLSCREEN_TO_TAB, SIDEBAR_TO_SPLIT} from '@libs/Navigation/linkingConfig/RELATIONS'; import type {FullScreenName} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -const FULLSCREEN_TO_TAB = { - [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: BOTTOM_TABS.HOME, - [SCREENS.SEARCH.CENTRAL_PANE]: BOTTOM_TABS.SEARCH, - [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: BOTTOM_TABS.SETTINGS, - [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: BOTTOM_TABS.SETTINGS, -}; - -const SCREENS_WITH_BOTTOM_TAB_BAR = [...Object.keys(SIDEBAR_TO_SPLIT), SCREENS.SEARCH.CENTRAL_PANE, SCREENS.SETTINGS.WORKSPACES]; +const SCREENS_WITH_BOTTOM_TAB_BAR = [...Object.keys(SIDEBAR_TO_SPLIT), SCREENS.SEARCH.ROOT, SCREENS.SETTINGS.WORKSPACES]; /** * Currently we are using the hybrid approach for the bottom tab bar. diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createRootStackNavigator/index.tsx similarity index 70% rename from src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx rename to src/libs/Navigation/AppNavigator/createRootStackNavigator/index.tsx index ab479bf0e773..e71f1d9c5264 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createRootStackNavigator/index.tsx @@ -5,28 +5,29 @@ import {isFullScreenName} from '@libs/Navigation/helpers'; import createPlatformStackNavigatorComponent from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent'; import defaultPlatformStackScreenOptions from '@libs/Navigation/PlatformStackNavigation/defaultPlatformStackScreenOptions'; import type {CustomStateHookProps, PlatformStackNavigationEventMap, PlatformStackNavigationOptions, PlatformStackNavigationState} from '@libs/Navigation/PlatformStackNavigation/types'; -import CustomRouter from './CustomRouter'; +import RootStackRouter from './RootStackRouter'; import TopLevelBottomTabBar from './TopLevelBottomTabBar'; -function useCustomRouterState({state}: CustomStateHookProps) { +// This is an optimization to keep mounted only last few screens in the stack. +function useCustomRootStackNavigatorState({state}: CustomStateHookProps) { const lastSplitIndex = state.routes.findLastIndex((route) => isFullScreenName(route.name)); const routesToRender = state.routes.slice(Math.max(0, lastSplitIndex - 1), state.routes.length); return {...state, routes: routesToRender, index: routesToRender.length - 1}; } -const ResponsiveStackNavigatorComponent = createPlatformStackNavigatorComponent('ResponsiveStackNavigator', { - createRouter: CustomRouter, +const RootStackNavigatorComponent = createPlatformStackNavigatorComponent('ResponsiveStackNavigator', { + createRouter: RootStackRouter, defaultScreenOptions: defaultPlatformStackScreenOptions, useCustomEffects: useNavigationResetOnLayoutChange, - useCustomState: useCustomRouterState, + useCustomState: useCustomRootStackNavigatorState, ExtraContent: TopLevelBottomTabBar, }); -function createResponsiveStackNavigator() { - return createNavigatorFactory, PlatformStackNavigationOptions, PlatformStackNavigationEventMap, typeof ResponsiveStackNavigatorComponent>( - ResponsiveStackNavigatorComponent, +function createRootStackNavigator() { + return createNavigatorFactory, PlatformStackNavigationOptions, PlatformStackNavigationEventMap, typeof RootStackNavigatorComponent>( + RootStackNavigatorComponent, )(); } -export default createResponsiveStackNavigator; +export default createRootStackNavigator; diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/syncBrowserHistory/index.ts b/src/libs/Navigation/AppNavigator/createRootStackNavigator/syncBrowserHistory/index.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/syncBrowserHistory/index.ts rename to src/libs/Navigation/AppNavigator/createRootStackNavigator/syncBrowserHistory/index.ts diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/syncBrowserHistory/index.web.ts b/src/libs/Navigation/AppNavigator/createRootStackNavigator/syncBrowserHistory/index.web.ts similarity index 100% rename from src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/syncBrowserHistory/index.web.ts rename to src/libs/Navigation/AppNavigator/createRootStackNavigator/syncBrowserHistory/index.web.ts diff --git a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/types.ts b/src/libs/Navigation/AppNavigator/createRootStackNavigator/types.ts similarity index 59% rename from src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/types.ts rename to src/libs/Navigation/AppNavigator/createRootStackNavigator/types.ts index 7c0071773495..933cb7d1336a 100644 --- a/src/libs/Navigation/AppNavigator/createResponsiveStackNavigator/types.ts +++ b/src/libs/Navigation/AppNavigator/createRootStackNavigator/types.ts @@ -2,7 +2,7 @@ import type {CommonActions, DefaultNavigatorOptions, ParamListBase, StackActionT import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack'; import type CONST from '@src/CONST'; -type CustomRouterActionType = +type RootStackNavigatorActionType = | { type: typeof CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID; payload: { @@ -19,39 +19,38 @@ type CustomRouterActionType = }; }; -type OpenWorkspaceSplitActionType = CustomRouterActionType & { +type OpenWorkspaceSplitActionType = RootStackNavigatorActionType & { type: typeof CONST.NAVIGATION.ACTION_TYPE.OPEN_WORKSPACE_SPLIT; }; -type SwitchPolicyIdActionType = CustomRouterActionType & { +type SwitchPolicyIdActionType = RootStackNavigatorActionType & { type: typeof CONST.NAVIGATION.ACTION_TYPE.SWITCH_POLICY_ID; }; type PushActionType = StackActionType & {type: typeof CONST.NAVIGATION.ACTION_TYPE.PUSH}; -type DismissModalActionType = CustomRouterActionType & { +type DismissModalActionType = RootStackNavigatorActionType & { type: typeof CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL; }; -type ResponsiveStackNavigatorConfig = { +type RootStackNavigatorConfig = { isSmallScreenWidth: boolean; }; -type ResponsiveStackNavigatorRouterOptions = StackRouterOptions; +type RootStackNavigatorRouterOptions = StackRouterOptions; -type ResponsiveStackNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> & - ResponsiveStackNavigatorConfig; +type RootStackNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> & RootStackNavigatorConfig; -type CustomRouterAction = CommonActions.Action | StackActionType | CustomRouterActionType; +type RootStackNavigatorAction = CommonActions.Action | StackActionType | RootStackNavigatorActionType; export type { OpenWorkspaceSplitActionType, SwitchPolicyIdActionType, PushActionType, DismissModalActionType, - CustomRouterAction, - CustomRouterActionType, - ResponsiveStackNavigatorRouterOptions, - ResponsiveStackNavigatorProps, - ResponsiveStackNavigatorConfig, + RootStackNavigatorAction, + RootStackNavigatorActionType, + RootStackNavigatorRouterOptions, + RootStackNavigatorProps, + RootStackNavigatorConfig, }; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts index cef5dd95c418..e8c0960bb2c5 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts @@ -7,6 +7,7 @@ import {getParamsFromRoute} from '@libs/Navigation/helpers'; import navigationRef from '@libs/Navigation/navigationRef'; import type {NavigationPartialRoute} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; +import CONST from '@src/CONST'; import type {SplitNavigatorRouterOptions} from './types'; import {getPreservedSplitNavigatorState} from './usePreserveSplitNavigatorState'; @@ -92,7 +93,7 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc } function isPushingSidebarOnCentralPane(state: StackState, action: CommonActions.Action | StackActionType, options: SplitNavigatorRouterOptions) { - if (action.type === 'PUSH' && action.payload.name === options.sidebarScreen && state.routes.length > 1) { + if (action.type === CONST.NAVIGATION.ACTION_TYPE.PUSH && action.payload.name === options.sidebarScreen && state.routes.length > 1) { return true; } return false; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/getInitialSplitNavigatorState.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/getInitialSplitNavigatorState.ts index 65ca59f9d8db..06ac86f40b2d 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/getInitialSplitNavigatorState.ts +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/getInitialSplitNavigatorState.ts @@ -1,5 +1,5 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; -import SIDEBAR_TO_SPLIT from '@libs/Navigation/linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT'; +import {SIDEBAR_TO_SPLIT} from '@libs/Navigation/linkingConfig/RELATIONS'; import type {NavigationPartialRoute, SplitNavigatorBySidebar, SplitNavigatorParamListType, SplitNavigatorSidebarScreen} from '@libs/Navigation/types'; type ExtractRouteType = Extract; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useHandleScreenResize/index.native.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/useHandleScreenResize/index.native.ts deleted file mode 100644 index 4ac0a1ae5595..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/useHandleScreenResize/index.native.ts +++ /dev/null @@ -1 +0,0 @@ -export default function useHandleScreenResize() {} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/useHandleScreenResize/index.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/useHandleScreenResize/index.ts deleted file mode 100644 index e6ae505cb560..000000000000 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/useHandleScreenResize/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type {NavigationHelpers, ParamListBase} from '@react-navigation/native'; -import {useEffect} from 'react'; -import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import navigationRef from '@libs/Navigation/navigationRef'; - -export default function useHandleScreenResize(navigation: NavigationHelpers) { - const {shouldUseNarrowLayout} = useResponsiveLayout(); - - useEffect(() => { - if (!navigationRef.isReady()) { - return; - } - // We need to separately reset state of this navigator to trigger getRehydratedState. - navigation.reset(navigation.getState()); - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, [shouldUseNarrowLayout]); -} diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitStackNavigatorChildren.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitStackNavigatorChildren.ts index 4995f96bc1a4..ae55de29f13a 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitStackNavigatorChildren.ts +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/usePrepareSplitStackNavigatorChildren.ts @@ -11,7 +11,6 @@ export default function usePrepareSplitNavigatorChildren(screensNode: ReactNode, return screen; } - // @TODO: Fix types here const screenProps = screen?.props as RouteConfig, EventMapBase>; if (screenProps?.name === sidebarScreenName) { diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 48e6094dd897..c7d2096452e4 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -32,7 +32,7 @@ import { } from './helpers'; import linkingConfig from './linkingConfig'; import navigationRef from './navigationRef'; -import type {NavigationPartialRoute, NavigationStateRoute, RootStackParamList, State} from './types'; +import type {NavigationPartialRoute, NavigationStateRoute, RootNavigatorParamList, State} from './types'; let allReports: OnyxCollection; Onyx.connect({ @@ -213,7 +213,7 @@ function doesRouteMatchToMinimalActionPayload(route: NavigationStateRoute | Navi * @private * Checks whether the given state is the root navigator state */ -function isRootNavigatorState(state: State): state is State { +function isRootNavigatorState(state: State): state is State { return state.key === navigationRef.current?.getRootState().key; } @@ -339,7 +339,7 @@ function resetToHome() { } : undefined; const payload = getInitialSplitNavigatorState({name: SCREENS.HOME}, splitNavigatorMainScreen); - navigationRef.dispatch({payload, type: 'REPLACE', target: rootState.key}); + navigationRef.dispatch({payload, type: CONST.NAVIGATION.ACTION_TYPE.REPLACE, target: rootState.key}); } /** @@ -451,7 +451,7 @@ type NavigateToReportWithPolicyCheckPayload = {report?: OnyxEntry; repor */ function navigateToReportWithPolicyCheck({report, reportID, reportActionID, referrer, policyIDToCheck}: NavigateToReportWithPolicyCheckPayload, ref = navigationRef) { const targetReport = reportID ? {reportID, ...allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]} : report; - const policyID = policyIDToCheck ?? getPolicyIDFromState(navigationRef.getRootState() as State); + const policyID = policyIDToCheck ?? getPolicyIDFromState(navigationRef.getRootState() as State); const policyMemberAccountIDs = getPolicyEmployeeAccountIDs(policyID); const shouldOpenAllWorkspace = isEmptyObject(targetReport) ? true : !ReportUtils.doesReportBelongToWorkspace(targetReport, policyMemberAccountIDs, policyID); @@ -474,7 +474,7 @@ function navigateToReportWithPolicyCheck({report, reportID, reportActionID, refe ref.dispatch( StackActions.push(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, { - policyID: null, + policyID: undefined, screen: SCREENS.REPORT, params, }), diff --git a/src/libs/Navigation/helpers/closeRHPFlow.ts b/src/libs/Navigation/helpers/closeRHPFlow.ts index 0f814ca13bb7..608fd7c855ea 100644 --- a/src/libs/Navigation/helpers/closeRHPFlow.ts +++ b/src/libs/Navigation/helpers/closeRHPFlow.ts @@ -1,13 +1,13 @@ import type {NavigationContainerRef} from '@react-navigation/native'; import {StackActions} from '@react-navigation/native'; import Log from '@libs/Log'; -import type {RootStackParamList} from '@libs/Navigation/types'; +import type {RootNavigatorParamList} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; /** * Closes the last RHP flow, if there is only one, closes the entire RHP. */ -export default function closeRHPFlow(navigationRef: NavigationContainerRef) { +export default function closeRHPFlow(navigationRef: NavigationContainerRef) { if (!navigationRef.isReady()) { return; } diff --git a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts index 3ab638f6808c..d4464cc50202 100644 --- a/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/helpers/getAdaptedStateFromPath.ts @@ -6,8 +6,8 @@ import type {OnyxCollection} from 'react-native-onyx'; import {isAnonymousUser} from '@libs/actions/Session'; import getInitialSplitNavigatorState from '@libs/Navigation/AppNavigator/createSplitNavigator/getInitialSplitNavigatorState'; import config from '@libs/Navigation/linkingConfig/config'; -import RELATIONS from '@libs/Navigation/linkingConfig/RELATIONS'; -import type {NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types'; +import {RHP_TO_SETTINGS, RHP_TO_SIDEBAR, RHP_TO_WORKSPACE, SEARCH_TO_RHP} from '@libs/Navigation/linkingConfig/RELATIONS'; +import type {NavigationPartialRoute, RootNavigatorParamList} from '@libs/Navigation/types'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -69,27 +69,27 @@ function getMatchingFullScreenRoute(route: NavigationPartialRoute, policyID?: st return getMatchingFullScreenRoute(focusedStateForBackToRoute, policyID); } - if (RELATIONS.SEARCH_TO_RHP.includes(route.name)) { - const paramsFromRoute = getParamsFromRoute(SCREENS.SEARCH.CENTRAL_PANE); + if (SEARCH_TO_RHP.includes(route.name)) { + const paramsFromRoute = getParamsFromRoute(SCREENS.SEARCH.ROOT); return { - name: SCREENS.SEARCH.CENTRAL_PANE, + name: SCREENS.SEARCH.ROOT, params: paramsFromRoute.length > 0 ? pick(route.params, paramsFromRoute) : undefined, }; } - if (RELATIONS.RHP_TO_SIDEBAR[route.name]) { + if (RHP_TO_SIDEBAR[route.name]) { return getInitialSplitNavigatorState( { - name: RELATIONS.RHP_TO_SIDEBAR[route.name], + name: RHP_TO_SIDEBAR[route.name], }, undefined, policyID ? {policyID} : undefined, ); } - if (RELATIONS.RHP_TO_WORKSPACE[route.name]) { - const paramsFromRoute = getParamsFromRoute(RELATIONS.RHP_TO_WORKSPACE[route.name]); + if (RHP_TO_WORKSPACE[route.name]) { + const paramsFromRoute = getParamsFromRoute(RHP_TO_WORKSPACE[route.name]); return getInitialSplitNavigatorState( { @@ -97,21 +97,21 @@ function getMatchingFullScreenRoute(route: NavigationPartialRoute, policyID?: st params: paramsFromRoute.length > 0 ? pick(route.params, paramsFromRoute) : undefined, }, { - name: RELATIONS.RHP_TO_WORKSPACE[route.name], + name: RHP_TO_WORKSPACE[route.name], params: paramsFromRoute.length > 0 ? pick(route.params, paramsFromRoute) : undefined, }, ); } - if (RELATIONS.RHP_TO_SETTINGS[route.name]) { - const paramsFromRoute = getParamsFromRoute(RELATIONS.RHP_TO_SETTINGS[route.name]); + if (RHP_TO_SETTINGS[route.name]) { + const paramsFromRoute = getParamsFromRoute(RHP_TO_SETTINGS[route.name]); return getInitialSplitNavigatorState( { name: SCREENS.SETTINGS.ROOT, }, { - name: RELATIONS.RHP_TO_SETTINGS[route.name], + name: RHP_TO_SETTINGS[route.name], params: paramsFromRoute.length > 0 ? pick(route.params, paramsFromRoute) : undefined, }, ); @@ -168,7 +168,7 @@ function getOnboardingAdaptedState(state: PartialState): Partia return getRoutesWithIndex(routes); } -function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { +function getAdaptedState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { const fullScreenRoute = state.routes.find((route) => isFullScreenName(route.name)); const onboardingNavigator = state.routes.find((route) => route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR); const isReportSplitNavigator = fullScreenRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; @@ -234,7 +234,7 @@ const getAdaptedStateFromPath: GetAdaptedStateFromPath = (path, options, shouldR // Anonymous users don't have access to workspaces const policyID = isAnonymous ? undefined : extractPolicyIDFromPath(path); - const state = getStateFromPath(pathWithoutPolicyID, options) as PartialState>; + const state = getStateFromPath(pathWithoutPolicyID, options) as PartialState>; if (shouldReplacePathInNestedState) { replacePathInNestedState(state, normalizedPath); } @@ -243,7 +243,7 @@ const getAdaptedStateFromPath: GetAdaptedStateFromPath = (path, options, shouldR throw new Error('Unable to parse path'); } - // On SCREENS.SEARCH.CENTRAL_PANE policyID is stored differently inside search query ("q" param), so we're handling this case + // On SCREENS.SEARCH.ROOT policyID is stored differently inside search query ("q" param), so we're handling this case const focusedRoute = findFocusedRoute(state); const policyIDFromQuery = extractPolicyIDFromQuery(focusedRoute); return getAdaptedState(state, policyID ?? policyIDFromQuery); diff --git a/src/libs/Navigation/helpers/getPolicyIDFromState.ts b/src/libs/Navigation/helpers/getPolicyIDFromState.ts index 808455834247..f5cd3ffdd081 100644 --- a/src/libs/Navigation/helpers/getPolicyIDFromState.ts +++ b/src/libs/Navigation/helpers/getPolicyIDFromState.ts @@ -1,4 +1,4 @@ -import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; +import type {NavigationPartialRoute, RootNavigatorParamList, State} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import extractPolicyIDFromQuery from './extractPolicyIDFromQuery'; @@ -10,8 +10,8 @@ import extractPolicyIDFromQuery from './extractPolicyIDFromQuery'; * - on NAVIGATORS.REPORTS_SPLIT_NAVIGATOR as `policyID` param * - on Search related screens as policyID filter inside `q` (SearchQuery) param (only for SEARCH_CENTRAL_PANE) */ -const getPolicyIDFromState = (state: State): string | undefined => { - const lastPolicyRoute = state?.routes?.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.CENTRAL_PANE); +const getPolicyIDFromState = (state: State): string | undefined => { + const lastPolicyRoute = state?.routes?.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.ROOT); if (lastPolicyRoute?.params && 'policyID' in lastPolicyRoute.params) { return lastPolicyRoute?.params?.policyID; } diff --git a/src/libs/Navigation/helpers/getTopmostReportParams.ts b/src/libs/Navigation/helpers/getTopmostReportParams.ts index 618b8760add4..83844847bc1f 100644 --- a/src/libs/Navigation/helpers/getTopmostReportParams.ts +++ b/src/libs/Navigation/helpers/getTopmostReportParams.ts @@ -1,5 +1,5 @@ import type {NavigationState, PartialState} from '@react-navigation/native'; -import type {ReportsSplitNavigatorParamList, RootStackParamList} from '@libs/Navigation/types'; +import type {ReportsSplitNavigatorParamList, RootNavigatorParamList} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; @@ -12,7 +12,7 @@ import SCREENS from '@src/SCREENS'; * @returns - It's possible that there is no report screen */ -type State = NavigationState | NavigationState | PartialState; +type State = NavigationState | NavigationState | PartialState; function getTopmostReportParams(state: State): ReportsSplitNavigatorParamList[typeof SCREENS.REPORT] | undefined { if (!state) { diff --git a/src/libs/Navigation/helpers/isNavigatorName.ts b/src/libs/Navigation/helpers/isNavigatorName.ts index d35480f8136a..29e3e142f201 100644 --- a/src/libs/Navigation/helpers/isNavigatorName.ts +++ b/src/libs/Navigation/helpers/isNavigatorName.ts @@ -1,4 +1,4 @@ -import RELATIONS from '@libs/Navigation/linkingConfig/RELATIONS'; +import {SIDEBAR_TO_SPLIT, SPLIT_TO_SIDEBAR} from '@libs/Navigation/linkingConfig/RELATIONS'; import type {FullScreenName, OnboardingFlowName, SplitNavigatorName, SplitNavigatorSidebarScreen} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; @@ -12,9 +12,9 @@ const ONBOARDING_SCREENS = [ SCREENS.ONBOARDING.WORKSPACES, ]; -const SPLIT_NAVIGATORS_SET = new Set(Object.values(RELATIONS.SIDEBAR_TO_SPLIT)); -const FULL_SCREENS_SET = new Set([...Object.values(RELATIONS.SIDEBAR_TO_SPLIT), SCREENS.SEARCH.CENTRAL_PANE]); -const SIDEBARS_SET = new Set(Object.values(RELATIONS.SPLIT_TO_SIDEBAR)); +const SPLIT_NAVIGATORS_SET = new Set(Object.values(SIDEBAR_TO_SPLIT)); +const FULL_SCREENS_SET = new Set([...Object.values(SIDEBAR_TO_SPLIT), SCREENS.SEARCH.ROOT]); +const SIDEBARS_SET = new Set(Object.values(SPLIT_TO_SIDEBAR)); const ONBOARDING_SCREENS_SET = new Set(ONBOARDING_SCREENS); /** diff --git a/src/libs/Navigation/helpers/isReportTopmostSplitNavigator.ts b/src/libs/Navigation/helpers/isReportTopmostSplitNavigator.ts index be811e945f2e..fbffc8bba7b0 100644 --- a/src/libs/Navigation/helpers/isReportTopmostSplitNavigator.ts +++ b/src/libs/Navigation/helpers/isReportTopmostSplitNavigator.ts @@ -1,10 +1,10 @@ import {navigationRef} from '@libs/Navigation/Navigation'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; +import type {RootNavigatorParamList, State} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import {isFullScreenName} from './isNavigatorName'; const isReportTopmostSplitNavigator = (): boolean => { - const rootState = navigationRef.getRootState() as State; + const rootState = navigationRef.getRootState() as State; if (!rootState) { return false; diff --git a/src/libs/Navigation/helpers/isSearchTopmostFullScreenRoute.ts b/src/libs/Navigation/helpers/isSearchTopmostFullScreenRoute.ts index e98b253b74bd..43077d44ab2a 100644 --- a/src/libs/Navigation/helpers/isSearchTopmostFullScreenRoute.ts +++ b/src/libs/Navigation/helpers/isSearchTopmostFullScreenRoute.ts @@ -1,16 +1,16 @@ import {navigationRef} from '@libs/Navigation/Navigation'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; +import type {RootNavigatorParamList, State} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; import {isFullScreenName} from './isNavigatorName'; const isSearchTopmostFullScreenRoute = (): boolean => { - const rootState = navigationRef.getRootState() as State; + const rootState = navigationRef.getRootState() as State; if (!rootState) { return false; } - return rootState.routes.findLast((route) => isFullScreenName(route.name))?.name === SCREENS.SEARCH.CENTRAL_PANE; + return rootState.routes.findLast((route) => isFullScreenName(route.name))?.name === SCREENS.SEARCH.ROOT; }; export default isSearchTopmostFullScreenRoute; diff --git a/src/libs/Navigation/helpers/linkTo/index.ts b/src/libs/Navigation/helpers/linkTo/index.ts index 39dd6b0b1571..5ca04bf947b7 100644 --- a/src/libs/Navigation/helpers/linkTo/index.ts +++ b/src/libs/Navigation/helpers/linkTo/index.ts @@ -7,7 +7,7 @@ import normalizePath from '@libs/Navigation/helpers/normalizePath'; import {shallowCompare} from '@libs/ObjectUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import linkingConfig from '@navigation/linkingConfig'; -import type {NavigationPartialRoute, ReportsSplitNavigatorParamList, RootStackParamList, StackNavigationAction} from '@navigation/types'; +import type {NavigationPartialRoute, ReportsSplitNavigatorParamList, RootNavigatorParamList, StackNavigationAction} from '@navigation/types'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import type {Route} from '@src/ROUTES'; @@ -31,7 +31,7 @@ function createActionWithPolicyID(action: StackActionType, policyID: string): St }; } -function areNamesAndParamsEqual(currentState: NavigationState, stateFromPath: PartialState>) { +function areNamesAndParamsEqual(currentState: NavigationState, stateFromPath: PartialState>) { const currentFocusedRoute = findFocusedRoute(currentState); const targetFocusedRoute = findFocusedRoute(stateFromPath); @@ -60,7 +60,7 @@ function isNavigatingToReportWithSameReportID(currentRoute: NavigationPartialRou return currentParams.reportID === newParams.reportID; } -export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string) { +export default function linkTo(navigation: NavigationContainerRef | null, path: Route, type?: string) { if (!navigation) { throw new Error("Couldn't find a navigation object. Is your component inside a screen in a navigator?"); } @@ -72,8 +72,8 @@ export default function linkTo(navigation: NavigationContainerRef>; - const currentState = navigation.getRootState() as NavigationState; + const stateFromPath = getStateFromPath(pathWithoutPolicyID) as PartialState>; + const currentState = navigation.getRootState() as NavigationState; const focusedRouteFromPath = findFocusedRoute(stateFromPath); const currentFocusedRoute = findFocusedRoute(currentState); diff --git a/src/libs/Navigation/helpers/replacePathInNestedState.ts b/src/libs/Navigation/helpers/replacePathInNestedState.ts index 6b50cd76446e..242632c83a55 100644 --- a/src/libs/Navigation/helpers/replacePathInNestedState.ts +++ b/src/libs/Navigation/helpers/replacePathInNestedState.ts @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {findFocusedRoute} from '@react-navigation/native'; import type {NavigationState, PartialState} from '@react-navigation/native'; -import type {RootStackParamList} from '@libs/Navigation/types'; +import type {RootNavigatorParamList} from '@libs/Navigation/types'; -function replacePathInNestedState(state: PartialState>, path: string) { +function replacePathInNestedState(state: PartialState>, path: string) { const found = findFocusedRoute(state); if (!found) { return; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/FULLSCREEN_TO_TAB.ts b/src/libs/Navigation/linkingConfig/RELATIONS/FULLSCREEN_TO_TAB.ts new file mode 100644 index 000000000000..544eaa6f22fc --- /dev/null +++ b/src/libs/Navigation/linkingConfig/RELATIONS/FULLSCREEN_TO_TAB.ts @@ -0,0 +1,14 @@ +import type {BottomTabName} from '@components/Navigation/BottomTabBar'; +import {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; +import type {FullScreenName} from '@libs/Navigation/types'; +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; + +const FULLSCREEN_TO_TAB: Record = { + [NAVIGATORS.REPORTS_SPLIT_NAVIGATOR]: BOTTOM_TABS.HOME, + [SCREENS.SEARCH.ROOT]: BOTTOM_TABS.SEARCH, + [NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]: BOTTOM_TABS.SETTINGS, + [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR]: BOTTOM_TABS.SETTINGS, +}; + +export default FULLSCREEN_TO_TAB; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/index.ts b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts index eed5e8d78b39..3f779ba351a1 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/index.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/index.ts @@ -1,3 +1,4 @@ +import FULLSCREEN_TO_TAB from './FULLSCREEN_TO_TAB'; import SEARCH_TO_RHP from './SEARCH_TO_RHP'; import SETTINGS_TO_RHP from './SETTINGS_TO_RHP'; import SIDEBAR_TO_RHP from './SIDEBAR_TO_RHP'; @@ -16,14 +17,9 @@ function createInverseRelation(relations: Pa return reversedRelations; } -export default { - SETTINGS_TO_RHP, - RHP_TO_SETTINGS: createInverseRelation(SETTINGS_TO_RHP), - RHP_TO_WORKSPACE: createInverseRelation(WORKSPACE_TO_RHP), - RHP_TO_SIDEBAR: createInverseRelation(SIDEBAR_TO_RHP), - SEARCH_TO_RHP, - SIDEBAR_TO_RHP, - WORKSPACE_TO_RHP, - SIDEBAR_TO_SPLIT, - SPLIT_TO_SIDEBAR: createInverseRelation(SIDEBAR_TO_SPLIT), -}; +const RHP_TO_SETTINGS = createInverseRelation(SETTINGS_TO_RHP); +const RHP_TO_WORKSPACE = createInverseRelation(WORKSPACE_TO_RHP); +const RHP_TO_SIDEBAR = createInverseRelation(SIDEBAR_TO_RHP); +const SPLIT_TO_SIDEBAR = createInverseRelation(SIDEBAR_TO_SPLIT); + +export {SETTINGS_TO_RHP, RHP_TO_SETTINGS, RHP_TO_WORKSPACE, RHP_TO_SIDEBAR, SEARCH_TO_RHP, SIDEBAR_TO_RHP, WORKSPACE_TO_RHP, SIDEBAR_TO_SPLIT, SPLIT_TO_SIDEBAR, FULLSCREEN_TO_TAB}; diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 26d48e2ed0f7..b9823b0cda76 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1,14 +1,14 @@ import type {LinkingOptions} from '@react-navigation/native'; import {createNormalizedConfigs} from '@libs/Navigation/helpers'; import type {RouteConfig} from '@libs/Navigation/helpers'; -import type {RootStackParamList} from '@navigation/types'; +import type {RootNavigatorParamList} from '@navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import ROUTES from '@src/ROUTES'; import type {Screen} from '@src/SCREENS'; import SCREENS from '@src/SCREENS'; // Moved to a separate file to avoid cyclic dependencies. -const config: LinkingOptions['config'] = { +const config: LinkingOptions['config'] = { screens: { // Main Routes [SCREENS.VALIDATE_LOGIN]: ROUTES.VALIDATE_LOGIN, @@ -28,37 +28,9 @@ const config: LinkingOptions['config'] = { [SCREENS.REPORT_AVATAR]: ROUTES.REPORT_AVATAR.route, [SCREENS.TRANSACTION_RECEIPT]: ROUTES.TRANSACTION_RECEIPT.route, [SCREENS.WORKSPACE_JOIN_USER]: ROUTES.WORKSPACE_JOIN_USER.route, - // [SCREENS.REPORT]: ROUTES.REPORT_WITH_ID.route, - // [SCREENS.SETTINGS.PROFILE.ROOT]: { - // path: ROUTES.SETTINGS_PROFILE, - // exact: true, - // }, - // [SCREENS.SETTINGS.PREFERENCES.ROOT]: { - // path: ROUTES.SETTINGS_PREFERENCES, - // // exact: true, - // }, - // [SCREENS.SETTINGS.SECURITY]: { - // path: ROUTES.SETTINGS_SECURITY, - // exact: true, - // }, - // [SCREENS.SETTINGS.WALLET.ROOT]: { - // path: ROUTES.SETTINGS_WALLET, - // exact: true, - // }, - // [SCREENS.SETTINGS.ABOUT]: { - // path: ROUTES.SETTINGS_ABOUT, - // exact: true, - // }, - // [SCREENS.SETTINGS.TROUBLESHOOT]: { - // path: ROUTES.SETTINGS_TROUBLESHOOT, - // exact: true, - // }, - // [SCREENS.SETTINGS.WORKSPACES]: ROUTES.SETTINGS_WORKSPACES, - [SCREENS.SEARCH.CENTRAL_PANE]: { + [SCREENS.SEARCH.ROOT]: { path: ROUTES.SEARCH_CENTRAL_PANE.route, }, - // [SCREENS.SETTINGS.SAVE_THE_WORLD]: ROUTES.SETTINGS_SAVE_THE_WORLD, - // [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: ROUTES.SETTINGS_SUBSCRIPTION, [SCREENS.NOT_FOUND]: '*', [NAVIGATORS.LEFT_MODAL_NAVIGATOR]: { diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index 483928e7011d..b09b24852d9d 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -2,11 +2,11 @@ import type {LinkingOptions} from '@react-navigation/native'; import {customGetPathFromState} from '@libs/Navigation/helpers'; import getAdaptedStateFromPath from '@libs/Navigation/helpers/getAdaptedStateFromPath'; -import type {RootStackParamList} from '@navigation/types'; +import type {RootNavigatorParamList} from '@navigation/types'; import config from './config'; import prefixes from './prefixes'; -const linkingConfig: LinkingOptions = { +const linkingConfig: LinkingOptions = { getStateFromPath: getAdaptedStateFromPath, getPathFromState: customGetPathFromState, prefixes, diff --git a/src/libs/Navigation/linkingConfig/prefixes.ts b/src/libs/Navigation/linkingConfig/prefixes.ts index ca2da6f56b39..c3b52cef9852 100644 --- a/src/libs/Navigation/linkingConfig/prefixes.ts +++ b/src/libs/Navigation/linkingConfig/prefixes.ts @@ -1,8 +1,8 @@ import type {LinkingOptions} from '@react-navigation/native'; -import type {RootStackParamList} from '@libs/Navigation/types'; +import type {RootNavigatorParamList} from '@libs/Navigation/types'; import CONST from '@src/CONST'; -const prefixes: LinkingOptions['prefixes'] = [ +const prefixes: LinkingOptions['prefixes'] = [ 'app://-/', 'new-expensify://', 'https://www.expensify.cash', diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index d00e43a1f54b..65742b65e4f2 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -22,11 +22,11 @@ import type SCREENS from '@src/SCREENS'; import type EXIT_SURVEY_REASON_FORM_INPUT_IDS from '@src/types/form/ExitSurveyReasonForm'; import type {CompanyCardFeed} from '@src/types/onyx'; import type {ConnectionName, SageIntacctMappingName} from '@src/types/onyx/Policy'; -import type SIDEBAR_TO_SPLIT from './linkingConfig/RELATIONS/SIDEBAR_TO_SPLIT'; +import type {SIDEBAR_TO_SPLIT} from './linkingConfig/RELATIONS'; -type NavigationRef = NavigationContainerRefWithCurrent; +type NavigationRef = NavigationContainerRefWithCurrent; -type NavigationRoot = NavigationHelpers; +type NavigationRoot = NavigationHelpers; type GoBackAction = Extract; type ResetAction = Extract; @@ -74,7 +74,6 @@ type BackToAndForwardToParms = { type SettingsNavigatorParamList = { [SCREENS.SETTINGS.SHARE_CODE]: undefined; - [SCREENS.SETTINGS.PROFILE.ROOT]: undefined; [SCREENS.SETTINGS.PROFILE.PRONOUNS]: undefined; [SCREENS.SETTINGS.PROFILE.DISPLAY_NAME]: undefined; [SCREENS.SETTINGS.PROFILE.TIMEZONE]: undefined; @@ -99,16 +98,11 @@ type SettingsNavigatorParamList = { backTo?: Routes; forwardTo?: Routes; }; - // [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; - [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: undefined; [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE]: undefined; [SCREENS.SETTINGS.PREFERENCES.LANGUAGE]: undefined; [SCREENS.SETTINGS.PREFERENCES.THEME]: undefined; [SCREENS.SETTINGS.CLOSE]: undefined; - // [SCREENS.SETTINGS.SECURITY]: undefined; - // [SCREENS.SETTINGS.ABOUT]: undefined; [SCREENS.SETTINGS.APP_DOWNLOAD_LINKS]: undefined; - // [SCREENS.SETTINGS.TROUBLESHOOT]: undefined; [SCREENS.SETTINGS.CONSOLE]: { backTo: Routes; }; @@ -117,7 +111,6 @@ type SettingsNavigatorParamList = { source: string; backTo: Routes; }; - [SCREENS.SETTINGS.WALLET.ROOT]: undefined; [SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS]: undefined; [SCREENS.SETTINGS.WALLET.DOMAIN_CARD]: { /** cardID of selected card */ @@ -1484,7 +1477,7 @@ type TravelNavigatorParamList = { }; type ReportsSplitNavigatorParamList = { - [SCREENS.HOME]: {policyID?: string}; + [SCREENS.HOME]: undefined; [SCREENS.REPORT]: { reportActionID: string; reportID: string; @@ -1494,7 +1487,7 @@ type ReportsSplitNavigatorParamList = { }; type SettingsSplitNavigatorParamList = { - [SCREENS.SETTINGS.ROOT]: {policyID?: string}; + [SCREENS.SETTINGS.ROOT]: undefined; [SCREENS.SETTINGS.WORKSPACES]: undefined; [SCREENS.SETTINGS.PREFERENCES.ROOT]: undefined; [SCREENS.SETTINGS.SECURITY]: undefined; @@ -1719,7 +1712,7 @@ type AuthScreensParamList = SharedScreensParamList & { isFromReviewDuplicates?: string; }; [SCREENS.CONNECTION_COMPLETE]: undefined; - [SCREENS.SEARCH.CENTRAL_PANE]: { + [SCREENS.SEARCH.ROOT]: { q: SearchQueryString; name?: string; }; @@ -1798,7 +1791,7 @@ type DebugParamList = { }; }; -type RootStackParamList = PublicScreensParamList & AuthScreensParamList & LeftModalNavigatorParamList; +type RootNavigatorParamList = PublicScreensParamList & AuthScreensParamList & LeftModalNavigatorParamList; type WorkspaceScreenName = keyof WorkspaceSplitNavigatorParamList; @@ -1808,13 +1801,13 @@ type SplitNavigatorName = keyof SplitNavigatorParamListType; type SplitNavigatorScreenName = keyof (WorkspaceSplitNavigatorParamList & SettingsSplitNavigatorParamList & ReportsSplitNavigatorParamList); -type FullScreenName = SplitNavigatorName | typeof SCREENS.SEARCH.CENTRAL_PANE; +type FullScreenName = SplitNavigatorName | typeof SCREENS.SEARCH.ROOT; declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace ReactNavigation { // eslint-disable-next-line @typescript-eslint/consistent-type-definitions, @typescript-eslint/no-empty-interface - interface RootParamList extends RootStackParamList {} + interface RootParamList extends RootNavigatorParamList {} } } @@ -1855,7 +1848,7 @@ export type { RestrictedActionParamList, RightModalNavigatorParamList, RoomMembersNavigatorParamList, - RootStackParamList, + RootNavigatorParamList, SearchAdvancedFiltersParamList, SearchReportParamList, SearchSavedSearchParamList, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 1bd7e9702a04..e9b53cf55085 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4315,7 +4315,7 @@ function navigateBackOnDeleteTransaction(backRoute: Route | undefined, isFromRHP const rootState = navigationRef.current?.getRootState(); const lastFullScreenRoute = rootState?.routes.findLast((route) => isFullScreenName(route.name)); - if (lastFullScreenRoute?.name === SCREENS.SEARCH.CENTRAL_PANE) { + if (lastFullScreenRoute?.name === SCREENS.SEARCH.ROOT) { Navigation.dismissModal(); return; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 1c67a9370d39..f19994f44629 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -40,7 +40,6 @@ import * as IOUUtils from '@libs/IOUUtils'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; import * as Localize from '@libs/Localize'; import Log from '@libs/Log'; -import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import * as NextStepUtils from '@libs/NextStepUtils'; import {rand64} from '@libs/NumberUtils'; diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index 0cf18ae1af93..1dbb01b008dd 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -810,7 +810,6 @@ function cleanupSession() { PersistedRequests.clear(); NetworkConnection.clearReconnectionCallbacks(); SessionUtils.resetDidUserLogInDuringSession(); - // TODO: Check if this breaks something resetHomeRouteParams(); clearCache().then(() => { Log.info('Cleared all cache data', true, {}, true); diff --git a/src/libs/actions/Welcome/OnboardingFlow.ts b/src/libs/actions/Welcome/OnboardingFlow.ts index bdbc6dde5645..cee6fde235ba 100644 --- a/src/libs/actions/Welcome/OnboardingFlow.ts +++ b/src/libs/actions/Welcome/OnboardingFlow.ts @@ -4,7 +4,7 @@ import Onyx from 'react-native-onyx'; import {getAdaptedStateFromPath} from '@libs/Navigation/helpers'; import linkingConfig from '@libs/Navigation/linkingConfig'; import {navigationRef} from '@libs/Navigation/Navigation'; -import type {RootStackParamList} from '@libs/Navigation/types'; +import type {RootNavigatorParamList} from '@libs/Navigation/types'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -40,7 +40,7 @@ Onyx.connect({ function startOnboardingFlow(isPrivateDomain?: boolean) { const currentRoute = navigationRef.getCurrentRoute(); const adaptedState = getAdaptedStateFromPath(getOnboardingInitialPath(isPrivateDomain), linkingConfig.config, false); - const focusedRoute = findFocusedRoute(adaptedState as PartialState>); + const focusedRoute = findFocusedRoute(adaptedState as PartialState>); if (focusedRoute?.name === currentRoute?.name) { return; } diff --git a/src/libs/navigateAfterJoinRequest/index.desktop.ts b/src/libs/navigateAfterJoinRequest/index.desktop.ts index 9b72ee30de57..d63fcb25aaf7 100644 --- a/src/libs/navigateAfterJoinRequest/index.desktop.ts +++ b/src/libs/navigateAfterJoinRequest/index.desktop.ts @@ -3,7 +3,6 @@ import Navigation from '@navigation/Navigation'; import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { - // @TODO: Check if this method works the same as on the main branch Navigation.goBack(undefined, {shouldPopToTop: true}); if (getIsSmallScreenWidth()) { Navigation.navigate(ROUTES.SETTINGS); diff --git a/src/libs/navigateAfterJoinRequest/index.ts b/src/libs/navigateAfterJoinRequest/index.ts index a3ac50cd59be..60cbf64cda90 100644 --- a/src/libs/navigateAfterJoinRequest/index.ts +++ b/src/libs/navigateAfterJoinRequest/index.ts @@ -2,7 +2,6 @@ import Navigation from '@navigation/Navigation'; import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { - // @TODO: Check if this method works the same as on the main branch Navigation.goBack(undefined, {shouldPopToTop: true}); Navigation.navigate(ROUTES.SETTINGS); Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); diff --git a/src/libs/navigateAfterJoinRequest/index.web.ts b/src/libs/navigateAfterJoinRequest/index.web.ts index 9b72ee30de57..d63fcb25aaf7 100644 --- a/src/libs/navigateAfterJoinRequest/index.web.ts +++ b/src/libs/navigateAfterJoinRequest/index.web.ts @@ -3,7 +3,6 @@ import Navigation from '@navigation/Navigation'; import ROUTES from '@src/ROUTES'; const navigateAfterJoinRequest = () => { - // @TODO: Check if this method works the same as on the main branch Navigation.goBack(undefined, {shouldPopToTop: true}); if (getIsSmallScreenWidth()) { Navigation.navigate(ROUTES.SETTINGS); diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index 116c360abfc4..ea8d3c257600 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -11,7 +11,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; +import {isSearchTopmostFullScreenRoute} from '@libs/Navigation/helpers'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {EditRequestNavigatorParamList} from '@libs/Navigation/types'; diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index d0b25a59c89f..705765f47146 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -2,6 +2,8 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import BottomTabBar, {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; +import TopBar from '@components/Navigation/TopBar'; import ScreenWrapper from '@components/ScreenWrapper'; import Search from '@components/Search'; import {useSearchContext} from '@components/Search/SearchContext'; @@ -11,8 +13,6 @@ import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; -import BottomTabBar, {BOTTOM_TABS} from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; -import TopBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar'; import FreezeWrapper from '@libs/Navigation/AppNavigator/FreezeWrapper'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; @@ -20,10 +20,10 @@ import type {AuthScreensParamList} from '@libs/Navigation/types'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import SearchPageBottomTab from './SearchPageBottomTab'; +import SearchPageNarrow from './SearchPageNarrow'; import SearchTypeMenu from './SearchTypeMenu'; -type SearchPageProps = PlatformStackScreenProps; +type SearchPageProps = PlatformStackScreenProps; function SearchPage({route}: SearchPageProps) { const {translate} = useLocalize(); @@ -49,7 +49,7 @@ function SearchPage({route}: SearchPageProps) { // To avoid calling hooks in the Search component when this page isn't visible, we return null here. if (shouldUseNarrowLayout) { return ( - - {/* {!selectionMode?.isEnabled && queryJSON ? ( */} {queryJSON ? ( @@ -97,7 +97,7 @@ function SearchPageBottomTab({queryJSON, policyID, searchName}: SearchPageBottom return ( } headerGapStyles={styles.searchHeaderGap} @@ -145,6 +145,6 @@ function SearchPageBottomTab({queryJSON, policyID, searchName}: SearchPageBottom ); } -SearchPageBottomTab.displayName = 'SearchPageBottomTab'; +SearchPageNarrow.displayName = 'SearchPageNarrow'; -export default SearchPageBottomTab; +export default SearchPageNarrow; diff --git a/src/pages/TransactionReceiptPage.tsx b/src/pages/TransactionReceiptPage.tsx index 497adef4ec1e..6ac0e87094c4 100644 --- a/src/pages/TransactionReceiptPage.tsx +++ b/src/pages/TransactionReceiptPage.tsx @@ -3,7 +3,7 @@ import {useOnyx} from 'react-native-onyx'; import AttachmentModal from '@components/AttachmentModal'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; -import type {AuthScreensParamList, RootStackParamList, State} from '@libs/Navigation/types'; +import type {AuthScreensParamList, RootNavigatorParamList, State} from '@libs/Navigation/types'; import * as ReceiptUtils from '@libs/ReceiptUtils'; import * as ReportActionUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -47,7 +47,7 @@ function TransactionReceipt({route}: TransactionReceiptProps) { const onModalClose = () => { // Receipt Page can be opened either from Reports or from Search RHP view // We have to handle going back to correct screens, if it was opened from RHP just close the modal, otherwise go to Report Page - const rootState = navigationRef.getRootState() as State; + const rootState = navigationRef.getRootState() as State; const secondToLastRoute = rootState.routes.at(-2); if (secondToLastRoute?.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR) { Navigation.dismissModal(); diff --git a/src/pages/WorkspaceSwitcherPage/index.tsx b/src/pages/WorkspaceSwitcherPage/index.tsx index 05986f436430..eec02a1c0ea8 100644 --- a/src/pages/WorkspaceSwitcherPage/index.tsx +++ b/src/pages/WorkspaceSwitcherPage/index.tsx @@ -17,8 +17,8 @@ import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import {sortWorkspacesBySelected} from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import type {BrickRoad} from '@libs/WorkspacesSettingsUtils'; import {getWorkspacesBrickRoads, getWorkspacesUnreadStatuses} from '@libs/WorkspacesSettingsUtils'; +import type {BrickRoad} from '@libs/WorkspacesSettingsUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index d1ea72362b82..06f049285749 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -599,7 +599,6 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro Navigation.dismissModal(); if (Navigation.getTopmostReportId() === prevOnyxReportID) { Navigation.setShouldPopAllStateOnUP(true); - // @TODO: Check if this method works the same as on the main branch Navigation.goBack(undefined, {shouldPopToTop: true}); } if (prevReport?.parentReportID) { diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx index c4e87cf93fe3..3689c9932e34 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx @@ -2,6 +2,8 @@ import {useRoute} from '@react-navigation/native'; import React, {useEffect} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; +import BottomTabBar, {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; +import TopBar from '@components/Navigation/TopBar'; import ScreenWrapper from '@components/ScreenWrapper'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; @@ -9,8 +11,6 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import {updateLastAccessedWorkspace} from '@libs/actions/Policy/Policy'; import * as Browser from '@libs/Browser'; -import BottomTabBar, {BOTTOM_TABS} from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; -import TopBar from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar'; import getInitialSplitNavigatorState from '@libs/Navigation/AppNavigator/createSplitNavigator/getInitialSplitNavigatorState'; import {getPreservedSplitNavigatorState} from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; import navigationRef from '@libs/Navigation/navigationRef'; diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 9e87b7758bd1..b2974419b44d 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -5,16 +5,15 @@ import type {GestureResponderEvent, ScrollView as RNScrollView, ScrollViewProps, import {NativeModules, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; -// eslint-disable-next-line no-restricted-imports import AccountSwitcher from '@components/AccountSwitcher'; import AccountSwitcherSkeletonView from '@components/AccountSwitcherSkeletonView'; -// eslint-disable-next-line no-restricted-imports import ConfirmModal from '@components/ConfirmModal'; import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import {InitialURLContext} from '@components/InitialURLContextProvider'; import MenuItem from '@components/MenuItem'; +import BottomTabBar, {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; import {PressableWithFeedback} from '@components/Pressable'; import ScreenWrapper from '@components/ScreenWrapper'; import {ScrollOffsetContext} from '@components/ScrollOffsetContextProvider'; @@ -32,7 +31,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import {resetExitSurveyForm} from '@libs/actions/ExitSurvey'; import * as CurrencyUtils from '@libs/CurrencyUtils'; -import BottomTabBar, {BOTTOM_TABS} from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import getTopmostRouteName from '@libs/Navigation/helpers/getTopmostRouteName'; import Navigation from '@libs/Navigation/Navigation'; import * as SubscriptionUtils from '@libs/SubscriptionUtils'; diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 402d5b05b56e..014187c0f4c5 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -9,6 +9,7 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import HighlightableMenuItem from '@components/HighlightableMenuItem'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; +import BottomTabBar, {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; @@ -23,7 +24,6 @@ import useWaitForNavigation from '@hooks/useWaitForNavigation'; import {isConnectionInProgress} from '@libs/actions/connections'; import * as CardUtils from '@libs/CardUtils'; import * as CurrencyUtils from '@libs/CurrencyUtils'; -import BottomTabBar, {BOTTOM_TABS} from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import getTopmostRouteName from '@libs/Navigation/helpers/getTopmostRouteName'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.tsx b/src/pages/workspace/WorkspaceInviteMessagePage.tsx index 1053d0482f84..ad288cbfb9ca 100644 --- a/src/pages/workspace/WorkspaceInviteMessagePage.tsx +++ b/src/pages/workspace/WorkspaceInviteMessagePage.tsx @@ -92,7 +92,6 @@ function WorkspaceInviteMessagePage({policy, route, currentUserPersonalDetails}: if (isEmptyObject(policy)) { return; } - // @TODO: Check if this method works the same as on the main branch Navigation.goBack(ROUTES.WORKSPACE_INVITE.getRoute(route.params.policyID, route.params.backTo)); // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, [isOnyxLoading]); diff --git a/src/pages/workspace/WorkspaceJoinUserPage.tsx b/src/pages/workspace/WorkspaceJoinUserPage.tsx index 66caff7263ef..f1febd9b057e 100644 --- a/src/pages/workspace/WorkspaceJoinUserPage.tsx +++ b/src/pages/workspace/WorkspaceJoinUserPage.tsx @@ -45,8 +45,6 @@ function WorkspaceJoinUserPage({route, policy}: WorkspaceJoinUserPageProps) { } if (!isEmptyObject(policy) && !policy?.isJoinRequestPending && !PolicyUtils.isPendingDeletePolicy(policy)) { Navigation.isNavigationReady().then(() => { - // @TODO: Check if this method works the same as on the main branch - // NOTE: It probably doesn't need any params. When this method is called, shouldPopAllStateOnUP is always false Navigation.goBack(undefined, {shouldPopToTop: true}); Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID ?? '-1')); }); diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index cbd843f3d34d..54ff03141936 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -12,6 +12,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; import LottieAnimations from '@components/LottieAnimations'; import type {MenuItemProps} from '@components/MenuItem'; +import BottomTabBar, {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; import type {OfflineWithFeedbackProps} from '@components/OfflineWithFeedback'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import type {PopoverMenuItem} from '@components/PopoverMenu'; @@ -28,7 +29,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {isConnectionInProgress} from '@libs/actions/connections'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import localeCompare from '@libs/LocaleCompare'; -import BottomTabBar, {BOTTOM_TABS} from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; diff --git a/src/types/modules/react-navigation.d.ts b/src/types/modules/react-navigation.d.ts index f6a47f3cdb9a..b222bb1892c2 100644 --- a/src/types/modules/react-navigation.d.ts +++ b/src/types/modules/react-navigation.d.ts @@ -1,8 +1,8 @@ -import type {RootStackParamList} from '@libs/Navigation/types'; +import type {RootNavigatorParamList} from '@libs/Navigation/types'; declare global { namespace ReactNavigation { // eslint-disable-next-line - interface RootParamList extends RootStackParamList {} + interface RootParamList extends RootNavigatorParamList {} } } diff --git a/tests/ui/WorkspaceCategoriesTest.tsx b/tests/ui/WorkspaceCategoriesTest.tsx index eca2f803f70e..f35920c2aa51 100644 --- a/tests/ui/WorkspaceCategoriesTest.tsx +++ b/tests/ui/WorkspaceCategoriesTest.tsx @@ -10,8 +10,8 @@ import {CurrentReportIDContextProvider} from '@components/withCurrentReportID'; import * as useResponsiveLayoutModule from '@hooks/useResponsiveLayout'; import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; import * as Localize from '@libs/Localize'; -import createResponsiveStackNavigator from '@navigation/AppNavigator/createResponsiveStackNavigator'; -import type {FullScreenNavigatorParamList} from '@navigation/types'; +import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; +import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; import WorkspaceCategoriesPage from '@pages/workspace/categories/WorkspaceCategoriesPage'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -22,20 +22,20 @@ import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct' TestHelper.setupGlobalFetchMock(); -const RootStack = createResponsiveStackNavigator(); +const Split = createSplitNavigator(); -const renderPage = (initialRouteName: typeof SCREENS.WORKSPACE.CATEGORIES, initialParams: FullScreenNavigatorParamList[typeof SCREENS.WORKSPACE.CATEGORIES]) => { +const renderPage = (initialRouteName: typeof SCREENS.WORKSPACE.CATEGORIES, initialParams: WorkspaceSplitNavigatorParamList[typeof SCREENS.WORKSPACE.CATEGORIES]) => { return render( - - + - + , diff --git a/tests/ui/WorkspaceUpgradeTest.tsx b/tests/ui/WorkspaceUpgradeTest.tsx index 456ca3f737c8..2f2b707e1413 100644 --- a/tests/ui/WorkspaceUpgradeTest.tsx +++ b/tests/ui/WorkspaceUpgradeTest.tsx @@ -4,8 +4,8 @@ import {act, fireEvent, render, screen} from '@testing-library/react-native'; import React from 'react'; import Onyx from 'react-native-onyx'; import {WRITE_COMMANDS} from '@libs/API/types'; +import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator'; import * as SequentialQueue from '@libs/Network/SequentialQueue'; -import createResponsiveStackNavigator from '@navigation/AppNavigator/createResponsiveStackNavigator'; import type {SettingsNavigatorParamList} from '@navigation/types'; import WorkspaceUpgradePage from '@pages/workspace/upgrade/WorkspaceUpgradePage'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -18,18 +18,18 @@ import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct' TestHelper.setupGlobalFetchMock(); -const RootStack = createResponsiveStackNavigator(); +const Stack = createPlatformStackNavigator(); const renderPage = (initialRouteName: typeof SCREENS.WORKSPACE.UPGRADE, initialParams: SettingsNavigatorParamList[typeof SCREENS.WORKSPACE.UPGRADE]) => { return render( - - + - + , ); }; From 94f9dfb0ae11ae347e0043136688ed69990d1f6a Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Thu, 9 Jan 2025 15:54:46 +0100 Subject: [PATCH 237/257] remove index file for helpers --- .../ActiveWorkspaceProvider/index.tsx | 2 +- .../DeeplinkWrapper/index.website.tsx | 2 +- .../FocusTrapForScreen/index.web.tsx | 2 +- .../MentionReportRenderer/index.tsx | 2 +- src/components/Navigation/BottomTabBar.tsx | 2 +- src/components/PromotedActionsBar.tsx | 2 +- .../ScrollOffsetContextProvider.tsx | 2 +- .../SearchRouter/SearchRouterContext.tsx | 2 +- src/components/Search/index.tsx | 2 +- .../Navigation/AppNavigator/AuthScreens.tsx | 2 +- .../getIsScreenBlurred/index.native.ts | 2 +- .../FreezeWrapper/getIsScreenBlurred/index.ts | 2 +- .../RootStackRouter.ts | 3 ++- .../TopLevelBottomTabBar.tsx | 2 +- .../createRootStackNavigator/index.tsx | 2 +- .../createSplitNavigator/SplitRouter.ts | 2 +- src/libs/Navigation/Navigation.ts | 18 ++++++------- src/libs/Navigation/NavigationRoot.tsx | 4 ++- src/libs/Navigation/helpers/index.ts | 26 ------------------- src/libs/Navigation/linkingConfig/config.ts | 4 +-- src/libs/Navigation/linkingConfig/index.ts | 2 +- src/libs/actions/IOU.ts | 1 + src/libs/actions/Report.ts | 2 +- src/libs/actions/Welcome/OnboardingFlow.ts | 2 +- src/libs/navigateAfterOnboarding.ts | 2 +- src/pages/AddPersonalBankAccountPage.tsx | 2 +- src/pages/EditReportFieldPage.tsx | 2 +- src/pages/home/report/ReportActionsList.tsx | 3 ++- 28 files changed, 39 insertions(+), 62 deletions(-) delete mode 100644 src/libs/Navigation/helpers/index.ts diff --git a/src/components/ActiveWorkspaceProvider/index.tsx b/src/components/ActiveWorkspaceProvider/index.tsx index 07d414f47ba3..e34e8091c0f7 100644 --- a/src/components/ActiveWorkspaceProvider/index.tsx +++ b/src/components/ActiveWorkspaceProvider/index.tsx @@ -1,7 +1,7 @@ import {useNavigationState} from '@react-navigation/native'; import React, {useEffect, useMemo, useState} from 'react'; import ActiveWorkspaceContext from '@components/ActiveWorkspace/ActiveWorkspaceContext'; -import {getPolicyIDFromState} from '@libs/Navigation/helpers'; +import getPolicyIDFromState from '@libs/Navigation/helpers/getPolicyIDFromState'; import type {RootNavigatorParamList, State} from '@libs/Navigation/types'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; diff --git a/src/components/DeeplinkWrapper/index.website.tsx b/src/components/DeeplinkWrapper/index.website.tsx index 9848902a817f..2f5bbd29e58e 100644 --- a/src/components/DeeplinkWrapper/index.website.tsx +++ b/src/components/DeeplinkWrapper/index.website.tsx @@ -1,7 +1,7 @@ import {Str} from 'expensify-common'; import {useEffect, useRef, useState} from 'react'; import * as Browser from '@libs/Browser'; -import {shouldPreventDeeplinkPrompt} from '@libs/Navigation/helpers'; +import shouldPreventDeeplinkPrompt from '@libs/Navigation/helpers/shouldPreventDeeplinkPrompt'; import Navigation from '@libs/Navigation/Navigation'; import navigationRef from '@libs/Navigation/navigationRef'; import * as App from '@userActions/App'; diff --git a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx index f6e08e3e505f..21d5991c8005 100644 --- a/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx +++ b/src/components/FocusTrap/FocusTrapForScreen/index.web.tsx @@ -5,7 +5,7 @@ import sharedTrapStack from '@components/FocusTrap/sharedTrapStack'; import TOP_TAB_SCREENS from '@components/FocusTrap/TOP_TAB_SCREENS'; import WIDE_LAYOUT_INACTIVE_SCREENS from '@components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import {isSidebarScreenName} from '@libs/Navigation/helpers'; +import {isSidebarScreenName} from '@libs/Navigation/helpers/isNavigatorName'; import CONST from '@src/CONST'; import type FocusTrapProps from './FocusTrapProps'; diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx index e1bfdd29d791..7dd36d372d96 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionReportRenderer/index.tsx @@ -10,7 +10,7 @@ import Text from '@components/Text'; import useCurrentReportID from '@hooks/useCurrentReportID'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; -import {isSearchTopmostFullScreenRoute} from '@libs/Navigation/helpers'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation from '@navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/components/Navigation/BottomTabBar.tsx b/src/components/Navigation/BottomTabBar.tsx index 1b4be6bbae7f..59e0cefa4bae 100644 --- a/src/components/Navigation/BottomTabBar.tsx +++ b/src/components/Navigation/BottomTabBar.tsx @@ -19,7 +19,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import getPlatform from '@libs/getPlatform'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import {getPreservedSplitNavigatorState} from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; -import {isFullScreenName} from '@libs/Navigation/helpers'; +import {isFullScreenName} from '@libs/Navigation/helpers/isNavigatorName'; import Navigation from '@libs/Navigation/Navigation'; import type {AuthScreensParamList, RootNavigatorParamList, State, WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; diff --git a/src/components/PromotedActionsBar.tsx b/src/components/PromotedActionsBar.tsx index 1102b99ba0dc..be4c734608c7 100644 --- a/src/components/PromotedActionsBar.tsx +++ b/src/components/PromotedActionsBar.tsx @@ -5,7 +5,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as HeaderUtils from '@libs/HeaderUtils'; import * as Localize from '@libs/Localize'; -import {isSearchTopmostFullScreenRoute} from '@libs/Navigation/helpers'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as ReportActions from '@userActions/Report'; diff --git a/src/components/ScrollOffsetContextProvider.tsx b/src/components/ScrollOffsetContextProvider.tsx index 9620da9e72e5..26e1da6c8e72 100644 --- a/src/components/ScrollOffsetContextProvider.tsx +++ b/src/components/ScrollOffsetContextProvider.tsx @@ -2,7 +2,7 @@ import type {ParamListBase} from '@react-navigation/native'; import React, {createContext, useCallback, useEffect, useMemo, useRef} from 'react'; import {withOnyx} from 'react-native-onyx'; import usePrevious from '@hooks/usePrevious'; -import {isSidebarScreenName} from '@libs/Navigation/helpers'; +import {isSidebarScreenName} from '@libs/Navigation/helpers/isNavigatorName'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {NavigationPartialRoute, State} from '@libs/Navigation/types'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/components/Search/SearchRouter/SearchRouterContext.tsx b/src/components/Search/SearchRouter/SearchRouterContext.tsx index e9015d4080d3..947dcc9c48c5 100644 --- a/src/components/Search/SearchRouter/SearchRouterContext.tsx +++ b/src/components/Search/SearchRouter/SearchRouterContext.tsx @@ -1,6 +1,6 @@ import React, {useContext, useMemo, useRef, useState} from 'react'; import type {AnimatedTextInputRef} from '@components/RNTextInput'; -import {isSearchTopmostFullScreenRoute} from '@libs/Navigation/helpers'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import * as Modal from '@userActions/Modal'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 4fc8f41aa53d..8d78211aa747 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -19,7 +19,7 @@ import * as SearchActions from '@libs/actions/Search'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Log from '@libs/Log'; import memoize from '@libs/memoize'; -import {isSearchTopmostFullScreenRoute} from '@libs/Navigation/helpers'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types'; import * as ReportUtils from '@libs/ReportUtils'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index e34d6b7f6a61..3cbba313dfcc 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -23,7 +23,7 @@ import KeyboardShortcut from '@libs/KeyboardShortcut'; import Log from '@libs/Log'; import NavBarManager from '@libs/NavBarManager'; import getCurrentUrl from '@libs/Navigation/currentUrl'; -import {isOnboardingFlowName} from '@libs/Navigation/helpers'; +import {isOnboardingFlowName} from '@libs/Navigation/helpers/isNavigatorName'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation'; import Presentation from '@libs/Navigation/PlatformStackNavigation/navigationOptions/presentation'; diff --git a/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.native.ts b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.native.ts index 4cc3caa86cdb..482cd7f29bb5 100644 --- a/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.native.ts +++ b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.native.ts @@ -1,5 +1,5 @@ import type {NavigationState} from '@react-navigation/native'; -import {isFullScreenName} from '@libs/Navigation/helpers'; +import {isFullScreenName} from '@libs/Navigation/helpers/isNavigatorName'; function getIsScreenBlurred(state: NavigationState, currentRouteKey: string) { // If the screen is one of the last two fullscreen routes in the stack, it is not freezed on native platforms. diff --git a/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.ts b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.ts index 4ad2ea2c9aa5..0b51e817a0ba 100644 --- a/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.ts +++ b/src/libs/Navigation/AppNavigator/FreezeWrapper/getIsScreenBlurred/index.ts @@ -1,5 +1,5 @@ import type {NavigationState} from '@react-navigation/native'; -import {isFullScreenName} from '@libs/Navigation/helpers'; +import {isFullScreenName} from '@libs/Navigation/helpers/isNavigatorName'; function getIsScreenBlurred(state: NavigationState, currentRouteKey: string) { const lastFullScreenRoute = state.routes.findLast((route) => isFullScreenName(route.name)); diff --git a/src/libs/Navigation/AppNavigator/createRootStackNavigator/RootStackRouter.ts b/src/libs/Navigation/AppNavigator/createRootStackNavigator/RootStackRouter.ts index ea5160a2862b..6443ceca025e 100644 --- a/src/libs/Navigation/AppNavigator/createRootStackNavigator/RootStackRouter.ts +++ b/src/libs/Navigation/AppNavigator/createRootStackNavigator/RootStackRouter.ts @@ -3,7 +3,8 @@ import {findFocusedRoute, StackRouter} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/routers'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import * as Localize from '@libs/Localize'; -import {isOnboardingFlowName, isSideModalNavigator} from '@libs/Navigation/helpers'; +import {isOnboardingFlowName} from '@libs/Navigation/helpers/isNavigatorName'; +import isSideModalNavigator from '@libs/Navigation/helpers/isSideModalNavigator'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; diff --git a/src/libs/Navigation/AppNavigator/createRootStackNavigator/TopLevelBottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createRootStackNavigator/TopLevelBottomTabBar.tsx index 9c24f145790a..61ea46715158 100644 --- a/src/libs/Navigation/AppNavigator/createRootStackNavigator/TopLevelBottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createRootStackNavigator/TopLevelBottomTabBar.tsx @@ -5,7 +5,7 @@ import BottomTabBar from '@components/Navigation/BottomTabBar'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyledSafeAreaInsets from '@hooks/useStyledSafeAreaInsets'; import useThemeStyles from '@hooks/useThemeStyles'; -import {isFullScreenName} from '@libs/Navigation/helpers'; +import {isFullScreenName} from '@libs/Navigation/helpers/isNavigatorName'; import {FULLSCREEN_TO_TAB, SIDEBAR_TO_SPLIT} from '@libs/Navigation/linkingConfig/RELATIONS'; import type {FullScreenName} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; diff --git a/src/libs/Navigation/AppNavigator/createRootStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createRootStackNavigator/index.tsx index e71f1d9c5264..d7d0b0a88744 100644 --- a/src/libs/Navigation/AppNavigator/createRootStackNavigator/index.tsx +++ b/src/libs/Navigation/AppNavigator/createRootStackNavigator/index.tsx @@ -1,7 +1,7 @@ import {createNavigatorFactory} from '@react-navigation/native'; import type {ParamListBase} from '@react-navigation/native'; import useNavigationResetOnLayoutChange from '@libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange'; -import {isFullScreenName} from '@libs/Navigation/helpers'; +import {isFullScreenName} from '@libs/Navigation/helpers/isNavigatorName'; import createPlatformStackNavigatorComponent from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent'; import defaultPlatformStackScreenOptions from '@libs/Navigation/PlatformStackNavigation/defaultPlatformStackScreenOptions'; import type {CustomStateHookProps, PlatformStackNavigationEventMap, PlatformStackNavigationOptions, PlatformStackNavigationState} from '@libs/Navigation/PlatformStackNavigation/types'; diff --git a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts index e8c0960bb2c5..3e0755635a14 100644 --- a/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitNavigator/SplitRouter.ts @@ -3,7 +3,7 @@ import {StackActions, StackRouter} from '@react-navigation/native'; import isEmpty from 'lodash/isEmpty'; import pick from 'lodash/pick'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import {getParamsFromRoute} from '@libs/Navigation/helpers'; +import getParamsFromRoute from '@libs/Navigation/helpers/getParamsFromRoute'; import navigationRef from '@libs/Navigation/navigationRef'; import type {NavigationPartialRoute} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index c7d2096452e4..5d8a0d925d02 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -20,16 +20,14 @@ import SCREENS, {PROTECTED_SCREENS} from '@src/SCREENS'; import type {Report} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import getInitialSplitNavigatorState from './AppNavigator/createSplitNavigator/getInitialSplitNavigatorState'; -import { - getMinimalAction, - getPolicyIDFromState, - getStateFromPath, - getTopmostReportParams, - isReportOpenInRHP, - linkTo, - closeRHPFlow as originalCloseRHPFlow, - setNavigationActionToMicrotaskQueue, -} from './helpers'; +import originalCloseRHPFlow from './helpers/closeRHPFlow'; +import getPolicyIDFromState from './helpers/getPolicyIDFromState'; +import getStateFromPath from './helpers/getStateFromPath'; +import getTopmostReportParams from './helpers/getTopmostReportParams'; +import isReportOpenInRHP from './helpers/isReportOpenInRHP'; +import linkTo from './helpers/linkTo'; +import getMinimalAction from './helpers/linkTo/getMinimalAction'; +import setNavigationActionToMicrotaskQueue from './helpers/setNavigationActionToMicrotaskQueue'; import linkingConfig from './linkingConfig'; import navigationRef from './navigationRef'; import type {NavigationPartialRoute, NavigationStateRoute, RootNavigatorParamList, State} from './types'; diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 7d716630a872..eaaed1e121dd 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -24,7 +24,9 @@ import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import AppNavigator from './AppNavigator'; import {cleanPreservedSplitNavigatorStates} from './AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; -import {customGetPathFromState, getAdaptedStateFromPath, setupCustomAndroidBackHandler} from './helpers'; +import customGetPathFromState from './helpers/customGetPathFromState'; +import getAdaptedStateFromPath from './helpers/getAdaptedStateFromPath'; +import setupCustomAndroidBackHandler from './helpers/setupCustomAndroidBackHandler'; import linkingConfig from './linkingConfig'; import Navigation, {navigationRef} from './Navigation'; diff --git a/src/libs/Navigation/helpers/index.ts b/src/libs/Navigation/helpers/index.ts deleted file mode 100644 index 85f8779031e3..000000000000 --- a/src/libs/Navigation/helpers/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -export * from './createNormalizedConfigs'; -export * from './isNavigatorName'; -export * from './linkTo/types'; -export {default as closeRHPFlow} from './closeRHPFlow'; -export {default as createNormalizedConfigs} from './createNormalizedConfigs'; -export {default as customGetPathFromState} from './customGetPathFromState'; -export {default as extractPolicyIDFromQuery} from './extractPolicyIDFromQuery'; -export {default as getAdaptedStateFromPath} from './getAdaptedStateFromPath'; -export {default as getOnboardingAdaptedState} from './getOnboardingAdaptedState'; -export {default as getParamsFromRoute} from './getParamsFromRoute'; -export {default as getPolicyIDFromState} from './getPolicyIDFromState'; -export {default as getStateFromPath} from './getStateFromPath'; -export {default as getTopmostReportParams} from './getTopmostReportParams'; -export {default as getTopmostRouteName} from './getTopmostRouteName'; -export {default as isReportOpenInRHP} from './isReportOpenInRHP'; -export {default as isSearchTopmostFullScreenRoute} from './isSearchTopmostFullScreenRoute'; -export {default as isReportTopmostSplitNavigator} from './isReportTopmostSplitNavigator'; -export {default as isSideModalNavigator} from './isSideModalNavigator'; -export {default as linkTo} from './linkTo'; -export {default as getMinimalAction} from './linkTo/getMinimalAction'; -export {default as normalizePath} from './normalizePath'; -export {default as replacePathInNestedState} from './replacePathInNestedState'; -export {default as setNavigationActionToMicrotaskQueue} from './setNavigationActionToMicrotaskQueue'; -export {default as setupCustomAndroidBackHandler} from './setupCustomAndroidBackHandler'; -export {default as shouldOpenOnAdminRoom} from './shouldOpenOnAdminRoom'; -export {default as shouldPreventDeeplinkPrompt} from './shouldPreventDeeplinkPrompt'; diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index b9823b0cda76..fe6ae9e9d721 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1,6 +1,6 @@ import type {LinkingOptions} from '@react-navigation/native'; -import {createNormalizedConfigs} from '@libs/Navigation/helpers'; -import type {RouteConfig} from '@libs/Navigation/helpers'; +import type {RouteConfig} from '@libs/Navigation/helpers/createNormalizedConfigs'; +import createNormalizedConfigs from '@libs/Navigation/helpers/createNormalizedConfigs'; import type {RootNavigatorParamList} from '@navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import ROUTES from '@src/ROUTES'; diff --git a/src/libs/Navigation/linkingConfig/index.ts b/src/libs/Navigation/linkingConfig/index.ts index b09b24852d9d..c07b42d1870c 100644 --- a/src/libs/Navigation/linkingConfig/index.ts +++ b/src/libs/Navigation/linkingConfig/index.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ import type {LinkingOptions} from '@react-navigation/native'; -import {customGetPathFromState} from '@libs/Navigation/helpers'; +import customGetPathFromState from '@libs/Navigation/helpers/customGetPathFromState'; import getAdaptedStateFromPath from '@libs/Navigation/helpers/getAdaptedStateFromPath'; import type {RootNavigatorParamList} from '@navigation/types'; import config from './config'; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f19994f44629..1c67a9370d39 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -40,6 +40,7 @@ import * as IOUUtils from '@libs/IOUUtils'; import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; import * as Localize from '@libs/Localize'; import Log from '@libs/Log'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import * as NextStepUtils from '@libs/NextStepUtils'; import {rand64} from '@libs/NumberUtils'; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index be7d477bf92c..4282486698f4 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -67,7 +67,7 @@ import isPublicScreenRoute from '@libs/isPublicScreenRoute'; import * as Localize from '@libs/Localize'; import Log from '@libs/Log'; import {registerPaginationConfig} from '@libs/Middleware/Pagination'; -import {isOnboardingFlowName} from '@libs/Navigation/helpers'; +import {isOnboardingFlowName} from '@libs/Navigation/helpers/isNavigatorName'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import enhanceParameters from '@libs/Network/enhanceParameters'; import type {NetworkStatus} from '@libs/NetworkConnection'; diff --git a/src/libs/actions/Welcome/OnboardingFlow.ts b/src/libs/actions/Welcome/OnboardingFlow.ts index cee6fde235ba..e76702b2363a 100644 --- a/src/libs/actions/Welcome/OnboardingFlow.ts +++ b/src/libs/actions/Welcome/OnboardingFlow.ts @@ -1,7 +1,7 @@ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import type {NavigationState, PartialState} from '@react-navigation/native'; import Onyx from 'react-native-onyx'; -import {getAdaptedStateFromPath} from '@libs/Navigation/helpers'; +import getAdaptedStateFromPath from '@libs/Navigation/helpers/getAdaptedStateFromPath'; import linkingConfig from '@libs/Navigation/linkingConfig'; import {navigationRef} from '@libs/Navigation/Navigation'; import type {RootNavigatorParamList} from '@libs/Navigation/types'; diff --git a/src/libs/navigateAfterOnboarding.ts b/src/libs/navigateAfterOnboarding.ts index a5fc2cc3cfb5..b7adc48b39d6 100644 --- a/src/libs/navigateAfterOnboarding.ts +++ b/src/libs/navigateAfterOnboarding.ts @@ -1,5 +1,5 @@ import ROUTES from '@src/ROUTES'; -import {shouldOpenOnAdminRoom} from './Navigation/helpers'; +import shouldOpenOnAdminRoom from './Navigation/helpers/shouldOpenOnAdminRoom'; import Navigation from './Navigation/Navigation'; import * as ReportUtils from './ReportUtils'; diff --git a/src/pages/AddPersonalBankAccountPage.tsx b/src/pages/AddPersonalBankAccountPage.tsx index 05e8606c9dd7..f267592a49fa 100644 --- a/src/pages/AddPersonalBankAccountPage.tsx +++ b/src/pages/AddPersonalBankAccountPage.tsx @@ -11,7 +11,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import getPlaidOAuthReceivedRedirectURI from '@libs/getPlaidOAuthReceivedRedirectURI'; -import {isFullScreenName} from '@libs/Navigation/helpers'; +import {isFullScreenName} from '@libs/Navigation/helpers/isNavigatorName'; import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; import * as BankAccounts from '@userActions/BankAccounts'; import * as PaymentMethods from '@userActions/PaymentMethods'; diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index ea8d3c257600..116c360abfc4 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -11,7 +11,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import {isSearchTopmostFullScreenRoute} from '@libs/Navigation/helpers'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {EditRequestNavigatorParamList} from '@libs/Navigation/types'; diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx index f5af104c5651..6d97250b381e 100644 --- a/src/pages/home/report/ReportActionsList.tsx +++ b/src/pages/home/report/ReportActionsList.tsx @@ -19,7 +19,8 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import DateUtils from '@libs/DateUtils'; -import {isReportTopmostSplitNavigator, isSearchTopmostFullScreenRoute} from '@libs/Navigation/helpers'; +import isReportTopmostSplitNavigator from '@libs/Navigation/helpers/isReportTopmostSplitNavigator'; +import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; From 1b323640332492c9103db329c398fada89318f20 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 9 Jan 2025 16:35:47 +0100 Subject: [PATCH 238/257] Fix navigating to workspaces list using settings tab button --- .../BottomTabBar.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index e3c716e40fbf..4bb975df411b 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -169,9 +169,16 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { (rootRoute) => rootRoute.name === NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR || rootRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, ); + // If there is no settings or workspace navigator route, then we should open the settings navigator. + if (!lastSettingsOrWorkspaceNavigatorRoute) { + Navigation.navigate(ROUTES.SETTINGS); + return; + } + + const state = lastSettingsOrWorkspaceNavigatorRoute.state ?? getPreservedSplitNavigatorState(lastSettingsOrWorkspaceNavigatorRoute.key); + // If there is a workspace navigator route, then we should open the workspace initial screen as it should be "remembered". - if (lastSettingsOrWorkspaceNavigatorRoute?.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - const state = lastSettingsOrWorkspaceNavigatorRoute.state ?? getPreservedSplitNavigatorState(lastSettingsOrWorkspaceNavigatorRoute.key); + if (lastSettingsOrWorkspaceNavigatorRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { const params = state?.routes.at(0)?.params as WorkspaceSplitNavigatorParamList[typeof SCREENS.WORKSPACE.INITIAL]; // Screens of this navigator should always have policyID @@ -188,17 +195,12 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) { } // If there is settings workspace screen in the settings navigator, then we should open the settings workspaces as it should be "remembered". - if ( - lastSettingsOrWorkspaceNavigatorRoute && - lastSettingsOrWorkspaceNavigatorRoute.state && - lastSettingsOrWorkspaceNavigatorRoute.state.routes.at(-1)?.name === SCREENS.SETTINGS.WORKSPACES - ) { + if (state?.routes?.at(-1)?.name === SCREENS.SETTINGS.WORKSPACES) { Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); return; } // Otherwise we should simply open the settings navigator. - // This case also covers if there is no route to remember. Navigation.navigate(ROUTES.SETTINGS); }); }, [shouldUseNarrowLayout]); From 2d6951a03843d37c1893061ea266bcf8cd506fa4 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Thu, 9 Jan 2025 16:43:58 +0100 Subject: [PATCH 239/257] remove isSplitNavigatorName --- src/libs/Navigation/helpers/isNavigatorName.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/libs/Navigation/helpers/isNavigatorName.ts b/src/libs/Navigation/helpers/isNavigatorName.ts index 29e3e142f201..062cdb581735 100644 --- a/src/libs/Navigation/helpers/isNavigatorName.ts +++ b/src/libs/Navigation/helpers/isNavigatorName.ts @@ -1,5 +1,5 @@ import {SIDEBAR_TO_SPLIT, SPLIT_TO_SIDEBAR} from '@libs/Navigation/linkingConfig/RELATIONS'; -import type {FullScreenName, OnboardingFlowName, SplitNavigatorName, SplitNavigatorSidebarScreen} from '@libs/Navigation/types'; +import type {FullScreenName, OnboardingFlowName, SplitNavigatorSidebarScreen} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; const ONBOARDING_SCREENS = [ @@ -12,7 +12,6 @@ const ONBOARDING_SCREENS = [ SCREENS.ONBOARDING.WORKSPACES, ]; -const SPLIT_NAVIGATORS_SET = new Set(Object.values(SIDEBAR_TO_SPLIT)); const FULL_SCREENS_SET = new Set([...Object.values(SIDEBAR_TO_SPLIT), SCREENS.SEARCH.ROOT]); const SIDEBARS_SET = new Set(Object.values(SPLIT_TO_SIDEBAR)); const ONBOARDING_SCREENS_SET = new Set(ONBOARDING_SCREENS); @@ -33,10 +32,6 @@ function isOnboardingFlowName(screen: string | undefined) { return checkIfScreenHasMatchingNameToSetValues(screen, ONBOARDING_SCREENS_SET); } -function isSplitNavigatorName(screen: string | undefined) { - return checkIfScreenHasMatchingNameToSetValues(screen, SPLIT_NAVIGATORS_SET); -} - function isFullScreenName(screen: string | undefined) { return checkIfScreenHasMatchingNameToSetValues(screen, FULL_SCREENS_SET); } @@ -45,4 +40,4 @@ function isSidebarScreenName(screen: string | undefined) { return checkIfScreenHasMatchingNameToSetValues(screen, SIDEBARS_SET); } -export {isFullScreenName, isOnboardingFlowName, isSidebarScreenName, isSplitNavigatorName}; +export {isFullScreenName, isOnboardingFlowName, isSidebarScreenName}; From e575d1b2a33f6f323a66a69610d8721d579297db Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Thu, 9 Jan 2025 18:23:32 +0100 Subject: [PATCH 240/257] fix resetPolicyIDInNavigationState --- src/libs/Navigation/helpers/resetPolicyIDInNavigationState.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/helpers/resetPolicyIDInNavigationState.ts b/src/libs/Navigation/helpers/resetPolicyIDInNavigationState.ts index 99db40720c72..8a6235835e08 100644 --- a/src/libs/Navigation/helpers/resetPolicyIDInNavigationState.ts +++ b/src/libs/Navigation/helpers/resetPolicyIDInNavigationState.ts @@ -10,7 +10,7 @@ import SCREENS from '@src/SCREENS'; */ function resetPolicyIDInNavigationState() { const rootState = navigationRef.getRootState(); - const lastPolicyRoute = rootState?.routes?.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.CENTRAL_PANE); + const lastPolicyRoute = rootState?.routes?.findLast((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR || route.name === SCREENS.SEARCH.ROOT); if (!lastPolicyRoute) { return; @@ -21,7 +21,7 @@ function resetPolicyIDInNavigationState() { return; } - const {q, ...rest} = lastPolicyRoute.params as AuthScreensParamList[typeof SCREENS.SEARCH.CENTRAL_PANE]; + const {q, ...rest} = lastPolicyRoute.params as AuthScreensParamList[typeof SCREENS.SEARCH.ROOT]; const queryJSON = SearchQueryUtils.buildSearchQueryJSON(q); if (!queryJSON || !queryJSON.policyID) { return; From f4ef8755985fa847f3ac6d3b2b0ef518b0a272d9 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Thu, 9 Jan 2025 18:32:14 +0100 Subject: [PATCH 241/257] fix ts problems --- src/pages/Search/SearchTypeMenuNarrow.tsx | 2 +- src/pages/workspace/WorkspaceProfilePage.tsx | 2 +- tests/ui/ValidateLoginPageTest.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/Search/SearchTypeMenuNarrow.tsx b/src/pages/Search/SearchTypeMenuNarrow.tsx index 091120a98aae..80c810fb5879 100644 --- a/src/pages/Search/SearchTypeMenuNarrow.tsx +++ b/src/pages/Search/SearchTypeMenuNarrow.tsx @@ -83,7 +83,7 @@ function SearchTypeMenuNarrow({typeMenuItems, activeItemIndex, queryJSON, title, useEffect(() => { const listener = (event: EventArg<'state', false, NavigationContainerEventMap['state']['data']>) => { - if (Navigation.getRouteNameFromStateEvent(event) === SCREENS.SEARCH.CENTRAL_PANE) { + if (Navigation.getRouteNameFromStateEvent(event) === SCREENS.SEARCH.ROOT) { setIsScreenFocused(true); return; } diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index f1b4477ae9b5..dfc841b12919 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -20,7 +20,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeIllustrations from '@hooks/useThemeIllustrations'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; -import {resetPolicyIDInNavigationState} from '@libs/Navigation/helpers'; +import resetPolicyIDInNavigationState from '@libs/Navigation/helpers/resetPolicyIDInNavigationState'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; diff --git a/tests/ui/ValidateLoginPageTest.tsx b/tests/ui/ValidateLoginPageTest.tsx index 19a9a375d726..2a6f4ecfd2b9 100644 --- a/tests/ui/ValidateLoginPageTest.tsx +++ b/tests/ui/ValidateLoginPageTest.tsx @@ -2,14 +2,14 @@ import {NavigationContainer} from '@react-navigation/native'; import {render, screen} from '@testing-library/react-native'; import React from 'react'; import Onyx from 'react-native-onyx'; -import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator'; +import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator'; import type {PublicScreensParamList} from '@libs/Navigation/types'; import ValidateLoginPage from '@pages/ValidateLoginPage/index.website'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import SCREENS from '@src/SCREENS'; -const RootStack = createResponsiveStackNavigator(); +const RootStack = createPlatformStackNavigator(); const renderPage = (initialParams: PublicScreensParamList[typeof SCREENS.VALIDATE_LOGIN]) => { return render( From 3bc1739d1d03f6b0241bea5e3b673948f19dd971 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Fri, 10 Jan 2025 10:45:09 +0100 Subject: [PATCH 242/257] Split BOTTOM_TABS const to a separate file to fix imports --- .../Navigation/BottomTabBar/BOTTOM_TABS.ts | 7 +++++++ .../index.tsx} | 17 ++++++----------- .../RELATIONS/FULLSCREEN_TO_TAB.ts | 2 +- src/pages/Search/SearchPage.tsx | 3 ++- src/pages/Search/SearchPageNarrow.tsx | 3 ++- .../sidebar/SidebarScreen/BaseSidebarScreen.tsx | 3 ++- src/pages/settings/InitialSettingsPage.tsx | 3 ++- src/pages/workspace/WorkspaceInitialPage.tsx | 3 ++- src/pages/workspace/WorkspacesListPage.tsx | 3 ++- 9 files changed, 26 insertions(+), 18 deletions(-) create mode 100644 src/components/Navigation/BottomTabBar/BOTTOM_TABS.ts rename src/components/Navigation/{BottomTabBar.tsx => BottomTabBar/index.tsx} (96%) diff --git a/src/components/Navigation/BottomTabBar/BOTTOM_TABS.ts b/src/components/Navigation/BottomTabBar/BOTTOM_TABS.ts new file mode 100644 index 000000000000..96eeeb5e66ea --- /dev/null +++ b/src/components/Navigation/BottomTabBar/BOTTOM_TABS.ts @@ -0,0 +1,7 @@ +const BOTTOM_TABS = { + HOME: 'HOME', + SEARCH: 'SEARCH', + SETTINGS: 'SETTINGS', +} as const; + +export default BOTTOM_TABS; diff --git a/src/components/Navigation/BottomTabBar.tsx b/src/components/Navigation/BottomTabBar/index.tsx similarity index 96% rename from src/components/Navigation/BottomTabBar.tsx rename to src/components/Navigation/BottomTabBar/index.tsx index 2970f363caeb..df8f178c06c0 100644 --- a/src/components/Navigation/BottomTabBar.tsx +++ b/src/components/Navigation/BottomTabBar/index.tsx @@ -18,15 +18,15 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import getPlatform from '@libs/getPlatform'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; -import {getPreservedSplitNavigatorState} from '@libs/Navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; -import {isFullScreenName} from '@libs/Navigation/helpers/isNavigatorName'; -import Navigation from '@libs/Navigation/Navigation'; -import type {AuthScreensParamList, RootNavigatorParamList, State, WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; import type {BrickRoad} from '@libs/WorkspacesSettingsUtils'; import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils'; +import {getPreservedSplitNavigatorState} from '@navigation/AppNavigator/createSplitNavigator/usePreserveSplitNavigatorState'; +import {isFullScreenName} from '@navigation/helpers/isNavigatorName'; +import Navigation from '@navigation/Navigation'; import navigationRef from '@navigation/navigationRef'; +import type {AuthScreensParamList, RootNavigatorParamList, State, WorkspaceSplitNavigatorParamList} from '@navigation/types'; import BottomTabAvatar from '@pages/home/sidebar/BottomTabAvatar'; import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton'; import variables from '@styles/variables'; @@ -35,13 +35,8 @@ import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; -import DebugTabView from './DebugTabView'; - -const BOTTOM_TABS = { - HOME: 'HOME', - SEARCH: 'SEARCH', - SETTINGS: 'SETTINGS', -} as const; +import DebugTabView from '../DebugTabView'; +import BOTTOM_TABS from './BOTTOM_TABS'; type BottomTabName = ValueOf; diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/FULLSCREEN_TO_TAB.ts b/src/libs/Navigation/linkingConfig/RELATIONS/FULLSCREEN_TO_TAB.ts index 544eaa6f22fc..b567a35c1ab8 100644 --- a/src/libs/Navigation/linkingConfig/RELATIONS/FULLSCREEN_TO_TAB.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/FULLSCREEN_TO_TAB.ts @@ -1,5 +1,5 @@ import type {BottomTabName} from '@components/Navigation/BottomTabBar'; -import {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; +import BOTTOM_TABS from '@components/Navigation/BottomTabBar/BOTTOM_TABS'; import type {FullScreenName} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 705765f47146..041e66a4e332 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -2,7 +2,8 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import BottomTabBar, {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; +import BottomTabBar from '@components/Navigation/BottomTabBar'; +import BOTTOM_TABS from '@components/Navigation/BottomTabBar/BOTTOM_TABS'; import TopBar from '@components/Navigation/TopBar'; import ScreenWrapper from '@components/ScreenWrapper'; import Search from '@components/Search'; diff --git a/src/pages/Search/SearchPageNarrow.tsx b/src/pages/Search/SearchPageNarrow.tsx index dc150532c72e..e28b4fcf06aa 100644 --- a/src/pages/Search/SearchPageNarrow.tsx +++ b/src/pages/Search/SearchPageNarrow.tsx @@ -3,7 +3,8 @@ import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Animated, {clamp, useAnimatedScrollHandler, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; -import BottomTabBar, {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; +import BottomTabBar from '@components/Navigation/BottomTabBar'; +import BOTTOM_TABS from '@components/Navigation/BottomTabBar/BOTTOM_TABS'; import TopBar from '@components/Navigation/TopBar'; import ScreenWrapper from '@components/ScreenWrapper'; import Search from '@components/Search'; diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx index 3689c9932e34..c404a2fe8233 100644 --- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx +++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.tsx @@ -2,7 +2,8 @@ import {useRoute} from '@react-navigation/native'; import React, {useEffect} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; -import BottomTabBar, {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; +import BottomTabBar from '@components/Navigation/BottomTabBar'; +import BOTTOM_TABS from '@components/Navigation/BottomTabBar/BOTTOM_TABS'; import TopBar from '@components/Navigation/TopBar'; import ScreenWrapper from '@components/ScreenWrapper'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index b2974419b44d..af17dae59e2c 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -13,7 +13,8 @@ import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import {InitialURLContext} from '@components/InitialURLContextProvider'; import MenuItem from '@components/MenuItem'; -import BottomTabBar, {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; +import BottomTabBar from '@components/Navigation/BottomTabBar'; +import BOTTOM_TABS from '@components/Navigation/BottomTabBar/BOTTOM_TABS'; import {PressableWithFeedback} from '@components/Pressable'; import ScreenWrapper from '@components/ScreenWrapper'; import {ScrollOffsetContext} from '@components/ScrollOffsetContextProvider'; diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index 014187c0f4c5..8ad5caa738aa 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -9,7 +9,8 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import HighlightableMenuItem from '@components/HighlightableMenuItem'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; -import BottomTabBar, {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; +import BottomTabBar from '@components/Navigation/BottomTabBar'; +import BOTTOM_TABS from '@components/Navigation/BottomTabBar/BOTTOM_TABS'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index e675304270fc..9dcba6136645 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -12,7 +12,8 @@ import * as Expensicons from '@components/Icon/Expensicons'; import * as Illustrations from '@components/Icon/Illustrations'; import LottieAnimations from '@components/LottieAnimations'; import type {MenuItemProps} from '@components/MenuItem'; -import BottomTabBar, {BOTTOM_TABS} from '@components/Navigation/BottomTabBar'; +import BottomTabBar from '@components/Navigation/BottomTabBar'; +import BOTTOM_TABS from '@components/Navigation/BottomTabBar/BOTTOM_TABS'; import type {OfflineWithFeedbackProps} from '@components/OfflineWithFeedback'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import type {PopoverMenuItem} from '@components/PopoverMenu'; From 03e6a6dd3d1e49789d4e066e2aac5e15a77aad68 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 23 Dec 2024 11:39:54 +0100 Subject: [PATCH 243/257] Move setNavigationActionToMicrotaskQueue to Navigation.ts --- src/libs/Navigation/Navigation.ts | 14 ++++++++++++++ .../helpers/setNavigationActionToMicrotaskQueue.ts | 13 ------------- 2 files changed, 14 insertions(+), 13 deletions(-) delete mode 100644 src/libs/Navigation/helpers/setNavigationActionToMicrotaskQueue.ts diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 5d8a0d925d02..b04b4ea592d3 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -524,6 +524,20 @@ function removeScreenFromNavigationState(screen: string) { }); } +function setNavigationActionToMicrotaskQueue(navigationAction: () => void) { + /** + * The function is used when the app needs to set a navigation action to the microtask queue, it guarantees to execute Onyx.update first, then the navigation action. + * More details - https://github.com/Expensify/App/issues/37785#issuecomment-1989056726. + */ + new Promise((resolve) => { + resolve(); + }).then(() => { + requestAnimationFrame(() => { + navigationAction(); + }); + }); +} + export default { setShouldPopAllStateOnUP, navigate, diff --git a/src/libs/Navigation/helpers/setNavigationActionToMicrotaskQueue.ts b/src/libs/Navigation/helpers/setNavigationActionToMicrotaskQueue.ts deleted file mode 100644 index f6c221185de6..000000000000 --- a/src/libs/Navigation/helpers/setNavigationActionToMicrotaskQueue.ts +++ /dev/null @@ -1,13 +0,0 @@ -export default function setNavigationActionToMicrotaskQueue(navigationAction: () => void) { - /** - * The function is used when the app needs to set a navigation action to the microtask queue, it guarantees to execute Onyx.update first, then the navigation action. - * More details - https://github.com/Expensify/App/issues/37785#issuecomment-1989056726. - */ - new Promise((resolve) => { - resolve(); - }).then(() => { - requestAnimationFrame(() => { - navigationAction(); - }); - }); -} From c4fa2877304a3f0531010e24051ba15b1c889b12 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 23 Dec 2024 13:36:43 +0100 Subject: [PATCH 244/257] Add tests for Navigation.goBack --- tests/ui/GoBackTests.tsx | 169 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 tests/ui/GoBackTests.tsx diff --git a/tests/ui/GoBackTests.tsx b/tests/ui/GoBackTests.tsx new file mode 100644 index 000000000000..dbeac2a874e5 --- /dev/null +++ b/tests/ui/GoBackTests.tsx @@ -0,0 +1,169 @@ +import {NavigationContainer} from '@react-navigation/native'; +import {act, render} from '@testing-library/react-native'; +import React from 'react'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; +import getIsNarrowLayout from '@libs/getIsNarrowLayout'; +import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator'; +import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; +import Navigation from '@libs/Navigation/Navigation'; +import navigationRef from '@libs/Navigation/navigationRef'; +import type {AuthScreensParamList, SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; +import NAVIGATORS from '@src/NAVIGATORS'; +import ROUTES from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; + +const RootStack = createResponsiveStackNavigator(); +const Split = createSplitNavigator(); + +jest.mock('@hooks/useResponsiveLayout', () => jest.fn()); +jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); + +jest.mock('@pages/home/sidebar/BottomTabAvatar'); + +const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: ResponsiveLayoutResult = { + shouldUseNarrowLayout: true, + isSmallScreenWidth: true, + isInNarrowPaneModal: false, + isExtraSmallScreenHeight: false, + isMediumScreenWidth: false, + isLargeScreenWidth: false, + isExtraSmallScreenWidth: false, + isSmallScreen: false, + onboardingIsMediumOrLargerScreenWidth: false, +}; + +const INITIAL_SETTINGS_STATE = { + index: 0, + routes: [ + { + name: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, + state: { + index: 2, + routes: [ + { + name: SCREENS.SETTINGS.ROOT, + }, + { + name: SCREENS.SETTINGS.PROFILE.ROOT, + }, + { + name: SCREENS.SETTINGS.PREFERENCES.ROOT, + }, + ], + }, + }, + ], +}; + +const PARENT_ROUTE = {key: 'parentRouteKey', name: 'ParentNavigator'}; + +const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; +const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; + +function SettingsSplitNavigator() { + return ( + + jest.fn()} + /> + jest.fn()} + /> + jest.fn()} + /> + jest.fn()} + /> + + ); +} + +function NavigationContainerWithSettings() { + return ( + + + + + + ); +} + +describe('Go back on the narrow layout without comparing route params', () => { + beforeEach(() => { + mockedGetIsNarrowLayout.mockReturnValue(true); + mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); + }); + + it('Should pop the last page in the navigation state', () => { + // Given the initialized navigation on the narrow layout with the settings split navigator + render(); + + const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitBeforeGoBack?.state?.index).toBe(2); + expect(settingsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PREFERENCES.ROOT); + + // When go back without specifying fallbackRoute + act(() => { + Navigation.goBack(); + }); + + // Then pop the last screen from the navigation state + const settingsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitAfterGoBack?.state?.index).toBe(1); + expect(settingsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PROFILE.ROOT); + }); + + it('Should go back to the page passed to goBack as a fallbackRoute', () => { + // Given the initialized navigation on the narrow layout with the settings split navigator + render(); + + const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitBeforeGoBack?.state?.index).toBe(2); + expect(settingsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PREFERENCES.ROOT); + + // When go back to the fallbackRoute present in the navigation state + act(() => { + Navigation.goBack(ROUTES.SETTINGS); + }); + + // Then pop to the fallbackRoute + const settingsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitAfterGoBack?.state?.index).toBe(0); + expect(settingsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ROOT); + }); + + it('Should replace the current page with the page passed as a fallbackRoute', () => { + // Given the initialized navigation on the narrow layout with the settings split navigator + render(); + + const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitBeforeGoBack?.state?.index).toBe(2); + expect(settingsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PREFERENCES.ROOT); + + // When go back to the fallbackRoute that does not exist in the navigation state + act(() => { + Navigation.goBack(ROUTES.SETTINGS_ABOUT); + }); + + // Then replace the current page with the page passed as a fallbackRoute + const settingsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitAfterGoBack?.state?.index).toBe(2); + expect(settingsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ABOUT); + }); +}); From 4a6766eeb95a36cfc26fa7cccfe3cd4f3b81003c Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 23 Dec 2024 16:45:27 +0100 Subject: [PATCH 245/257] Add tests for Navigation.goBack with comparing route params --- tests/ui/GoBackTests.tsx | 124 ++++++++++++++++++++++++++++++++++----- 1 file changed, 109 insertions(+), 15 deletions(-) diff --git a/tests/ui/GoBackTests.tsx b/tests/ui/GoBackTests.tsx index dbeac2a874e5..816e2db22043 100644 --- a/tests/ui/GoBackTests.tsx +++ b/tests/ui/GoBackTests.tsx @@ -1,3 +1,4 @@ +import type {InitialState} from '@react-navigation/native'; import {NavigationContainer} from '@react-navigation/native'; import {act, render} from '@testing-library/react-native'; import React from 'react'; @@ -8,13 +9,14 @@ import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/create import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import Navigation from '@libs/Navigation/Navigation'; import navigationRef from '@libs/Navigation/navigationRef'; -import type {AuthScreensParamList, SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; +import type {AuthScreensParamList, ReportsSplitNavigatorParamList, SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; import NAVIGATORS from '@src/NAVIGATORS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; const RootStack = createResponsiveStackNavigator(); -const Split = createSplitNavigator(); +const ReportsSplit = createSplitNavigator(); +const SettingsSplit = createSplitNavigator(); jest.mock('@hooks/useResponsiveLayout', () => jest.fn()); jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); @@ -33,7 +35,7 @@ const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: ResponsiveLayoutResult = { onboardingIsMediumOrLargerScreenWidth: false, }; -const INITIAL_SETTINGS_STATE = { +const INITIAL_SETTINGS_STATE: InitialState = { index: 0, routes: [ { @@ -56,6 +58,31 @@ const INITIAL_SETTINGS_STATE = { ], }; +const INITIAL_REPORTS_STATE: InitialState = { + index: 0, + routes: [ + { + name: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, + state: { + index: 2, + routes: [ + { + name: SCREENS.HOME, + }, + { + name: SCREENS.REPORT, + params: {reportID: '1'}, + }, + { + name: SCREENS.REPORT, + params: {reportID: '2'}, + }, + ], + }, + }, + ], +}; + const PARENT_ROUTE = {key: 'parentRouteKey', name: 'ParentNavigator'}; const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; @@ -63,38 +90,63 @@ const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction - jest.fn()} /> - jest.fn()} /> - jest.fn()} /> - jest.fn()} /> - + ); } -function NavigationContainerWithSettings() { +function ReportsSplitNavigator() { + return ( + + jest.fn()} + /> + jest.fn()} + /> + + ); +} + +type TestNavigationContainerProps = {initialState: InitialState}; + +function TestNavigationContainer({initialState}: TestNavigationContainerProps) { return ( + { +describe('Go back on the narrow layout', () => { beforeEach(() => { mockedGetIsNarrowLayout.mockReturnValue(true); mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); @@ -112,7 +164,7 @@ describe('Go back on the narrow layout without comparing route params', () => { it('Should pop the last page in the navigation state', () => { // Given the initialized navigation on the narrow layout with the settings split navigator - render(); + render(); const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); expect(settingsSplitBeforeGoBack?.state?.index).toBe(2); @@ -131,7 +183,7 @@ describe('Go back on the narrow layout without comparing route params', () => { it('Should go back to the page passed to goBack as a fallbackRoute', () => { // Given the initialized navigation on the narrow layout with the settings split navigator - render(); + render(); const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); expect(settingsSplitBeforeGoBack?.state?.index).toBe(2); @@ -150,7 +202,7 @@ describe('Go back on the narrow layout without comparing route params', () => { it('Should replace the current page with the page passed as a fallbackRoute', () => { // Given the initialized navigation on the narrow layout with the settings split navigator - render(); + render(); const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); expect(settingsSplitBeforeGoBack?.state?.index).toBe(2); @@ -166,4 +218,46 @@ describe('Go back on the narrow layout without comparing route params', () => { expect(settingsSplitAfterGoBack?.state?.index).toBe(2); expect(settingsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ABOUT); }); + + it('Should go back to the page with matched route params', () => { + // Given the initialized navigation on the narrow layout with the reports split navigator + render(); + + const reportsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(reportsSplitBeforeGoBack?.state?.index).toBe(2); + expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); + expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '2'}); + + // When go back to the same page with a different route param + act(() => { + Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute('1')); + }); + + // Then pop to the page with matching params + const reportsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(reportsSplitAfterGoBack?.state?.index).toBe(1); + expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); + expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '1'}); + }); + + it('Should replace the current page with the same one with different params', () => { + // Given the initialized navigation on the narrow layout with the reports split navigator + render(); + + const reportsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(reportsSplitBeforeGoBack?.state?.index).toBe(2); + expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); + expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '2'}); + + // When go back to the same page with different route params that does not exist in the navigation state + act(() => { + Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute('3')); + }); + + // Then replace the current page with the same one with different params + const reportsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(reportsSplitAfterGoBack?.state?.index).toBe(2); + expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); + expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '3'}); + }); }); From 3acba0a1c2ae389b055aff9220eb3962112a030d Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 30 Dec 2024 08:50:44 +0100 Subject: [PATCH 246/257] Add test for going back to previous split --- tests/ui/GoBackTests.tsx | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/ui/GoBackTests.tsx b/tests/ui/GoBackTests.tsx index 816e2db22043..565eea88a783 100644 --- a/tests/ui/GoBackTests.tsx +++ b/tests/ui/GoBackTests.tsx @@ -260,4 +260,28 @@ describe('Go back on the narrow layout', () => { expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '3'}); }); + + it('Should go back to the page from the previous split navigator', () => { + const initialState = { + index: 1, + routes: [...INITIAL_SETTINGS_STATE.routes, ...INITIAL_REPORTS_STATE.routes], + }; + + // Given the initialized navigation on the narrow layout with reports and settings pages + render(); + + const rootStateBeforeGoBack = navigationRef.current?.getRootState(); + expect(rootStateBeforeGoBack?.index).toBe(1); + expect(rootStateBeforeGoBack?.routes.at(-1)?.name).toBe(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + + // When go back to the page present in the previous split navigator + act(() => { + Navigation.goBack(ROUTES.SETTINGS); + }); + + // Then pop the current split navigator + const rootStateAfterGoBack = navigationRef.current?.getRootState(); + expect(rootStateAfterGoBack?.index).toBe(0); + expect(rootStateAfterGoBack?.routes.at(-1)?.name).toBe(NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR); + }); }); From 5232577412290687f804bbb776f91252f5e81f75 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 31 Dec 2024 10:03:48 +0100 Subject: [PATCH 247/257] Cleanup and group go back tests --- tests/ui/GoBackTests.tsx | 486 ++++++++++++++++++++++++++------------- 1 file changed, 331 insertions(+), 155 deletions(-) diff --git a/tests/ui/GoBackTests.tsx b/tests/ui/GoBackTests.tsx index 565eea88a783..eb8b69b23dcb 100644 --- a/tests/ui/GoBackTests.tsx +++ b/tests/ui/GoBackTests.tsx @@ -35,54 +35,6 @@ const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: ResponsiveLayoutResult = { onboardingIsMediumOrLargerScreenWidth: false, }; -const INITIAL_SETTINGS_STATE: InitialState = { - index: 0, - routes: [ - { - name: NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, - state: { - index: 2, - routes: [ - { - name: SCREENS.SETTINGS.ROOT, - }, - { - name: SCREENS.SETTINGS.PROFILE.ROOT, - }, - { - name: SCREENS.SETTINGS.PREFERENCES.ROOT, - }, - ], - }, - }, - ], -}; - -const INITIAL_REPORTS_STATE: InitialState = { - index: 0, - routes: [ - { - name: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, - state: { - index: 2, - routes: [ - { - name: SCREENS.HOME, - }, - { - name: SCREENS.REPORT, - params: {reportID: '1'}, - }, - { - name: SCREENS.REPORT, - params: {reportID: '2'}, - }, - ], - }, - }, - ], -}; - const PARENT_ROUTE = {key: 'parentRouteKey', name: 'ParentNavigator'}; const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; @@ -162,126 +114,350 @@ describe('Go back on the narrow layout', () => { mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); }); - it('Should pop the last page in the navigation state', () => { - // Given the initialized navigation on the narrow layout with the settings split navigator - render(); - - const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); - expect(settingsSplitBeforeGoBack?.state?.index).toBe(2); - expect(settingsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PREFERENCES.ROOT); - - // When go back without specifying fallbackRoute - act(() => { - Navigation.goBack(); + describe('called without params', () => { + it('Should pop the last page in the navigation state', () => { + // Given the initialized navigation on the narrow layout with the settings split navigator + render( + , + ); + + const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitBeforeGoBack?.state?.index).toBe(1); + expect(settingsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PROFILE.ROOT); + + // When go back without specifying fallbackRoute + act(() => { + Navigation.goBack(); + }); + + // Then pop the last screen from the navigation state + const settingsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitAfterGoBack?.state?.index).toBe(0); + expect(settingsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ROOT); }); - - // Then pop the last screen from the navigation state - const settingsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); - expect(settingsSplitAfterGoBack?.state?.index).toBe(1); - expect(settingsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PROFILE.ROOT); }); - it('Should go back to the page passed to goBack as a fallbackRoute', () => { - // Given the initialized navigation on the narrow layout with the settings split navigator - render(); - - const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); - expect(settingsSplitBeforeGoBack?.state?.index).toBe(2); - expect(settingsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PREFERENCES.ROOT); - - // When go back to the fallbackRoute present in the navigation state - act(() => { - Navigation.goBack(ROUTES.SETTINGS); + describe('called with fallbackRoute param', () => { + it('Should go back to the page passed to goBack as a fallbackRoute', () => { + // Given the initialized navigation on the narrow layout with the settings split navigator + render( + , + ); + + const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitBeforeGoBack?.state?.index).toBe(2); + expect(settingsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PREFERENCES.ROOT); + + // When go back to the fallbackRoute present in the navigation state + act(() => { + Navigation.goBack(ROUTES.SETTINGS); + }); + + // Then pop to the fallbackRoute + const settingsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitAfterGoBack?.state?.index).toBe(0); + expect(settingsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ROOT); }); - // Then pop to the fallbackRoute - const settingsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); - expect(settingsSplitAfterGoBack?.state?.index).toBe(0); - expect(settingsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ROOT); - }); - - it('Should replace the current page with the page passed as a fallbackRoute', () => { - // Given the initialized navigation on the narrow layout with the settings split navigator - render(); - - const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); - expect(settingsSplitBeforeGoBack?.state?.index).toBe(2); - expect(settingsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PREFERENCES.ROOT); - - // When go back to the fallbackRoute that does not exist in the navigation state - act(() => { - Navigation.goBack(ROUTES.SETTINGS_ABOUT); + it('Should replace the current page with the page passed as a fallbackRoute', () => { + // Given the initialized navigation on the narrow layout with the settings split navigator + render( + , + ); + + const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitBeforeGoBack?.state?.index).toBe(1); + expect(settingsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PROFILE.ROOT); + + // When go back to the fallbackRoute that does not exist in the navigation state + act(() => { + Navigation.goBack(ROUTES.SETTINGS_ABOUT); + }); + + // Then replace the current page with the page passed as a fallbackRoute + const settingsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitAfterGoBack?.state?.index).toBe(1); + expect(settingsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ABOUT); }); - // Then replace the current page with the page passed as a fallbackRoute - const settingsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); - expect(settingsSplitAfterGoBack?.state?.index).toBe(2); - expect(settingsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ABOUT); - }); - - it('Should go back to the page with matched route params', () => { - // Given the initialized navigation on the narrow layout with the reports split navigator - render(); - - const reportsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); - expect(reportsSplitBeforeGoBack?.state?.index).toBe(2); - expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); - expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '2'}); - - // When go back to the same page with a different route param - act(() => { - Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute('1')); + it('Should go back to the page from the previous split navigator', () => { + // Given the initialized navigation on the narrow layout with reports and settings pages + render( + , + ); + + const rootStateBeforeGoBack = navigationRef.current?.getRootState(); + expect(rootStateBeforeGoBack?.index).toBe(1); + expect(rootStateBeforeGoBack?.routes.at(-1)?.name).toBe(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + + // When go back to the page present in the previous split navigator + act(() => { + Navigation.goBack(ROUTES.SETTINGS); + }); + + // Then pop the current split navigator + const rootStateAfterGoBack = navigationRef.current?.getRootState(); + expect(rootStateAfterGoBack?.index).toBe(0); + expect(rootStateAfterGoBack?.routes.at(-1)?.name).toBe(NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR); }); - - // Then pop to the page with matching params - const reportsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); - expect(reportsSplitAfterGoBack?.state?.index).toBe(1); - expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); - expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '1'}); }); - it('Should replace the current page with the same one with different params', () => { - // Given the initialized navigation on the narrow layout with the reports split navigator - render(); - - const reportsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); - expect(reportsSplitBeforeGoBack?.state?.index).toBe(2); - expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); - expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '2'}); - - // When go back to the same page with different route params that does not exist in the navigation state - act(() => { - Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute('3')); + describe('called with fallbackRoute param with route params comparison', () => { + it('Should go back to the page with matched route params', () => { + // Given the initialized navigation on the narrow layout with the reports split navigator + render( + , + ); + + const reportsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(reportsSplitBeforeGoBack?.state?.index).toBe(3); + expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); + expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '3'}); + + // When go back to the same page with a different route param + act(() => { + Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute('1')); + }); + + // Then pop to the page with matching params + const reportsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(reportsSplitAfterGoBack?.state?.index).toBe(1); + expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); + expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '1'}); }); - // Then replace the current page with the same one with different params - const reportsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); - expect(reportsSplitAfterGoBack?.state?.index).toBe(2); - expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); - expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '3'}); - }); - - it('Should go back to the page from the previous split navigator', () => { - const initialState = { - index: 1, - routes: [...INITIAL_SETTINGS_STATE.routes, ...INITIAL_REPORTS_STATE.routes], - }; - - // Given the initialized navigation on the narrow layout with reports and settings pages - render(); - - const rootStateBeforeGoBack = navigationRef.current?.getRootState(); - expect(rootStateBeforeGoBack?.index).toBe(1); - expect(rootStateBeforeGoBack?.routes.at(-1)?.name).toBe(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); - - // When go back to the page present in the previous split navigator - act(() => { - Navigation.goBack(ROUTES.SETTINGS); + it('Should replace the current page with the same one with different params', () => { + // Given the initialized navigation on the narrow layout with the reports split navigator + render( + , + ); + + const reportsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(reportsSplitBeforeGoBack?.state?.index).toBe(2); + expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); + expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '2'}); + + // When go back to the same page with different route params that does not exist in the navigation state + act(() => { + Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute('3')); + }); + + // Then replace the current page with the same one with different params + const reportsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(reportsSplitAfterGoBack?.state?.index).toBe(2); + expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); + expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '3'}); }); - // Then pop the current split navigator - const rootStateAfterGoBack = navigationRef.current?.getRootState(); - expect(rootStateAfterGoBack?.index).toBe(0); - expect(rootStateAfterGoBack?.routes.at(-1)?.name).toBe(NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR); + it('Should go back without comparing params', () => { + // Given the initialized navigation on the narrow layout with reports split navigator + render( + , + ); + + const reportsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(reportsSplitBeforeGoBack?.state?.index).toBe(3); + expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); + expect(reportsSplitBeforeGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '3'}); + + // When go back to the same page with different route params without comparing params + act(() => { + Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute('1'), {compareParams: false}); + }); + + // Then do not go back to the page with matching route params, instead replace the current page + const reportsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(reportsSplitAfterGoBack?.state?.index).toBe(3); + expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.REPORT); + expect(reportsSplitAfterGoBack?.state?.routes.at(-1)?.params).toMatchObject({reportID: '1'}); + }); }); }); From 0b6c39fc12acb8ffc79b240a8c301d1a43f37a5b Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 31 Dec 2024 11:47:54 +0100 Subject: [PATCH 248/257] Add test for going back to the page present in the split navigator that is more than 1 route away --- tests/ui/GoBackTests.tsx | 72 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/tests/ui/GoBackTests.tsx b/tests/ui/GoBackTests.tsx index eb8b69b23dcb..defc058bb0ce 100644 --- a/tests/ui/GoBackTests.tsx +++ b/tests/ui/GoBackTests.tsx @@ -103,6 +103,10 @@ function TestNavigationContainer({initialState}: TestNavigationContainerProps) { name={NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR} component={SettingsSplitNavigator} /> + jest.fn()} + /> ); @@ -305,10 +309,76 @@ describe('Go back on the narrow layout', () => { expect(rootStateAfterGoBack?.index).toBe(0); expect(rootStateAfterGoBack?.routes.at(-1)?.name).toBe(NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR); }); + + it('Should replace the current route with a new split navigator when distance from the fallbackRoute is greater than one split navigator', () => { + // Given the initialized navigation on the narrow layout + render( + , + ); + + const rootStateBeforeGoBack = navigationRef.current?.getRootState(); + expect(rootStateBeforeGoBack?.index).toBe(2); + expect(rootStateBeforeGoBack?.routes.at(-1)?.name).toBe(SCREENS.SEARCH.CENTRAL_PANE); + + // When go back to the page present in the split navigator that is more than 1 route away + act(() => { + Navigation.goBack(ROUTES.SETTINGS); + }); + + // Then replace the current route with a new split navigator including the target page to avoid losing routes from the navigation state + const rootStateAfterGoBack = navigationRef.current?.getRootState(); + expect(rootStateAfterGoBack?.index).toBe(2); + expect(rootStateAfterGoBack?.routes.at(-1)?.name).toBe(NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR); + }); }); describe('called with fallbackRoute param with route params comparison', () => { - it('Should go back to the page with matched route params', () => { + it('Should go back to the page with matching route params', () => { // Given the initialized navigation on the narrow layout with the reports split navigator render( Date: Tue, 31 Dec 2024 13:14:12 +0100 Subject: [PATCH 249/257] Add NavigateTests --- tests/ui/NavigateTests.tsx | 279 +++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 tests/ui/NavigateTests.tsx diff --git a/tests/ui/NavigateTests.tsx b/tests/ui/NavigateTests.tsx new file mode 100644 index 000000000000..107f151424a3 --- /dev/null +++ b/tests/ui/NavigateTests.tsx @@ -0,0 +1,279 @@ +import type {InitialState} from '@react-navigation/native'; +import {NavigationContainer} from '@react-navigation/native'; +import {act, render} from '@testing-library/react-native'; +import React from 'react'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; +import getIsNarrowLayout from '@libs/getIsNarrowLayout'; +import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator'; +import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; +import Navigation from '@libs/Navigation/Navigation'; +import navigationRef from '@libs/Navigation/navigationRef'; +import type {AuthScreensParamList, ReportsSplitNavigatorParamList, SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; +import CONST from '@src/CONST'; +import NAVIGATORS from '@src/NAVIGATORS'; +import ROUTES from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; + +const RootStack = createResponsiveStackNavigator(); +const ReportsSplit = createSplitNavigator(); +const SettingsSplit = createSplitNavigator(); + +jest.mock('@hooks/useResponsiveLayout', () => jest.fn()); +jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); + +jest.mock('@pages/home/sidebar/BottomTabAvatar'); + +const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: ResponsiveLayoutResult = { + shouldUseNarrowLayout: true, + isSmallScreenWidth: true, + isInNarrowPaneModal: false, + isExtraSmallScreenHeight: false, + isMediumScreenWidth: false, + isLargeScreenWidth: false, + isExtraSmallScreenWidth: false, + isSmallScreen: false, + onboardingIsMediumOrLargerScreenWidth: false, +}; + +const PARENT_ROUTE = {key: 'parentRouteKey', name: 'ParentNavigator'}; + +const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; +const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; + +function SettingsSplitNavigator() { + return ( + + jest.fn()} + /> + jest.fn()} + /> + jest.fn()} + /> + jest.fn()} + /> + + ); +} + +function ReportsSplitNavigator() { + return ( + + jest.fn()} + /> + jest.fn()} + /> + + ); +} + +type TestNavigationContainerProps = {initialState: InitialState}; + +function TestNavigationContainer({initialState}: TestNavigationContainerProps) { + return ( + + + + + jest.fn()} + /> + + + ); +} + +describe('Navigate', () => { + beforeEach(() => { + mockedGetIsNarrowLayout.mockReturnValue(true); + mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); + }); + + describe('on the narrow layout', () => { + it('to the page within the same navigator', () => { + // Given the initialized navigation on the narrow layout with the settings split navigator + render( + , + ); + + const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitBeforeGoBack?.state?.index).toBe(0); + expect(settingsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ROOT); + + // When navigate to the page from the same split navigator + act(() => { + Navigation.navigate(ROUTES.SETTINGS_PROFILE); + }); + + // Then push a new page to the current split navigator + const settingsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitAfterGoBack?.state?.index).toBe(1); + expect(settingsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PROFILE.ROOT); + }); + + it('to the page within the same navigator using replace action', () => { + // Given the initialized navigation on the narrow layout with the settings split navigator + render( + , + ); + + const settingsSplitBeforeGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitBeforeGoBack?.state?.index).toBe(1); + expect(settingsSplitBeforeGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.PROFILE.ROOT); + + // When navigate to the page from the same split navigator using replace action + act(() => { + Navigation.navigate(ROUTES.SETTINGS_ABOUT, CONST.NAVIGATION.ACTION_TYPE.REPLACE); + }); + + // Then replace the current page with the page passed to the navigate function + const settingsSplitAfterGoBack = navigationRef.current?.getRootState().routes.at(0); + expect(settingsSplitAfterGoBack?.state?.index).toBe(1); + expect(settingsSplitAfterGoBack?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ABOUT); + }); + + it('to the page from the different split navigator', () => { + // Given the initialized navigation on the narrow layout with the settings split navigator + render( + , + ); + + const rootStateBeforeNavigate = navigationRef.current?.getRootState(); + const lastSplitBeforeNavigate = rootStateBeforeNavigate?.routes.at(-1); + expect(rootStateBeforeNavigate?.index).toBe(0); + expect(lastSplitBeforeNavigate?.name).toBe(NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR); + expect(lastSplitBeforeNavigate?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ROOT); + + // When navigate to the page from the different split navigator + act(() => { + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute('1')); + }); + + // Then push a new split navigator to the navigation state + const rootStateAfterNavigate = navigationRef.current?.getRootState(); + const lastSplitAfterNavigate = rootStateAfterNavigate?.routes.at(-1); + expect(rootStateAfterNavigate?.index).toBe(1); + expect(lastSplitAfterNavigate?.name).toBe(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + }); + + it('to the report split from the search page passing the active workspace id', () => { + // Given the initialized navigation on the narrow layout with the search page with the active workspace id + render( + , + ); + + const rootStateBeforeNavigate = navigationRef.current?.getRootState(); + const lastSplitBeforeNavigate = rootStateBeforeNavigate?.routes.at(-1); + expect(rootStateBeforeNavigate?.index).toBe(0); + expect(lastSplitBeforeNavigate?.name).toBe(SCREENS.SEARCH.CENTRAL_PANE); + + // When navigate to the Home page when the active workspace is set + act(() => { + Navigation.navigate(ROUTES.HOME); + }); + + // Then push a new report split navigator with policyID in params + const rootStateAfterNavigate = navigationRef.current?.getRootState(); + const lastSplitAfterNavigate = rootStateAfterNavigate?.routes.at(-1); + expect(rootStateAfterNavigate?.index).toBe(1); + expect(lastSplitAfterNavigate?.name).toBe(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + expect(lastSplitAfterNavigate?.params).toMatchObject({policyID: '1'}); + }); + }); +}); From 3a9fd70bc84925512a16fab376e602a737c7163e Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 7 Jan 2025 11:13:33 +0100 Subject: [PATCH 250/257] Add SwitchPolicyIDTests --- tests/ui/SwitchPolicyIDTests.tsx | 258 +++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 tests/ui/SwitchPolicyIDTests.tsx diff --git a/tests/ui/SwitchPolicyIDTests.tsx b/tests/ui/SwitchPolicyIDTests.tsx new file mode 100644 index 000000000000..e74308b55520 --- /dev/null +++ b/tests/ui/SwitchPolicyIDTests.tsx @@ -0,0 +1,258 @@ +import type {InitialState} from '@react-navigation/native'; +import {NavigationContainer} from '@react-navigation/native'; +import {act, render} from '@testing-library/react-native'; +import React from 'react'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; +import getIsNarrowLayout from '@libs/getIsNarrowLayout'; +import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator'; +import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; +import navigationRef from '@libs/Navigation/navigationRef'; +import type {AuthScreensParamList, ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; +import switchPolicyAfterInteractions from '@pages/WorkspaceSwitcherPage/switchPolicyAfterInteractions'; +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; + +const RootStack = createResponsiveStackNavigator(); +const ReportsSplit = createSplitNavigator(); + +jest.mock('@hooks/useResponsiveLayout', () => jest.fn()); +jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); + +jest.mock('@pages/home/sidebar/BottomTabAvatar'); + +const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: ResponsiveLayoutResult = { + shouldUseNarrowLayout: true, + isSmallScreenWidth: true, + isInNarrowPaneModal: false, + isExtraSmallScreenHeight: false, + isMediumScreenWidth: false, + isLargeScreenWidth: false, + isExtraSmallScreenWidth: false, + isSmallScreen: false, + onboardingIsMediumOrLargerScreenWidth: false, +}; + +const PARENT_ROUTE = {key: 'parentRouteKey', name: 'ParentNavigator'}; + +const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; +const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; + +function ReportsSplitNavigator() { + return ( + + jest.fn()} + /> + jest.fn()} + /> + + ); +} + +type TestNavigationContainerProps = {initialState: InitialState}; + +function TestNavigationContainer({initialState}: TestNavigationContainerProps) { + return ( + + + + jest.fn()} + /> + + + ); +} + +describe('Switch policy ID', () => { + beforeEach(() => { + mockedGetIsNarrowLayout.mockReturnValue(true); + mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); + }); + + describe('from the global to the specific workspace', () => { + it('from the Inbox tab', () => { + // Given the initialized navigation on the narrow layout with the reports split navigator without the active workspace + render( + , + ); + + const rootStateBeforeSwitch = navigationRef.current?.getRootState(); + expect(rootStateBeforeSwitch?.index).toBe(0); + const lastRouteBeforeSwitch = rootStateBeforeSwitch?.routes?.at(-1); + expect(lastRouteBeforeSwitch?.name).toBe(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + expect(lastRouteBeforeSwitch?.params).toBeUndefined(); + + // When switch to the specific policy from the Inbox tab + act(() => { + switchPolicyAfterInteractions('1'); + }); + + // Then push a new report split navigator with the policyID route param + const rootStateAfterSwitch = navigationRef.current?.getRootState(); + expect(rootStateAfterSwitch?.index).toBe(1); + const lastRouteAfterSwitch = rootStateAfterSwitch?.routes?.at(-1); + expect(lastRouteAfterSwitch?.name).toBe(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + expect(lastRouteAfterSwitch?.params).toMatchObject({policyID: '1'}); + }); + + it('from the Search page', () => { + // Given the initialized navigation on the narrow layout with the search page without the active workspace + render( + , + ); + + const rootStateBeforeSwitch = navigationRef.current?.getRootState(); + expect(rootStateBeforeSwitch?.index).toBe(0); + const lastRouteBeforeSwitch = rootStateBeforeSwitch?.routes?.at(-1); + expect(lastRouteBeforeSwitch?.name).toBe(SCREENS.SEARCH.CENTRAL_PANE); + expect(lastRouteBeforeSwitch?.params).toMatchObject({q: 'type:expense status:all sortBy:date sortOrder:desc'}); + + // When switch to the specific policy from the Search page + act(() => { + switchPolicyAfterInteractions('1'); + }); + + // Then push a new search page with the policyID included in the query + const rootStateAfterSwitch = navigationRef.current?.getRootState(); + expect(rootStateAfterSwitch?.index).toBe(1); + const lastRouteAfterSwitch = rootStateAfterSwitch?.routes?.at(-1); + expect(lastRouteAfterSwitch?.name).toBe(SCREENS.SEARCH.CENTRAL_PANE); + expect(lastRouteAfterSwitch?.params).toMatchObject({q: 'type:expense status:all sortBy:date sortOrder:desc policyID:1'}); + }); + }); + + describe('from the specific workspace to the global', () => { + it('from the Inbox tab', () => { + // Given the initialized navigation on the narrow layout with the reports split navigator without the active workspace + render( + , + ); + + const rootStateBeforeSwitch = navigationRef.current?.getRootState(); + expect(rootStateBeforeSwitch?.index).toBe(0); + const lastRouteBeforeSwitch = rootStateBeforeSwitch?.routes?.at(-1); + expect(lastRouteBeforeSwitch?.name).toBe(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + expect(lastRouteBeforeSwitch?.params).toMatchObject({policyID: '1'}); + + // When switch policy to the global from the Inbox tab + act(() => { + switchPolicyAfterInteractions(undefined); + }); + + // Then push a new report split navigator without the policyID route param + const rootStateAfterSwitch = navigationRef.current?.getRootState(); + expect(rootStateAfterSwitch?.index).toBe(1); + const lastRouteAfterSwitch = rootStateAfterSwitch?.routes?.at(-1); + expect(lastRouteAfterSwitch?.name).toBe(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + expect(lastRouteAfterSwitch?.params).toMatchObject({policyID: undefined}); + }); + + it('from the Search page', () => { + // Given the initialized navigation on the narrow layout with the search page without the active workspace + render( + , + ); + + const rootStateBeforeSwitch = navigationRef.current?.getRootState(); + expect(rootStateBeforeSwitch?.index).toBe(0); + const lastRouteBeforeSwitch = rootStateBeforeSwitch?.routes?.at(-1); + expect(lastRouteBeforeSwitch?.name).toBe(SCREENS.SEARCH.CENTRAL_PANE); + expect(lastRouteBeforeSwitch?.params).toMatchObject({q: 'type:expense status:all sortBy:date sortOrder:desc policyID:1'}); + + // When switch policy to the global from the Search page + act(() => { + switchPolicyAfterInteractions(undefined); + }); + + // Then push a new search page without the policyID included in the query + const rootStateAfterSwitch = navigationRef.current?.getRootState(); + expect(rootStateAfterSwitch?.index).toBe(1); + const lastRouteAfterSwitch = rootStateAfterSwitch?.routes?.at(-1); + expect(lastRouteAfterSwitch?.name).toBe(SCREENS.SEARCH.CENTRAL_PANE); + expect(lastRouteAfterSwitch?.params).toMatchObject({q: 'type:expense status:all sortBy:date sortOrder:desc'}); + }); + }); +}); From c404c0274490f7e761e60bc781396f8390591562 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 7 Jan 2025 11:44:40 +0100 Subject: [PATCH 251/257] Create package for navigation tests --- jest.config.js | 1 + src/CONST.ts | 16 ++++++++++++++ tests/{ui => navigation}/GoBackTests.tsx | 22 ++++--------------- tests/{ui => navigation}/NavigateTests.tsx | 21 +++--------------- .../{ui => navigation}/ResizeScreenTests.tsx | 22 ++++--------------- .../SwitchPolicyIDTests.tsx | 20 +++-------------- 6 files changed, 31 insertions(+), 71 deletions(-) rename tests/{ui => navigation}/GoBackTests.tsx (97%) rename tests/{ui => navigation}/NavigateTests.tsx (93%) rename tests/{ui => navigation}/ResizeScreenTests.tsx (82%) rename tests/{ui => navigation}/SwitchPolicyIDTests.tsx (94%) diff --git a/jest.config.js b/jest.config.js index 13645e720c8e..ea9a23f01362 100644 --- a/jest.config.js +++ b/jest.config.js @@ -5,6 +5,7 @@ module.exports = { `/tests/ui/**/*.${testFileExtension}`, `/tests/unit/**/*.${testFileExtension}`, `/tests/actions/**/*.${testFileExtension}`, + `/tests/navigation/**/*.${testFileExtension}`, `/?(*.)+(spec|test).${testFileExtension}`, ], transform: { diff --git a/src/CONST.ts b/src/CONST.ts index c529e14a4846..b1c5ac7f8138 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -4,6 +4,7 @@ import {sub as dateSubtract} from 'date-fns/sub'; import Config from 'react-native-config'; import * as KeyCommand from 'react-native-key-command'; import type {ValueOf} from 'type-fest'; +import type ResponsiveLayoutResult from './hooks/useResponsiveLayout/types'; import type {Video} from './libs/actions/Report'; import type {MileageRate} from './libs/DistanceRequestUtils'; import BankAccount from './libs/models/BankAccount'; @@ -6494,6 +6495,21 @@ const CONST = { GLOBAL_CREATE_TOOLTIP: 'globalCreateTooltip', }, SMART_BANNER_HEIGHT: 152, + + NAVIGATION_TESTS: { + DEFAULT_PARENT_ROUTE: {key: 'parentRouteKey', name: 'ParentNavigator'}, + DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: { + shouldUseNarrowLayout: true, + isSmallScreenWidth: true, + isInNarrowPaneModal: false, + isExtraSmallScreenHeight: false, + isMediumScreenWidth: false, + isLargeScreenWidth: false, + isExtraSmallScreenWidth: false, + isSmallScreen: false, + onboardingIsMediumOrLargerScreenWidth: false, + } as ResponsiveLayoutResult, + }, } as const; type Country = keyof typeof CONST.ALL_COUNTRIES; diff --git a/tests/ui/GoBackTests.tsx b/tests/navigation/GoBackTests.tsx similarity index 97% rename from tests/ui/GoBackTests.tsx rename to tests/navigation/GoBackTests.tsx index defc058bb0ce..347cde2a232a 100644 --- a/tests/ui/GoBackTests.tsx +++ b/tests/navigation/GoBackTests.tsx @@ -3,13 +3,13 @@ import {NavigationContainer} from '@react-navigation/native'; import {act, render} from '@testing-library/react-native'; import React from 'react'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator'; import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import Navigation from '@libs/Navigation/Navigation'; import navigationRef from '@libs/Navigation/navigationRef'; import type {AuthScreensParamList, ReportsSplitNavigatorParamList, SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; +import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; @@ -23,20 +23,6 @@ jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); jest.mock('@pages/home/sidebar/BottomTabAvatar'); -const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: ResponsiveLayoutResult = { - shouldUseNarrowLayout: true, - isSmallScreenWidth: true, - isInNarrowPaneModal: false, - isExtraSmallScreenHeight: false, - isMediumScreenWidth: false, - isLargeScreenWidth: false, - isExtraSmallScreenWidth: false, - isSmallScreen: false, - onboardingIsMediumOrLargerScreenWidth: false, -}; - -const PARENT_ROUTE = {key: 'parentRouteKey', name: 'ParentNavigator'}; - const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; @@ -45,7 +31,7 @@ function SettingsSplitNavigator() { { beforeEach(() => { mockedGetIsNarrowLayout.mockReturnValue(true); - mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); + mockedUseResponsiveLayout.mockReturnValue({...CONST.NAVIGATION_TESTS.DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); }); describe('called without params', () => { diff --git a/tests/ui/NavigateTests.tsx b/tests/navigation/NavigateTests.tsx similarity index 93% rename from tests/ui/NavigateTests.tsx rename to tests/navigation/NavigateTests.tsx index 107f151424a3..23386739bbde 100644 --- a/tests/ui/NavigateTests.tsx +++ b/tests/navigation/NavigateTests.tsx @@ -3,7 +3,6 @@ import {NavigationContainer} from '@react-navigation/native'; import {act, render} from '@testing-library/react-native'; import React from 'react'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator'; import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; @@ -24,20 +23,6 @@ jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); jest.mock('@pages/home/sidebar/BottomTabAvatar'); -const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: ResponsiveLayoutResult = { - shouldUseNarrowLayout: true, - isSmallScreenWidth: true, - isInNarrowPaneModal: false, - isExtraSmallScreenHeight: false, - isMediumScreenWidth: false, - isLargeScreenWidth: false, - isExtraSmallScreenWidth: false, - isSmallScreen: false, - onboardingIsMediumOrLargerScreenWidth: false, -}; - -const PARENT_ROUTE = {key: 'parentRouteKey', name: 'ParentNavigator'}; - const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; @@ -46,7 +31,7 @@ function SettingsSplitNavigator() { { beforeEach(() => { mockedGetIsNarrowLayout.mockReturnValue(true); - mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); + mockedUseResponsiveLayout.mockReturnValue({...CONST.NAVIGATION_TESTS.DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); }); describe('on the narrow layout', () => { diff --git a/tests/ui/ResizeScreenTests.tsx b/tests/navigation/ResizeScreenTests.tsx similarity index 82% rename from tests/ui/ResizeScreenTests.tsx rename to tests/navigation/ResizeScreenTests.tsx index 15b83413bc68..08a4a6e0c639 100644 --- a/tests/ui/ResizeScreenTests.tsx +++ b/tests/navigation/ResizeScreenTests.tsx @@ -3,7 +3,6 @@ import {NavigationContainer} from '@react-navigation/native'; import {render, renderHook} from '@testing-library/react-native'; import React from 'react'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import useNavigationResetOnLayoutChange from '@libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange'; @@ -12,6 +11,7 @@ import type {CustomEffectsHookProps} from '@libs/Navigation/PlatformStackNavigat import type {SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; import InitialSettingsPage from '@pages/settings/InitialSettingsPage'; import ProfilePage from '@pages/settings/Profile/ProfilePage'; +import CONST from '@src/CONST'; import SCREENS from '@src/SCREENS'; const Split = createSplitNavigator(); @@ -22,18 +22,6 @@ jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); jest.mock('@pages/settings/InitialSettingsPage'); jest.mock('@pages/settings/Profile/ProfilePage'); -const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: ResponsiveLayoutResult = { - shouldUseNarrowLayout: true, - isSmallScreenWidth: true, - isInNarrowPaneModal: false, - isExtraSmallScreenHeight: false, - isMediumScreenWidth: false, - isLargeScreenWidth: false, - isExtraSmallScreenWidth: false, - isSmallScreen: false, - onboardingIsMediumOrLargerScreenWidth: false, -}; - const INITIAL_STATE = { index: 0, routes: [ @@ -43,8 +31,6 @@ const INITIAL_STATE = { ], }; -const PARENT_ROUTE = {key: 'parentRouteKey', name: 'ParentNavigator'}; - const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; @@ -52,7 +38,7 @@ describe('Resize screen', () => { it('Should display the settings profile after resizing the screen with the settings page opened to the wide layout', () => { // Given the initialized navigation on the narrow layout with the settings screen mockedGetIsNarrowLayout.mockReturnValue(true); - mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); + mockedUseResponsiveLayout.mockReturnValue({...CONST.NAVIGATION_TESTS.DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); render( { { // When resizing the screen to the wide layout mockedGetIsNarrowLayout.mockReturnValue(false); - mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: false}); + mockedUseResponsiveLayout.mockReturnValue({...CONST.NAVIGATION_TESTS.DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: false}); rerender({}); const rootStateAfterResize = navigationRef.current?.getRootState(); diff --git a/tests/ui/SwitchPolicyIDTests.tsx b/tests/navigation/SwitchPolicyIDTests.tsx similarity index 94% rename from tests/ui/SwitchPolicyIDTests.tsx rename to tests/navigation/SwitchPolicyIDTests.tsx index e74308b55520..50778b8fe698 100644 --- a/tests/ui/SwitchPolicyIDTests.tsx +++ b/tests/navigation/SwitchPolicyIDTests.tsx @@ -3,13 +3,13 @@ import {NavigationContainer} from '@react-navigation/native'; import {act, render} from '@testing-library/react-native'; import React from 'react'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; -import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator'; import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import navigationRef from '@libs/Navigation/navigationRef'; import type {AuthScreensParamList, ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; import switchPolicyAfterInteractions from '@pages/WorkspaceSwitcherPage/switchPolicyAfterInteractions'; +import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; @@ -21,20 +21,6 @@ jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); jest.mock('@pages/home/sidebar/BottomTabAvatar'); -const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE: ResponsiveLayoutResult = { - shouldUseNarrowLayout: true, - isSmallScreenWidth: true, - isInNarrowPaneModal: false, - isExtraSmallScreenHeight: false, - isMediumScreenWidth: false, - isLargeScreenWidth: false, - isExtraSmallScreenWidth: false, - isSmallScreen: false, - onboardingIsMediumOrLargerScreenWidth: false, -}; - -const PARENT_ROUTE = {key: 'parentRouteKey', name: 'ParentNavigator'}; - const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; @@ -43,7 +29,7 @@ function ReportsSplitNavigator() { { beforeEach(() => { mockedGetIsNarrowLayout.mockReturnValue(true); - mockedUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); + mockedUseResponsiveLayout.mockReturnValue({...CONST.NAVIGATION_TESTS.DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); }); describe('from the global to the specific workspace', () => { From 39605796ba26c1bf58ee4504700fd69cf483044d Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 10 Jan 2025 09:17:38 +0100 Subject: [PATCH 252/257] Move setNavigationActionToMicrotaskQueue to helpers --- src/libs/Navigation/Navigation.ts | 14 -------------- .../helpers/setNavigationActionToMicrotaskQueue.ts | 13 +++++++++++++ 2 files changed, 13 insertions(+), 14 deletions(-) create mode 100644 src/libs/Navigation/helpers/setNavigationActionToMicrotaskQueue.ts diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index b04b4ea592d3..5d8a0d925d02 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -524,20 +524,6 @@ function removeScreenFromNavigationState(screen: string) { }); } -function setNavigationActionToMicrotaskQueue(navigationAction: () => void) { - /** - * The function is used when the app needs to set a navigation action to the microtask queue, it guarantees to execute Onyx.update first, then the navigation action. - * More details - https://github.com/Expensify/App/issues/37785#issuecomment-1989056726. - */ - new Promise((resolve) => { - resolve(); - }).then(() => { - requestAnimationFrame(() => { - navigationAction(); - }); - }); -} - export default { setShouldPopAllStateOnUP, navigate, diff --git a/src/libs/Navigation/helpers/setNavigationActionToMicrotaskQueue.ts b/src/libs/Navigation/helpers/setNavigationActionToMicrotaskQueue.ts new file mode 100644 index 000000000000..f6c221185de6 --- /dev/null +++ b/src/libs/Navigation/helpers/setNavigationActionToMicrotaskQueue.ts @@ -0,0 +1,13 @@ +export default function setNavigationActionToMicrotaskQueue(navigationAction: () => void) { + /** + * The function is used when the app needs to set a navigation action to the microtask queue, it guarantees to execute Onyx.update first, then the navigation action. + * More details - https://github.com/Expensify/App/issues/37785#issuecomment-1989056726. + */ + new Promise((resolve) => { + resolve(); + }).then(() => { + requestAnimationFrame(() => { + navigationAction(); + }); + }); +} From 8bc926d74860f69daf2862cf563f58aa6355b31e Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 10 Jan 2025 09:54:04 +0100 Subject: [PATCH 253/257] Refactor old names in nav tests --- tests/navigation/GoBackTests.tsx | 10 +++++----- tests/navigation/NavigateTests.tsx | 10 +++++----- tests/navigation/SwitchPolicyIDTests.tsx | 18 +++++++++--------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/navigation/GoBackTests.tsx b/tests/navigation/GoBackTests.tsx index 347cde2a232a..08483f6d01fd 100644 --- a/tests/navigation/GoBackTests.tsx +++ b/tests/navigation/GoBackTests.tsx @@ -4,7 +4,7 @@ import {act, render} from '@testing-library/react-native'; import React from 'react'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator'; +import createRootStackNavigator from '@libs/Navigation/AppNavigator/createRootStackNavigator'; import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import Navigation from '@libs/Navigation/Navigation'; import navigationRef from '@libs/Navigation/navigationRef'; @@ -14,7 +14,7 @@ import NAVIGATORS from '@src/NAVIGATORS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; -const RootStack = createResponsiveStackNavigator(); +const RootStack = createRootStackNavigator(); const ReportsSplit = createSplitNavigator(); const SettingsSplit = createSplitNavigator(); @@ -90,7 +90,7 @@ function TestNavigationContainer({initialState}: TestNavigationContainerProps) { component={SettingsSplitNavigator} /> jest.fn()} /> @@ -340,7 +340,7 @@ describe('Go back on the narrow layout', () => { }, }, { - name: SCREENS.SEARCH.CENTRAL_PANE, + name: SCREENS.SEARCH.ROOT, }, ], }} @@ -349,7 +349,7 @@ describe('Go back on the narrow layout', () => { const rootStateBeforeGoBack = navigationRef.current?.getRootState(); expect(rootStateBeforeGoBack?.index).toBe(2); - expect(rootStateBeforeGoBack?.routes.at(-1)?.name).toBe(SCREENS.SEARCH.CENTRAL_PANE); + expect(rootStateBeforeGoBack?.routes.at(-1)?.name).toBe(SCREENS.SEARCH.ROOT); // When go back to the page present in the split navigator that is more than 1 route away act(() => { diff --git a/tests/navigation/NavigateTests.tsx b/tests/navigation/NavigateTests.tsx index 23386739bbde..f4bc3be4a001 100644 --- a/tests/navigation/NavigateTests.tsx +++ b/tests/navigation/NavigateTests.tsx @@ -4,7 +4,7 @@ import {act, render} from '@testing-library/react-native'; import React from 'react'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator'; +import createRootStackNavigator from '@libs/Navigation/AppNavigator/createRootStackNavigator'; import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import Navigation from '@libs/Navigation/Navigation'; import navigationRef from '@libs/Navigation/navigationRef'; @@ -14,7 +14,7 @@ import NAVIGATORS from '@src/NAVIGATORS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; -const RootStack = createResponsiveStackNavigator(); +const RootStack = createRootStackNavigator(); const ReportsSplit = createSplitNavigator(); const SettingsSplit = createSplitNavigator(); @@ -90,7 +90,7 @@ function TestNavigationContainer({initialState}: TestNavigationContainerProps) { component={SettingsSplitNavigator} /> jest.fn()} /> @@ -233,7 +233,7 @@ describe('Navigate', () => { index: 0, routes: [ { - name: SCREENS.SEARCH.CENTRAL_PANE, + name: SCREENS.SEARCH.ROOT, params: { q: 'type:expense status:all sortBy:date sortOrder:desc policyID:1', }, @@ -246,7 +246,7 @@ describe('Navigate', () => { const rootStateBeforeNavigate = navigationRef.current?.getRootState(); const lastSplitBeforeNavigate = rootStateBeforeNavigate?.routes.at(-1); expect(rootStateBeforeNavigate?.index).toBe(0); - expect(lastSplitBeforeNavigate?.name).toBe(SCREENS.SEARCH.CENTRAL_PANE); + expect(lastSplitBeforeNavigate?.name).toBe(SCREENS.SEARCH.ROOT); // When navigate to the Home page when the active workspace is set act(() => { diff --git a/tests/navigation/SwitchPolicyIDTests.tsx b/tests/navigation/SwitchPolicyIDTests.tsx index 50778b8fe698..b041f3046899 100644 --- a/tests/navigation/SwitchPolicyIDTests.tsx +++ b/tests/navigation/SwitchPolicyIDTests.tsx @@ -4,7 +4,7 @@ import {act, render} from '@testing-library/react-native'; import React from 'react'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import createResponsiveStackNavigator from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator'; +import createRootStackNavigator from '@libs/Navigation/AppNavigator/createRootStackNavigator'; import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import navigationRef from '@libs/Navigation/navigationRef'; import type {AuthScreensParamList, ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; @@ -13,7 +13,7 @@ import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -const RootStack = createResponsiveStackNavigator(); +const RootStack = createRootStackNavigator(); const ReportsSplit = createSplitNavigator(); jest.mock('@hooks/useResponsiveLayout', () => jest.fn()); @@ -57,7 +57,7 @@ function TestNavigationContainer({initialState}: TestNavigationContainerProps) { component={ReportsSplitNavigator} /> jest.fn()} /> @@ -126,7 +126,7 @@ describe('Switch policy ID', () => { index: 0, routes: [ { - name: SCREENS.SEARCH.CENTRAL_PANE, + name: SCREENS.SEARCH.ROOT, params: { q: 'type:expense status:all sortBy:date sortOrder:desc', }, @@ -139,7 +139,7 @@ describe('Switch policy ID', () => { const rootStateBeforeSwitch = navigationRef.current?.getRootState(); expect(rootStateBeforeSwitch?.index).toBe(0); const lastRouteBeforeSwitch = rootStateBeforeSwitch?.routes?.at(-1); - expect(lastRouteBeforeSwitch?.name).toBe(SCREENS.SEARCH.CENTRAL_PANE); + expect(lastRouteBeforeSwitch?.name).toBe(SCREENS.SEARCH.ROOT); expect(lastRouteBeforeSwitch?.params).toMatchObject({q: 'type:expense status:all sortBy:date sortOrder:desc'}); // When switch to the specific policy from the Search page @@ -151,7 +151,7 @@ describe('Switch policy ID', () => { const rootStateAfterSwitch = navigationRef.current?.getRootState(); expect(rootStateAfterSwitch?.index).toBe(1); const lastRouteAfterSwitch = rootStateAfterSwitch?.routes?.at(-1); - expect(lastRouteAfterSwitch?.name).toBe(SCREENS.SEARCH.CENTRAL_PANE); + expect(lastRouteAfterSwitch?.name).toBe(SCREENS.SEARCH.ROOT); expect(lastRouteAfterSwitch?.params).toMatchObject({q: 'type:expense status:all sortBy:date sortOrder:desc policyID:1'}); }); }); @@ -212,7 +212,7 @@ describe('Switch policy ID', () => { index: 0, routes: [ { - name: SCREENS.SEARCH.CENTRAL_PANE, + name: SCREENS.SEARCH.ROOT, params: { q: 'type:expense status:all sortBy:date sortOrder:desc policyID:1', }, @@ -225,7 +225,7 @@ describe('Switch policy ID', () => { const rootStateBeforeSwitch = navigationRef.current?.getRootState(); expect(rootStateBeforeSwitch?.index).toBe(0); const lastRouteBeforeSwitch = rootStateBeforeSwitch?.routes?.at(-1); - expect(lastRouteBeforeSwitch?.name).toBe(SCREENS.SEARCH.CENTRAL_PANE); + expect(lastRouteBeforeSwitch?.name).toBe(SCREENS.SEARCH.ROOT); expect(lastRouteBeforeSwitch?.params).toMatchObject({q: 'type:expense status:all sortBy:date sortOrder:desc policyID:1'}); // When switch policy to the global from the Search page @@ -237,7 +237,7 @@ describe('Switch policy ID', () => { const rootStateAfterSwitch = navigationRef.current?.getRootState(); expect(rootStateAfterSwitch?.index).toBe(1); const lastRouteAfterSwitch = rootStateAfterSwitch?.routes?.at(-1); - expect(lastRouteAfterSwitch?.name).toBe(SCREENS.SEARCH.CENTRAL_PANE); + expect(lastRouteAfterSwitch?.name).toBe(SCREENS.SEARCH.ROOT); expect(lastRouteAfterSwitch?.params).toMatchObject({q: 'type:expense status:all sortBy:date sortOrder:desc'}); }); }); From 9c9d28ca9b912b714a0158b5a79dc46ce4cd71d5 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 10 Jan 2025 11:05:22 +0100 Subject: [PATCH 254/257] Move TestNavigationContainer to test utils --- tests/navigation/GoBackTests.tsx | 82 +--------------------- tests/navigation/NavigateTests.tsx | 82 +--------------------- tests/navigation/SwitchPolicyIDTests.tsx | 50 +------------- tests/utils/TestNavigationContainer.tsx | 87 ++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 211 deletions(-) create mode 100644 tests/utils/TestNavigationContainer.tsx diff --git a/tests/navigation/GoBackTests.tsx b/tests/navigation/GoBackTests.tsx index 08483f6d01fd..8d5aaf747798 100644 --- a/tests/navigation/GoBackTests.tsx +++ b/tests/navigation/GoBackTests.tsx @@ -1,22 +1,14 @@ -import type {InitialState} from '@react-navigation/native'; -import {NavigationContainer} from '@react-navigation/native'; import {act, render} from '@testing-library/react-native'; import React from 'react'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import createRootStackNavigator from '@libs/Navigation/AppNavigator/createRootStackNavigator'; -import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import Navigation from '@libs/Navigation/Navigation'; import navigationRef from '@libs/Navigation/navigationRef'; -import type {AuthScreensParamList, ReportsSplitNavigatorParamList, SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; - -const RootStack = createRootStackNavigator(); -const ReportsSplit = createSplitNavigator(); -const SettingsSplit = createSplitNavigator(); +import TestNavigationContainer from '../utils/TestNavigationContainer'; jest.mock('@hooks/useResponsiveLayout', () => jest.fn()); jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); @@ -26,78 +18,6 @@ jest.mock('@pages/home/sidebar/BottomTabAvatar'); const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; -function SettingsSplitNavigator() { - return ( - - jest.fn()} - /> - jest.fn()} - /> - jest.fn()} - /> - jest.fn()} - /> - - ); -} - -function ReportsSplitNavigator() { - return ( - - jest.fn()} - /> - jest.fn()} - /> - - ); -} - -type TestNavigationContainerProps = {initialState: InitialState}; - -function TestNavigationContainer({initialState}: TestNavigationContainerProps) { - return ( - - - - - jest.fn()} - /> - - - ); -} - describe('Go back on the narrow layout', () => { beforeEach(() => { mockedGetIsNarrowLayout.mockReturnValue(true); diff --git a/tests/navigation/NavigateTests.tsx b/tests/navigation/NavigateTests.tsx index f4bc3be4a001..0a290b4ce9a0 100644 --- a/tests/navigation/NavigateTests.tsx +++ b/tests/navigation/NavigateTests.tsx @@ -1,22 +1,14 @@ -import type {InitialState} from '@react-navigation/native'; -import {NavigationContainer} from '@react-navigation/native'; import {act, render} from '@testing-library/react-native'; import React from 'react'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import createRootStackNavigator from '@libs/Navigation/AppNavigator/createRootStackNavigator'; -import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import Navigation from '@libs/Navigation/Navigation'; import navigationRef from '@libs/Navigation/navigationRef'; -import type {AuthScreensParamList, ReportsSplitNavigatorParamList, SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; - -const RootStack = createRootStackNavigator(); -const ReportsSplit = createSplitNavigator(); -const SettingsSplit = createSplitNavigator(); +import TestNavigationContainer from '../utils/TestNavigationContainer'; jest.mock('@hooks/useResponsiveLayout', () => jest.fn()); jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); @@ -26,78 +18,6 @@ jest.mock('@pages/home/sidebar/BottomTabAvatar'); const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; -function SettingsSplitNavigator() { - return ( - - jest.fn()} - /> - jest.fn()} - /> - jest.fn()} - /> - jest.fn()} - /> - - ); -} - -function ReportsSplitNavigator() { - return ( - - jest.fn()} - /> - jest.fn()} - /> - - ); -} - -type TestNavigationContainerProps = {initialState: InitialState}; - -function TestNavigationContainer({initialState}: TestNavigationContainerProps) { - return ( - - - - - jest.fn()} - /> - - - ); -} - describe('Navigate', () => { beforeEach(() => { mockedGetIsNarrowLayout.mockReturnValue(true); diff --git a/tests/navigation/SwitchPolicyIDTests.tsx b/tests/navigation/SwitchPolicyIDTests.tsx index b041f3046899..61900c2fb817 100644 --- a/tests/navigation/SwitchPolicyIDTests.tsx +++ b/tests/navigation/SwitchPolicyIDTests.tsx @@ -1,20 +1,13 @@ -import type {InitialState} from '@react-navigation/native'; -import {NavigationContainer} from '@react-navigation/native'; import {act, render} from '@testing-library/react-native'; import React from 'react'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; -import createRootStackNavigator from '@libs/Navigation/AppNavigator/createRootStackNavigator'; -import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import navigationRef from '@libs/Navigation/navigationRef'; -import type {AuthScreensParamList, ReportsSplitNavigatorParamList} from '@libs/Navigation/types'; import switchPolicyAfterInteractions from '@pages/WorkspaceSwitcherPage/switchPolicyAfterInteractions'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; - -const RootStack = createRootStackNavigator(); -const ReportsSplit = createSplitNavigator(); +import TestNavigationContainer from '../utils/TestNavigationContainer'; jest.mock('@hooks/useResponsiveLayout', () => jest.fn()); jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); @@ -24,47 +17,6 @@ jest.mock('@pages/home/sidebar/BottomTabAvatar'); const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; -function ReportsSplitNavigator() { - return ( - - jest.fn()} - /> - jest.fn()} - /> - - ); -} - -type TestNavigationContainerProps = {initialState: InitialState}; - -function TestNavigationContainer({initialState}: TestNavigationContainerProps) { - return ( - - - - jest.fn()} - /> - - - ); -} - describe('Switch policy ID', () => { beforeEach(() => { mockedGetIsNarrowLayout.mockReturnValue(true); diff --git a/tests/utils/TestNavigationContainer.tsx b/tests/utils/TestNavigationContainer.tsx new file mode 100644 index 000000000000..9f19ca4658a0 --- /dev/null +++ b/tests/utils/TestNavigationContainer.tsx @@ -0,0 +1,87 @@ +import type {InitialState} from '@react-navigation/native'; +import {NavigationContainer} from '@react-navigation/native'; +import React from 'react'; +import createRootStackNavigator from '@libs/Navigation/AppNavigator/createRootStackNavigator'; +import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; +import navigationRef from '@libs/Navigation/navigationRef'; +import type {AuthScreensParamList, ReportsSplitNavigatorParamList, SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; +import CONST from '@src/CONST'; +import NAVIGATORS from '@src/NAVIGATORS'; +import SCREENS from '@src/SCREENS'; + +const RootStack = createRootStackNavigator(); +const ReportsSplit = createSplitNavigator(); +const SettingsSplit = createSplitNavigator(); + +type TestNavigationContainerProps = {initialState: InitialState}; + +function TestReportsSplitNavigator() { + return ( + + jest.fn()} + /> + jest.fn()} + /> + + ); +} + +function TestSettingsSplitNavigator() { + return ( + + jest.fn()} + /> + jest.fn()} + /> + jest.fn()} + /> + jest.fn()} + /> + + ); +} + +function TestNavigationContainer({initialState}: TestNavigationContainerProps) { + return ( + + + + + jest.fn()} + /> + + + ); +} +export default TestNavigationContainer; From 6589e68185dd1a5a36f38b65cfec1f476d095b51 Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 10 Jan 2025 14:16:11 +0100 Subject: [PATCH 255/257] fix tests --- tests/ui/LHNItemsPresence.tsx | 10 ++++++++++ tests/ui/WorkspaceCategoriesTest.tsx | 10 +++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/tests/ui/LHNItemsPresence.tsx b/tests/ui/LHNItemsPresence.tsx index 8e3e8d2b702b..4be4a311c658 100644 --- a/tests/ui/LHNItemsPresence.tsx +++ b/tests/ui/LHNItemsPresence.tsx @@ -1,3 +1,4 @@ +import type * as reactNavigationNativeImport from '@react-navigation/native'; import {screen} from '@testing-library/react-native'; import type {ComponentType} from 'react'; import Onyx from 'react-native-onyx'; @@ -24,6 +25,15 @@ import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatch jest.mock('@libs/Permissions'); jest.mock('@hooks/useActiveWorkspace', () => jest.fn(() => ({activeWorkspaceID: undefined}))); +jest.mock('@react-navigation/native', () => ({ + ...jest.requireActual('@react-navigation/native'), + useNavigationState: () => undefined, + useIsFocused: () => true, + useRoute: () => ({name: 'Home'}), + useNavigation: () => undefined, + useFocusEffect: () => undefined, +})); + type LazyLoadLHNTestUtils = { fakePersonalDetails: PersonalDetailsList; }; diff --git a/tests/ui/WorkspaceCategoriesTest.tsx b/tests/ui/WorkspaceCategoriesTest.tsx index fc34be67f173..cdcba7295c0e 100644 --- a/tests/ui/WorkspaceCategoriesTest.tsx +++ b/tests/ui/WorkspaceCategoriesTest.tsx @@ -10,7 +10,7 @@ import {CurrentReportIDContextProvider} from '@hooks/useCurrentReportID'; import * as useResponsiveLayoutModule from '@hooks/useResponsiveLayout'; import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; import * as Localize from '@libs/Localize'; -import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; +import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator'; import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; import WorkspaceCategoriesPage from '@pages/workspace/categories/WorkspaceCategoriesPage'; import CONST from '@src/CONST'; @@ -22,20 +22,20 @@ import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct' TestHelper.setupGlobalFetchMock(); -const Split = createSplitNavigator(); +const Stack = createPlatformStackNavigator(); const renderPage = (initialRouteName: typeof SCREENS.WORKSPACE.CATEGORIES, initialParams: WorkspaceSplitNavigatorParamList[typeof SCREENS.WORKSPACE.CATEGORIES]) => { return render( - - + - + , From f05d53c5ee52b19f9c072a534599e4ae6e0cdccd Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 10 Jan 2025 14:17:19 +0100 Subject: [PATCH 256/257] fix lint --- src/components/Navigation/BottomTabBar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Navigation/BottomTabBar/index.tsx b/src/components/Navigation/BottomTabBar/index.tsx index df8f178c06c0..f8c2e70bdf6c 100644 --- a/src/components/Navigation/BottomTabBar/index.tsx +++ b/src/components/Navigation/BottomTabBar/index.tsx @@ -5,6 +5,7 @@ import {useOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; +import DebugTabView from '@components/Navigation/DebugTabView'; import {PressableWithFeedback} from '@components/Pressable'; import {useProductTrainingContext} from '@components/ProductTrainingContext'; import type {SearchQueryString} from '@components/Search/types'; @@ -35,7 +36,6 @@ import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; -import DebugTabView from '../DebugTabView'; import BOTTOM_TABS from './BOTTOM_TABS'; type BottomTabName = ValueOf; From 8648ce71f61cb8de918e5d21de49b0f9922dba1c Mon Sep 17 00:00:00 2001 From: Adam Grzybowski Date: Fri, 10 Jan 2025 15:44:17 +0100 Subject: [PATCH 257/257] fix tests v2 --- tests/unit/SidebarOrderTest.ts | 9 +++++++++ tests/utils/LHNTestUtils.tsx | 1 + 2 files changed, 10 insertions(+) diff --git a/tests/unit/SidebarOrderTest.ts b/tests/unit/SidebarOrderTest.ts index ca38f9b8e64e..7e29dd78a566 100644 --- a/tests/unit/SidebarOrderTest.ts +++ b/tests/unit/SidebarOrderTest.ts @@ -1,3 +1,4 @@ +import type * as reactNavigationNativeImport from '@react-navigation/native'; import {screen} from '@testing-library/react-native'; import Onyx from 'react-native-onyx'; import * as Report from '@libs/actions/Report'; @@ -16,6 +17,14 @@ import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatch jest.mock('@libs/Permissions'); jest.mock('@components/Icon/Expensicons'); jest.mock('@src/hooks/useResponsiveLayout'); +jest.mock('@react-navigation/native', () => ({ + ...jest.requireActual('@react-navigation/native'), + useNavigationState: () => true, + useIsFocused: () => true, + useRoute: () => ({name: 'Home'}), + useNavigation: () => undefined, + useFocusEffect: () => undefined, +})); describe('Sidebar', () => { beforeAll(() => diff --git a/tests/utils/LHNTestUtils.tsx b/tests/utils/LHNTestUtils.tsx index 0d2613ea7739..2818aa49545f 100644 --- a/tests/utils/LHNTestUtils.tsx +++ b/tests/utils/LHNTestUtils.tsx @@ -38,6 +38,7 @@ jest.mock('@react-navigation/native', () => { const actualNav = jest.requireActual('@react-navigation/native'); return { ...actualNav, + useNavigationState: () => true, useRoute: jest.fn(), useFocusEffect: jest.fn(), useIsFocused: () => true,