diff --git a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts index 6e97bb18cfaa..8ff509cd5269 100644 --- a/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts +++ b/src/libs/Navigation/AppNavigator/createSplitStackNavigator/SplitStackRouter.ts @@ -4,6 +4,7 @@ import pick from 'lodash/pick'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import getParamsFromRoute from '@libs/Navigation/linkingConfig/getParamsFromRoute'; import navigationRef from '@libs/Navigation/navigationRef'; +import SCREENS from '@src/SCREENS'; import type {SplitStackNavigatorRouterOptions} from './types'; import {getPreservedSplitNavigatorState} from './usePreserveSplitNavigatorState'; @@ -26,6 +27,16 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc // - defaultCentralScreen to cover central pane. if (!isAtLeastOneInState(state, sidebarScreen) && !isNarrowLayout) { const paramsFromRoute = getParamsFromRoute(sidebarScreen); + let params = pick(lastRoute?.params, paramsFromRoute); + + // On a wide screen the backTo param has to be passed to the sidebar screen (SCREENS.WORKSPACE.INITIAL), because the back action is performed from this page + if (lastRoute?.name === SCREENS.WORKSPACE.PROFILE) { + const hasRouteBackToParam = lastRoute?.params && 'backTo' in lastRoute.params; + + if (hasRouteBackToParam) { + params = {...params, backTo: lastRoute.params.backTo}; + } + } // @ts-expect-error Updating read only property // noinspection JSConstantReassignment @@ -37,7 +48,7 @@ function adaptStateIfNecessary({state, options: {sidebarScreen, defaultCentralSc state.routes.unshift({ name: sidebarScreen, // This handles the case where the sidebar should have params included in the central screen e.g. policyID for workspace initial. - params: pick(lastRoute?.params, paramsFromRoute), + params, }); } } diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index c9bfd2195e8b..44aa98afdc96 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -6,6 +6,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {Writable} from 'type-fest'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import Log from '@libs/Log'; +import {isSplitNavigatorRoute} from '@libs/NavigationUtils'; import {shallowCompare} from '@libs/ObjectUtils'; import getPolicyEmployeeAccountIDs from '@libs/PolicyEmployeeListUtils'; import * as ReportConnection from '@libs/ReportConnection'; @@ -299,7 +300,7 @@ function goBack(fallbackRoute?: Route, shouldEnforceFallback = false, shouldPopT const canGoBack = navigationRef.current?.canGoBack(); - if (!canGoBack && lastRoute?.name.endsWith('SplitNavigator') && lastRoute?.state?.routes?.length === 1) { + if (!canGoBack && isSplitNavigatorRoute(lastRoute as NavigationPartialRoute) && lastRoute?.state?.routes?.length === 1) { const splitNavigatorName = lastRoute?.name as keyof SplitNavigatorParamListType; const name = SPLIT_NAVIGATOR_TO_SIDEBAR_MAP[splitNavigatorName]; const params = getSidebarScreenParams(lastRoute); diff --git a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts b/src/libs/Navigation/linkingConfig/createSplitNavigator.ts index aa1a1bef6760..c2d09d28dc87 100644 --- a/src/libs/Navigation/linkingConfig/createSplitNavigator.ts +++ b/src/libs/Navigation/linkingConfig/createSplitNavigator.ts @@ -10,7 +10,7 @@ const getRoutesWithIndex = (routes: NavigationPartialRoute[]): PartialState( splitNavigatorLHN: NavigationPartialRoute, route?: NavigationPartialRoute>, - splitNavigatorParams?: SplitNavigatorParamListType[SplitNavigatorByLHN], + splitNavigatorParams?: Record, ): NavigationPartialRoute> { const routes = []; diff --git a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts index 74c38d130ad6..8d0134360d7d 100644 --- a/src/libs/Navigation/linkingConfig/customGetPathFromState.ts +++ b/src/libs/Navigation/linkingConfig/customGetPathFromState.ts @@ -1,21 +1,21 @@ import {getPathFromState} from '@react-navigation/native'; -import type {RootStackParamList, State} from '@libs/Navigation/types'; -import {removePolicyIDParamFromState} from '@libs/NavigationUtils'; +import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types'; +import {isFullScreenRoute, removePolicyIDParamFromState} from '@libs/NavigationUtils'; import NAVIGATORS from '@src/NAVIGATORS'; const customGetPathFromState: typeof getPathFromState = (state, options) => { // For the Home page we should remove policyID from the params, because on small screens it's displayed twice in the URL const stateWithoutPolicyID = removePolicyIDParamFromState(state as State); const path = getPathFromState(stateWithoutPolicyID, options); - const topmostRoute = state.routes.at(-1); + const fullScreenRoute = state.routes.findLast((route) => isFullScreenRoute(route as NavigationPartialRoute)); - const shouldAddPolicyID = !!topmostRoute && topmostRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; + const shouldAddPolicyID = fullScreenRoute?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; if (!shouldAddPolicyID) { return path; } - const policyID = topmostRoute.params && `policyID` in topmostRoute.params ? (topmostRoute.params.policyID as string) : undefined; + const policyID = fullScreenRoute.params && `policyID` in fullScreenRoute.params ? (fullScreenRoute.params.policyID as string) : undefined; return `${policyID ? `/w/${policyID}` : ''}${path}`; }; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 9c883dde2219..ceb9aa9ca625 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -3,6 +3,7 @@ import {findFocusedRoute, getStateFromPath} from '@react-navigation/native'; import pick from 'lodash/pick'; import {isAnonymousUser} from '@libs/actions/Session'; import type {NavigationPartialRoute, RootStackParamList, SettingsSplitNavigatorParamList, WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; +import {isFullScreenRoute} from '@libs/NavigationUtils'; import {extractPolicyIDFromPath, getPathWithoutPolicyID} from '@libs/PolicyUtils'; import * as ReportConnection from '@libs/ReportConnection'; import extractPolicyIDFromQuery from '@navigation/extractPolicyIDFromQuery'; @@ -32,9 +33,11 @@ function isRouteWithReportID(route: NavigationPartialRoute): route is Route>) { +function getMatchingFullScreenRouteForState(state: PartialState>, policyID?: string) { const focusedRoute = findFocusedRoute(state); + const reportSplitParams = policyID ? {policyID} : undefined; + if (!focusedRoute) { return undefined; } @@ -57,7 +60,7 @@ function getMatchingFullScreenRouteForState(state: PartialState>); + return getMatchingFullScreenRouteForState(stateForBackTo as PartialState>, policyID); } if (RELATIONS.SEARCH_TO_RHP.includes(focusedRoute.name)) { @@ -71,9 +74,13 @@ function getMatchingFullScreenRouteForState(state: PartialState>, policyID?: string): GetAdaptedStateReturnType { const fullScreenRoute = state.routes.find(isFullScreenRoute); const reportsSplitNavigator = state.routes.find((route) => route.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); @@ -159,8 +161,7 @@ function getAdaptedState(state: PartialState // If there is no full screen route in the root, we want to add it. if (!fullScreenRoute) { - const matchingRootRoute = getMatchingFullScreenRouteForState(state); - + const matchingRootRoute = getMatchingFullScreenRouteForState(state, policyID); // If there is a matching root route, add it to the state. if (matchingRootRoute) { return { @@ -168,9 +169,11 @@ function getAdaptedState(state: PartialState }; } + const reportSplitParams = policyID ? {policyID} : undefined; + // If not, add the default full screen route. return { - adaptedState: getRoutesWithIndex([{name: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR}, ...state.routes]), + adaptedState: getRoutesWithIndex([{name: NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, params: reportSplitParams}, ...state.routes]), }; } diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index aae0c52adbf0..c4c88fb99fa6 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1581,8 +1581,12 @@ type CentralPaneName = keyof CentralPaneScreensParamList; type OnboardingFlowName = keyof OnboardingModalNavigatorParamList; +type SplitNavigatorName = keyof SplitNavigatorParamListType; + type SplitNavigatorScreenName = keyof (WorkspaceSplitNavigatorParamList & SettingsSplitNavigatorParamList & ReportsSplitNavigatorParamList); +type FullScreenName = SplitNavigatorName | typeof SCREENS.SEARCH.CENTRAL_PANE; + type SwitchPolicyIDParams = { policyID?: string; route?: Routes; @@ -1657,7 +1661,9 @@ export type { RestrictedActionParamList, MissingPersonalDetailsParamList, DebugParamList, + SplitNavigatorName, SplitNavigatorScreenName, + FullScreenName, SplitNavigatorLHNScreen, SplitNavigatorParamListType, SplitNavigatorByLHN, diff --git a/src/libs/NavigationUtils.ts b/src/libs/NavigationUtils.ts index ea1710b9931c..e11255314c86 100644 --- a/src/libs/NavigationUtils.ts +++ b/src/libs/NavigationUtils.ts @@ -1,7 +1,14 @@ import cloneDeep from 'lodash/cloneDeep'; +import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import getTopmostBottomTabRoute from './Navigation/getTopmostBottomTabRoute'; -import type {CentralPaneName, OnboardingFlowName, RootStackParamList, State} from './Navigation/types'; +import type {CentralPaneName, FullScreenName, NavigationPartialRoute, OnboardingFlowName, RootStackParamList, SplitNavigatorName, State} from './Navigation/types'; + +const SPLIT_NAVIGATORS = [NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR]; + +const SPLIT_NAVIGATORS_SET = new Set(SPLIT_NAVIGATORS); + +const FULL_SCREEN_ROUTES_SET = new Set([...SPLIT_NAVIGATORS, SCREENS.SEARCH.CENTRAL_PANE]); const CENTRAL_PANE_SCREEN_NAMES = new Set([ SCREENS.SETTINGS.WORKSPACES, @@ -43,4 +50,20 @@ function isOnboardingFlowName(screen: string | undefined): screen is OnboardingF return ONBOARDING_SCREEN_NAMES.has(screen as OnboardingFlowName); } -export {isCentralPaneName, removePolicyIDParamFromState, isOnboardingFlowName}; +function isSplitNavigatorRoute(route: NavigationPartialRoute | undefined): route is NavigationPartialRoute { + if (!route?.name) { + return false; + } + + return SPLIT_NAVIGATORS_SET.has(route.name as SplitNavigatorName); +} + +function isFullScreenRoute(route: NavigationPartialRoute | undefined): route is NavigationPartialRoute { + if (!route?.name) { + return false; + } + + return FULL_SCREEN_ROUTES_SET.has(route.name as FullScreenName); +} + +export {isCentralPaneName, removePolicyIDParamFromState, isOnboardingFlowName, isFullScreenRoute, isSplitNavigatorRoute};