From 4fe5789c76351343d0435827dd0ee06f736376f0 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 30 Sep 2024 13:18:10 +0200 Subject: [PATCH 01/22] 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 02/22] 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 03/22] 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 04/22] 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 05/22] 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 06/22] 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 07/22] 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 08/22] 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 09/22] 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 10/22] 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 11/22] 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 12/22] 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 13/22] 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 14/22] 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 15/22] 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 16/22] 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 17/22] 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 18/22] 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 19/22] 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 20/22] 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 21/22] 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 22/22] 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;