diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 8a204ab436b3..d4a4f6f54d59 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -24,7 +24,7 @@ import originalCloseRHPFlow from './helpers/closeRHPFlow'; import getPolicyIDFromState from './helpers/getPolicyIDFromState'; import getStateFromPath from './helpers/getStateFromPath'; import getTopmostReportParams from './helpers/getTopmostReportParams'; -import {isFullScreenName, isOnboardingFlowName} from './helpers/isNavigatorName'; +import {isFullScreenName, isOnboardingFlowName, isSplitNavigatorName} from './helpers/isNavigatorName'; import isReportOpenInRHP from './helpers/isReportOpenInRHP'; import isSideModalNavigator from './helpers/isSideModalNavigator'; import linkTo from './helpers/linkTo'; @@ -34,6 +34,7 @@ import replaceWithSplitNavigator from './helpers/replaceWithSplitNavigator'; import setNavigationActionToMicrotaskQueue from './helpers/setNavigationActionToMicrotaskQueue'; import switchPolicyID from './helpers/switchPolicyID'; import {linkingConfig} from './linkingConfig'; +import {SPLIT_TO_SIDEBAR} from './linkingConfig/RELATIONS'; import navigationRef from './navigationRef'; import type {NavigationPartialRoute, NavigationRoute, NavigationStateRoute, RootNavigatorParamList, State} from './types'; @@ -73,13 +74,21 @@ const navigationIsReadyPromise = new Promise((resolve) => { let pendingRoute: Route | null = null; -let shouldPopAllStateOnUP = false; +let shouldPopToSidebar = false; /** * Inform the navigation that next time user presses UP we should pop all the state back to LHN. */ -function setShouldPopAllStateOnUP(shouldPopAllStateFlag: boolean) { - shouldPopAllStateOnUP = shouldPopAllStateFlag; +function setShouldPopToSidebar(shouldPopAllStateFlag: boolean) { + shouldPopToSidebar = shouldPopAllStateFlag; +} + +/** + * Returns shouldPopToSidebar variable used to determine whether should we pop all state back to LHN + * @returns shouldPopToSidebar + */ +function getShouldPopToSidebar() { + return shouldPopToSidebar; } type CanNavigateParams = { @@ -265,17 +274,10 @@ type GoBackOptions = { * In that case we want to goUp to a country picker with any params so we don't compare them. */ compareParams?: boolean; - - /** - * Specifies whether goBack should pop to top when invoked. - * Additionaly, to execute popToTop, set the value of the global variable ShouldPopAllStateOnUP to true using the setShouldPopAllStateOnUP function. - */ - shouldPopToTop?: boolean; }; const defaultGoBackOptions: Required = { compareParams: true, - shouldPopToTop: false, }; /** @@ -344,14 +346,6 @@ function goBack(backToRoute?: Route, options?: GoBackOptions) { return; } - if (options?.shouldPopToTop) { - if (shouldPopAllStateOnUP) { - shouldPopAllStateOnUP = false; - navigationRef.current?.dispatch(StackActions.popToTop()); - return; - } - } - if (backToRoute) { goUp(backToRoute, options); return; @@ -365,6 +359,38 @@ function goBack(backToRoute?: Route, options?: GoBackOptions) { navigationRef.current?.goBack(); } +function popToSidebar() { + setShouldPopToSidebar(false); + + const rootState = navigationRef.current?.getRootState(); + const currentRoute = rootState?.routes.at(-1); + + if (!currentRoute) { + Log.hmmm('[popToSidebar] Unable to pop to sidebar, no current root found in navigator'); + return; + } + + if (!isSplitNavigatorName(currentRoute?.name)) { + Log.hmmm('[popToSidebar] must be invoked only from SplitNavigator'); + return; + } + + const topRoute = currentRoute.state?.routes.at(0); + const lastRoute = currentRoute.state?.routes.at(-1); + + const currentRouteName = currentRoute?.name as keyof typeof SPLIT_TO_SIDEBAR; + if (topRoute?.name !== SPLIT_TO_SIDEBAR[currentRouteName]) { + const params = currentRoute.name === NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR ? {...lastRoute?.params} : undefined; + + const sidebarName = SPLIT_TO_SIDEBAR[currentRouteName]; + + navigationRef.dispatch({payload: {name: sidebarName, params}, type: CONST.NAVIGATION.ACTION_TYPE.REPLACE}); + return; + } + + navigationRef.current?.dispatch(StackActions.popToTop()); +} + /** * Reset the navigation state to Home page. */ @@ -616,15 +642,15 @@ const dismissModalWithReport = (navigateToReportPayload: NavigateToReportWithPol }; /** - * Returns to the first screen in the stack, dismissing all the others, only if the global variable shouldPopAllStateOnUP is set to true. + * Returns to the first screen in the stack, dismissing all the others, only if the global variable shouldPopToSidebar is set to true. */ function popToTop() { - if (!shouldPopAllStateOnUP) { + if (!shouldPopToSidebar) { goBack(); return; } - shouldPopAllStateOnUP = false; + shouldPopToSidebar = false; navigationRef.current?.dispatch(StackActions.popToTop()); } @@ -671,7 +697,9 @@ function isOnboardingFlow() { } export default { - setShouldPopAllStateOnUP, + setShouldPopToSidebar, + getShouldPopToSidebar, + popToSidebar, navigate, setParams, dismissModal, diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 4a7b83e12bf9..8e5b5739debd 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -169,14 +169,14 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady}: N return; } - // After resizing the screen from wide to narrow, if we have visited multiple central screens, we want to go back to the LHN screen, so we set shouldPopAllStateOnUP to true. + // After resizing the screen from wide to narrow, if we have visited multiple central screens, we want to go back to the LHN screen, so we set shouldPopToSidebar to true. // Now when this value is true, Navigation.goBack with the option {shouldPopToTop: true} will remove all visited central screens in the given tab from the navigation stack and go back to the LHN. // More context here: https://github.com/Expensify/App/pull/59300 if (!shouldUseNarrowLayout) { return; } - Navigation.setShouldPopAllStateOnUP(true); + Navigation.setShouldPopToSidebar(true); }, [shouldUseNarrowLayout]); useEffect(() => { diff --git a/src/libs/Navigation/helpers/goBackFromWorkspaceCentralScreen.ts b/src/libs/Navigation/helpers/goBackFromWorkspaceCentralScreen.ts deleted file mode 100644 index 5324bff9be0e..000000000000 --- a/src/libs/Navigation/helpers/goBackFromWorkspaceCentralScreen.ts +++ /dev/null @@ -1,28 +0,0 @@ -import Log from '@libs/Log'; -import Navigation from '@libs/Navigation/Navigation'; -import navigationRef from '@libs/Navigation/navigationRef'; -import NAVIGATORS from '@src/NAVIGATORS'; -import ROUTES from '@src/ROUTES'; - -/** - * If there are already other screens open in WorkspaceSplitNavigator, we return to the previous one. - * If not, from the central screen in WorkspaceSplitNavigator we should return to the WorkspaceInitialPage. - */ -function goBackFromWorkspaceCentralScreen(policyID: string | undefined) { - const rootState = navigationRef.getRootState(); - const lastRoute = rootState.routes.at(-1); - - if (lastRoute?.name !== NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR) { - Log.hmmm('[goBackFromWorkspaceCentralScreen] goBackFromWorkspaceCentralScreen was called from a different navigator than WorkspaceSplitNavigator.'); - return; - } - - if (lastRoute.state?.routes && lastRoute.state.routes.length > 1) { - Navigation.goBack(undefined, {shouldPopToTop: true}); - return; - } - - Navigation.goBack(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); -} - -export default goBackFromWorkspaceCentralScreen; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index d1eb658bee70..afa7148ba752 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2906,8 +2906,7 @@ function deleteReport(reportID: string | undefined, shouldDeleteChildReports = f function navigateToConciergeChatAndDeleteReport(reportID: string | undefined, shouldPopToTop = false, shouldDeleteChildReports = false) { // Dismiss the current report screen and replace it with Concierge Chat if (shouldPopToTop) { - Navigation.setShouldPopAllStateOnUP(true); - Navigation.goBack(undefined, {shouldPopToTop: true}); + Navigation.popToSidebar(); } else { Navigation.goBack(); } diff --git a/src/libs/navigateAfterJoinRequest.ts b/src/libs/navigateAfterJoinRequest.ts index 3e99948ca85d..6605de8ee656 100644 --- a/src/libs/navigateAfterJoinRequest.ts +++ b/src/libs/navigateAfterJoinRequest.ts @@ -2,7 +2,11 @@ import ROUTES from '@src/ROUTES'; import Navigation from './Navigation/Navigation'; const navigateAfterJoinRequest = () => { - Navigation.goBack(undefined, {shouldPopToTop: true}); + if (Navigation.getShouldPopToSidebar()) { + Navigation.popToSidebar(); + } else { + Navigation.goBack(); + } Navigation.setNavigationActionToMicrotaskQueue(() => { Navigation.navigate(ROUTES.SETTINGS_WORKSPACES.route); }); diff --git a/src/pages/TeachersUnite/SaveTheWorldPage.tsx b/src/pages/TeachersUnite/SaveTheWorldPage.tsx index ce4c8b230f3c..dcdab230d899 100644 --- a/src/pages/TeachersUnite/SaveTheWorldPage.tsx +++ b/src/pages/TeachersUnite/SaveTheWorldPage.tsx @@ -57,7 +57,7 @@ function SaveTheWorldPage() { title={translate('sidebarScreen.saveTheWorld')} shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter - onBackButtonPress={() => Navigation.goBack(undefined, {shouldPopToTop: true})} + onBackButtonPress={Navigation.popToSidebar} icon={Illustrations.TeachersUnite} shouldUseHeadlineHeader /> diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 536997bad08d..87f8a4a6aeec 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -330,11 +330,15 @@ function ReportScreen({route, navigation}: ReportScreenProps) { Navigation.dismissModal(); return; } + if (Navigation.getShouldPopToSidebar()) { + Navigation.popToSidebar(); + return; + } if (backTo) { - Navigation.goBack(backTo as Route, {shouldPopToTop: true}); + Navigation.goBack(backTo as Route); return; } - Navigation.goBack(undefined, {shouldPopToTop: true}); + Navigation.goBack(); }, [isInNarrowPaneModal, backTo]); let headerView = ( @@ -589,9 +593,8 @@ function ReportScreen({route, navigation}: ReportScreenProps) { } Navigation.dismissModal(); if (Navigation.getTopmostReportId() === prevOnyxReportID) { - Navigation.setShouldPopAllStateOnUP(true); Navigation.isNavigationReady().then(() => { - Navigation.goBack(undefined, {shouldPopToTop: true}); + Navigation.popToSidebar(); }); } if (prevReport?.parentReportID) { diff --git a/src/pages/settings/AboutPage/AboutPage.tsx b/src/pages/settings/AboutPage/AboutPage.tsx index a0f86c2c2e26..b045e66e107f 100644 --- a/src/pages/settings/AboutPage/AboutPage.tsx +++ b/src/pages/settings/AboutPage/AboutPage.tsx @@ -142,7 +142,7 @@ function AboutPage() { title={translate('initialSettingsPage.about')} shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter - onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS, {shouldPopToTop: true})} + onBackButtonPress={Navigation.popToSidebar} icon={Illustrations.PalmTree} shouldUseHeadlineHeader /> diff --git a/src/pages/settings/Preferences/PreferencesPage.tsx b/src/pages/settings/Preferences/PreferencesPage.tsx index 2a24f657fbca..53ff9f71c643 100755 --- a/src/pages/settings/Preferences/PreferencesPage.tsx +++ b/src/pages/settings/Preferences/PreferencesPage.tsx @@ -53,7 +53,7 @@ function PreferencesPage() { shouldUseHeadlineHeader shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter - onBackButtonPress={() => Navigation.goBack(undefined, {shouldPopToTop: true})} + onBackButtonPress={Navigation.popToSidebar} /> diff --git a/src/pages/settings/Profile/ProfilePage.tsx b/src/pages/settings/Profile/ProfilePage.tsx index 30b39fba2536..d33bd317ac15 100755 --- a/src/pages/settings/Profile/ProfilePage.tsx +++ b/src/pages/settings/Profile/ProfilePage.tsx @@ -152,7 +152,13 @@ function ProfilePage() { > Navigation.goBack(route.params?.backTo, {shouldPopToTop: true})} + onBackButtonPress={() => { + if (Navigation.getShouldPopToSidebar()) { + Navigation.popToSidebar(); + return; + } + Navigation.goBack(route.params?.backTo); + }} shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter icon={Illustrations.Profile} diff --git a/src/pages/settings/Security/SecuritySettingsPage.tsx b/src/pages/settings/Security/SecuritySettingsPage.tsx index 9ec999949fef..cf44d1864ff8 100644 --- a/src/pages/settings/Security/SecuritySettingsPage.tsx +++ b/src/pages/settings/Security/SecuritySettingsPage.tsx @@ -52,7 +52,7 @@ function SecuritySettingsPage() { const personalDetails = usePersonalDetails(); const {canUseMergeAccounts} = usePermissions(); - const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: true}); const delegateButtonRef = useRef(null); const [shouldShowDelegatePopoverMenu, setShouldShowDelegatePopoverMenu] = useState(false); @@ -265,7 +265,7 @@ function SecuritySettingsPage() { Navigation.goBack(undefined, {shouldPopToTop: true})} + onBackButtonPress={Navigation.popToSidebar} icon={Illustrations.LockClosed} shouldUseHeadlineHeader shouldDisplaySearchRouter diff --git a/src/pages/settings/Subscription/SubscriptionSettingsPage.tsx b/src/pages/settings/Subscription/SubscriptionSettingsPage.tsx index 283b101d810a..03e80b5f35e0 100644 --- a/src/pages/settings/Subscription/SubscriptionSettingsPage.tsx +++ b/src/pages/settings/Subscription/SubscriptionSettingsPage.tsx @@ -49,7 +49,13 @@ function SubscriptionSettingsPage({route}: SubscriptionSettingsPageProps) { > Navigation.goBack(backTo, {shouldPopToTop: true})} + onBackButtonPress={() => { + if (Navigation.getShouldPopToSidebar()) { + Navigation.popToSidebar(); + return; + } + Navigation.goBack(backTo); + }} shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter icon={Illustrations.CreditCardsNew} diff --git a/src/pages/settings/Troubleshoot/TroubleshootPage.tsx b/src/pages/settings/Troubleshoot/TroubleshootPage.tsx index d23348bcad9d..ccd292db3a89 100644 --- a/src/pages/settings/Troubleshoot/TroubleshootPage.tsx +++ b/src/pages/settings/Troubleshoot/TroubleshootPage.tsx @@ -52,8 +52,8 @@ function TroubleshootPage() { const {shouldUseNarrowLayout} = useResponsiveLayout(); const illustrationStyle = getLightbulbIllustrationStyle(); const [isLoading, setIsLoading] = useState(false); - const [shouldStoreLogs] = useOnyx(ONYXKEYS.SHOULD_STORE_LOGS); - const [shouldMaskOnyxState = true] = useOnyx(ONYXKEYS.SHOULD_MASK_ONYX_STATE); + const [shouldStoreLogs] = useOnyx(ONYXKEYS.SHOULD_STORE_LOGS, {canBeMissing: true}); + const [shouldMaskOnyxState = true] = useOnyx(ONYXKEYS.SHOULD_MASK_ONYX_STATE, {canBeMissing: true}); const {resetOptions} = useOptionsList({shouldInitialize: false}); const exportOnyxState = useCallback(() => { @@ -108,7 +108,7 @@ function TroubleshootPage() { title={translate('initialSettingsPage.aboutPage.troubleshoot')} shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter - onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS, {shouldPopToTop: true})} + onBackButtonPress={Navigation.popToSidebar} icon={Illustrations.Lightbulb} shouldUseHeadlineHeader /> diff --git a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx index 63902af88a83..3b2413e4afdf 100644 --- a/src/pages/settings/Wallet/WalletPage/WalletPage.tsx +++ b/src/pages/settings/Wallet/WalletPage/WalletPage.tsx @@ -389,7 +389,7 @@ function WalletPage({shouldListenForResize = false}: WalletPageProps) { shouldUseHeadlineHeader shouldShowBackButton={shouldUseNarrowLayout} shouldDisplaySearchRouter - onBackButtonPress={() => Navigation.goBack(undefined, {shouldPopToTop: true})} + onBackButtonPress={Navigation.popToSidebar} /> ); diff --git a/src/pages/workspace/WorkspaceJoinUserPage.tsx b/src/pages/workspace/WorkspaceJoinUserPage.tsx index 32da53dfa2c8..a708c33cc0c2 100644 --- a/src/pages/workspace/WorkspaceJoinUserPage.tsx +++ b/src/pages/workspace/WorkspaceJoinUserPage.tsx @@ -21,7 +21,7 @@ type WorkspaceJoinUserPageProps = WorkspaceJoinUserPageRoute; function WorkspaceJoinUserPage({route}: WorkspaceJoinUserPageProps) { const styles = useThemeStyles(); const policyID = route?.params?.policyID; - const [policy, policyResult] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); + const [policy, policyResult] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {canBeMissing: true}); const isPolicyLoading = isLoadingOnyxValue(policyResult); const inviterEmail = route?.params?.email; const isUnmounted = useRef(false); @@ -32,7 +32,11 @@ function WorkspaceJoinUserPage({route}: WorkspaceJoinUserPageProps) { } if (!isEmptyObject(policy) && !policy?.isJoinRequestPending && !isPendingDeletePolicy(policy)) { Navigation.isNavigationReady().then(() => { - Navigation.goBack(undefined, {shouldPopToTop: true}); + if (Navigation.getShouldPopToSidebar()) { + Navigation.popToSidebar(); + } else { + Navigation.goBack(); + } Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); }); return; diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index fdef786af354..30dbe12f0ebb 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -50,7 +50,6 @@ import {removeApprovalWorkflow as removeApprovalWorkflowAction, updateApprovalWo import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import {formatPhoneNumber as formatPhoneNumberUtil} from '@libs/LocalePhoneNumber'; import Log from '@libs/Log'; -import goBackFromWorkspaceCentralScreen from '@libs/Navigation/helpers/goBackFromWorkspaceCentralScreen'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; @@ -724,7 +723,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson turnOffMobileSelectionMode(); return; } - goBackFromWorkspaceCentralScreen(policyID); + Navigation.popToSidebar(); }} > {() => ( diff --git a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx index b29ef882d9ad..5561ee1172f6 100644 --- a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx +++ b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx @@ -16,7 +16,6 @@ import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import {filterInactiveCards, getAllCardsForWorkspace, getCompanyFeeds, isSmartLimitEnabled as isSmartLimitEnabledUtil} from '@libs/CardUtils'; import {getLatestErrorField} from '@libs/ErrorUtils'; -import goBackFromWorkspaceCentralScreen from '@libs/Navigation/helpers/goBackFromWorkspaceCentralScreen'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; @@ -442,7 +441,7 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro shouldUseHeadlineHeader title={translate('workspace.common.moreFeatures')} shouldShowBackButton={shouldUseNarrowLayout} - onBackButtonPress={() => goBackFromWorkspaceCentralScreen(policyID)} + onBackButtonPress={Navigation.popToSidebar} /> diff --git a/src/pages/workspace/WorkspaceOverviewPage.tsx b/src/pages/workspace/WorkspaceOverviewPage.tsx index 832a4ac16e14..fd2700859a3e 100644 --- a/src/pages/workspace/WorkspaceOverviewPage.tsx +++ b/src/pages/workspace/WorkspaceOverviewPage.tsx @@ -35,7 +35,6 @@ import { } from '@libs/actions/Policy/Policy'; import {filterInactiveCards} from '@libs/CardUtils'; import {getLatestErrorField} from '@libs/ErrorUtils'; -import goBackFromWorkspaceCentralScreen from '@libs/Navigation/helpers/goBackFromWorkspaceCentralScreen'; import resetPolicyIDInNavigationState from '@libs/Navigation/helpers/resetPolicyIDInNavigationState'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; @@ -218,7 +217,7 @@ function WorkspaceOverviewPage({policyDraft, policy: policyProp, route}: Workspa return; } - goBackFromWorkspaceCentralScreen(policy?.id); + Navigation.popToSidebar(); }; return ( diff --git a/src/pages/workspace/WorkspacePageWithSections.tsx b/src/pages/workspace/WorkspacePageWithSections.tsx index 11fb2a5bd257..23b82b09b4b3 100644 --- a/src/pages/workspace/WorkspacePageWithSections.tsx +++ b/src/pages/workspace/WorkspacePageWithSections.tsx @@ -16,7 +16,6 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import {openWorkspaceView} from '@libs/actions/BankAccounts'; import BankAccount from '@libs/models/BankAccount'; -import goBackFromWorkspaceCentralScreen from '@libs/Navigation/helpers/goBackFromWorkspaceCentralScreen'; import Navigation from '@libs/Navigation/Navigation'; import {isPendingDeletePolicy, isPolicyAdmin, shouldShowPolicy as shouldShowPolicyUtil} from '@libs/PolicyUtils'; import CONST from '@src/CONST'; @@ -183,7 +182,7 @@ function WorkspacePageWithSections({ return; } - goBackFromWorkspaceCentralScreen(policyID); + Navigation.popToSidebar(); }; return ( diff --git a/src/pages/workspace/accounting/PolicyAccountingPage.tsx b/src/pages/workspace/accounting/PolicyAccountingPage.tsx index f2f2c9d82b7f..b6eaa0eebdc1 100644 --- a/src/pages/workspace/accounting/PolicyAccountingPage.tsx +++ b/src/pages/workspace/accounting/PolicyAccountingPage.tsx @@ -32,7 +32,6 @@ import {isAuthenticationError, isConnectionInProgress, isConnectionUnverified, r import {shouldShowQBOReimbursableExportDestinationAccountError} from '@libs/actions/connections/QuickbooksOnline'; import {getAssignedSupportData} from '@libs/actions/Policy/Policy'; import {isExpensifyCardFullySetUp} from '@libs/CardUtils'; -import goBackFromWorkspaceCentralScreen from '@libs/Navigation/helpers/goBackFromWorkspaceCentralScreen'; import { areSettingsInErrorFields, findCurrentXeroOrganization, @@ -542,7 +541,7 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) { icon={Illustrations.Accounting} shouldUseHeadlineHeader threeDotsAnchorPosition={threeDotsAnchorPosition} - onBackButtonPress={() => goBackFromWorkspaceCentralScreen(policyID)} + onBackButtonPress={Navigation.popToSidebar} /> {!shouldUseNarrowLayout && headerButtons} diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx index 79a058318dfb..b0d54b7c6045 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardListPage.tsx @@ -24,7 +24,6 @@ import useSearchResults from '@hooks/useSearchResults'; import useThemeStyles from '@hooks/useThemeStyles'; import {clearDeletePaymentMethodError} from '@libs/actions/PaymentMethods'; import {filterCardsByPersonalDetails, getCardsByCardholderName, sortCardsByCardholderName} from '@libs/CardUtils'; -import goBackFromWorkspaceCentralScreen from '@libs/Navigation/helpers/goBackFromWorkspaceCentralScreen'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import {getDescriptionForPolicyDomainCard, getMemberAccountIDsForWorkspace} from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; @@ -160,7 +159,7 @@ function WorkspaceExpensifyCardListPage({route, cardsList, fundID}: WorkspaceExp shouldUseHeadlineHeader title={translate('workspace.common.expensifyCard')} shouldShowBackButton={shouldUseNarrowLayout} - onBackButtonPress={() => goBackFromWorkspaceCentralScreen(policyID)} + onBackButtonPress={Navigation.popToSidebar} > {!shouldShowSelector && !shouldUseNarrowLayout && isBankAccountVerified && getHeaderButtons()} diff --git a/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx b/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx index dab5a1dd7a56..c8bb24348dc0 100644 --- a/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx +++ b/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx @@ -36,7 +36,6 @@ import useThreeDotsAnchorPosition from '@hooks/useThreeDotsAnchorPosition'; import {convertAmountToDisplayString} from '@libs/CurrencyUtils'; import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import localeCompare from '@libs/LocaleCompare'; -import goBackFromWorkspaceCentralScreen from '@libs/Navigation/helpers/goBackFromWorkspaceCentralScreen'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; @@ -396,7 +395,7 @@ function WorkspacePerDiemPage({route}: WorkspacePerDiemPageProps) { return; } - goBackFromWorkspaceCentralScreen(policyID); + Navigation.popToSidebar(); }} shouldShowThreeDotsButton threeDotsMenuItems={threeDotsMenuItems} diff --git a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx index 83b0584d21a7..205e62704f42 100644 --- a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx +++ b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx @@ -176,6 +176,7 @@ function WorkspaceReportFieldsPage({ title={translate('common.reports')} shouldUseHeadlineHeader shouldShowBackButton={shouldUseNarrowLayout} + onBackButtonPress={Navigation.popToSidebar} /> {isLoading && ( {!shouldUseNarrowLayout && headerButtons} diff --git a/tests/navigation/PopToSidebarTests.tsx b/tests/navigation/PopToSidebarTests.tsx new file mode 100644 index 000000000000..a45d03fd8bff --- /dev/null +++ b/tests/navigation/PopToSidebarTests.tsx @@ -0,0 +1,130 @@ +import {act, render} from '@testing-library/react-native'; +import React from 'react'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import getIsNarrowLayout from '@libs/getIsNarrowLayout'; +import Navigation from '@libs/Navigation/Navigation'; +import navigationRef from '@libs/Navigation/navigationRef'; +import CONST from '@src/CONST'; +import NAVIGATORS from '@src/NAVIGATORS'; +import ROUTES from '@src/ROUTES'; +import SCREENS from '@src/SCREENS'; +import TestNavigationContainer from '../utils/TestNavigationContainer'; + +jest.mock('@hooks/useResponsiveLayout', () => jest.fn()); +jest.mock('@libs/getIsNarrowLayout', () => jest.fn()); + +jest.mock('@pages/home/sidebar/NavigationTabBarAvatar'); +jest.mock('@src/components/Navigation/TopLevelNavigationTabBar'); +jest.mock('@components/ConfirmedRoute.tsx'); + +const mockedGetIsNarrowLayout = getIsNarrowLayout as jest.MockedFunction; +const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction; + +describe('Pop to sidebar after resize from wide to narrow layout', () => { + beforeEach(() => { + mockedGetIsNarrowLayout.mockReturnValue(true); + mockedUseResponsiveLayout.mockReturnValue({...CONST.NAVIGATION_TESTS.DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true}); + }); + + describe('After opening several screens in the settings tab', () => { + it('Should pop all visited screens and go back to the settings sidebar screen', () => { + render( + , + ); + + const settingsSplitBeforePopToSidebar = navigationRef.current?.getRootState().routes.at(-1); + expect(settingsSplitBeforePopToSidebar?.state?.index).toBe(3); + + // When we pop with LHN on top of stack + act(() => { + Navigation.popToSidebar(); + }); + + // Then all screens should be popped of the stack and only settings root left + const settingsSplitAfterPopToSidebar = navigationRef.current?.getRootState().routes.at(-1); + expect(settingsSplitAfterPopToSidebar?.state?.index).toBe(0); + expect(settingsSplitAfterPopToSidebar?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ROOT); + }); + }); + + describe('After navigating to the central screen in the settings tab from the chat', () => { + it('Should replace the route with LHN', () => { + render( + , + ); + + const lastSplitBeforeNavigate = navigationRef.current?.getRootState().routes.at(-1); + expect(lastSplitBeforeNavigate?.name).toBe(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR); + + act(() => { + Navigation.navigate(ROUTES.SETTINGS_ABOUT); + }); + + const lastSplitAfterNavigate = navigationRef.current?.getRootState().routes.at(-1); + expect(lastSplitAfterNavigate?.name).toBe(NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR); + expect(lastSplitAfterNavigate?.state?.index).toBe(0); + expect(lastSplitAfterNavigate?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ABOUT); + + // When we pop to sidebar without LHN on top of stack + act(() => { + Navigation.popToSidebar(); + }); + + // Then the top screen should be replaced with LHN + const lastSplitAfterPopToSidebar = navigationRef.current?.getRootState().routes.at(-1); + expect(lastSplitAfterPopToSidebar?.state?.index).toBe(0); + expect(lastSplitAfterPopToSidebar?.state?.routes.at(-1)?.name).toBe(SCREENS.SETTINGS.ROOT); + }); + }); +}); diff --git a/tests/utils/TestNavigationContainer.tsx b/tests/utils/TestNavigationContainer.tsx index 518ab8205d8c..31551bd4912c 100644 --- a/tests/utils/TestNavigationContainer.tsx +++ b/tests/utils/TestNavigationContainer.tsx @@ -4,7 +4,13 @@ import React from 'react'; import createRootStackNavigator from '@libs/Navigation/AppNavigator/createRootStackNavigator'; import createSplitNavigator from '@libs/Navigation/AppNavigator/createSplitNavigator'; import navigationRef from '@libs/Navigation/navigationRef'; -import type {AuthScreensParamList, ReportsSplitNavigatorParamList, SearchFullscreenNavigatorParamList, SettingsSplitNavigatorParamList} from '@libs/Navigation/types'; +import type { + AuthScreensParamList, + ReportsSplitNavigatorParamList, + SearchFullscreenNavigatorParamList, + SettingsSplitNavigatorParamList, + WorkspaceSplitNavigatorParamList, +} from '@libs/Navigation/types'; import createPlatformStackNavigator from '@navigation/PlatformStackNavigation/createPlatformStackNavigator'; import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; @@ -14,11 +20,39 @@ const RootStack = createRootStackNavigator(); const ReportsSplit = createSplitNavigator(); const SettingsSplit = createSplitNavigator(); const SearchStack = createPlatformStackNavigator(); +const WorkspaceSplit = createSplitNavigator(); const getEmptyComponent = () => jest.fn(); type TestNavigationContainerProps = {initialState: InitialState}; +function TestWorkspaceSplitNavigator() { + return ( + + + + + + + ); +} + function TestReportsSplitNavigator() { return ( +