diff --git a/src/CONST/index.ts b/src/CONST/index.ts index d08f02a939d9..33391cf1b9cf 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -6820,7 +6820,7 @@ const CONST = { CASH_BACK: 'earnedCashback', }, - EXCLUDE_FROM_LAST_VISITED_PATH: [SCREENS.NOT_FOUND, SCREENS.SAML_SIGN_IN, SCREENS.VALIDATE_LOGIN, SCREENS.MIGRATED_USER_WELCOME_MODAL.ROOT, SCREENS.MONEY_REQUEST.STEP_SCAN] as string[], + EXCLUDE_FROM_LAST_VISITED_PATH: [SCREENS.NOT_FOUND, SCREENS.SAML_SIGN_IN, SCREENS.VALIDATE_LOGIN, SCREENS.MIGRATED_USER_WELCOME_MODAL.ROOT] as string[], CANCELLATION_TYPE: { MANUAL: 'manual', diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index f25fb2d23695..dc5c3a2c385a 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -131,12 +131,6 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady}: N const isTransitioning = path?.includes(ROUTES.TRANSITION_BETWEEN_APPS); - // If we have a transition URL, don't restore last visited path - let React Navigation handle it - // This prevents reusing deep links after logout regardless of authentication status - if (isTransitioning) { - return undefined; - } - // If the user haven't completed the flow, we want to always redirect them to the onboarding flow. // We also make sure that the user is authenticated, isn't part of a group workspace, isn't in the transition flow & wasn't invited to NewDot. if (!CONFIG.IS_HYBRID_APP && !hasNonPersonalPolicy && !isOnboardingCompleted && !wasInvitedToNewDot && authenticated && !isTransitioning) { @@ -152,20 +146,20 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady}: N ); } - if (shouldOpenLastVisitedPath(lastVisitedPath) && authenticated) { - // Only skip restoration if there's a specific deep link that's not the root - // This allows restoration when app is killed and reopened without a deep link - const isRootPath = !path || path === '' || path === '/'; - const isSpecificDeepLink = path && !isRootPath; + // If there is no lastVisitedPath, we can do early return. We won't modify the default behavior. + // The same applies to HybridApp, as we always define the route to which we want to transition. + if (!shouldOpenLastVisitedPath(lastVisitedPath) || CONFIG.IS_HYBRID_APP) { + return undefined; + } - if (!isSpecificDeepLink) { - Log.info('Restoring last visited path on app startup', false, {lastVisitedPath, initialUrl, path}); - return getAdaptedStateFromPath(lastVisitedPath, linkingConfig.config); - } + // If the user opens the root of app "/" it will be parsed to empty string "". + // If the path is defined and different that empty string we don't want to modify the default behavior. + if (path) { + return; } - // Default behavior - let React Navigation handle the initial state - return undefined; + // Otherwise we want to redirect the user to the last visited path. + return getAdaptedStateFromPath(lastVisitedPath, linkingConfig.config); // The initialState value is relevant only on the first render. // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index f108929ec5e7..37ebc4ffe2dd 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -1,5 +1,4 @@ // Issue - https://github.com/Expensify/App/issues/26719 -import {getPathFromState} from '@react-navigation/native'; import {Str} from 'expensify-common'; import type {AppStateStatus} from 'react-native'; import {AppState} from 'react-native'; @@ -12,8 +11,7 @@ import * as Browser from '@libs/Browser'; import DateUtils from '@libs/DateUtils'; import Log from '@libs/Log'; import getCurrentUrl from '@libs/Navigation/currentUrl'; -import {linkingConfig} from '@libs/Navigation/linkingConfig'; -import Navigation, {navigationRef} from '@libs/Navigation/Navigation'; +import Navigation from '@libs/Navigation/Navigation'; import Performance from '@libs/Performance'; import {isPublicRoom, isValidReport} from '@libs/ReportUtils'; import {isLoggingInAsNewUser as isLoggingInAsNewUserSessionUtils} from '@libs/SessionUtils'; @@ -209,36 +207,10 @@ function setAppLoading(isLoading: boolean) { Onyx.set(ONYXKEYS.IS_LOADING_APP, isLoading); } -/** - * Saves the current navigation path to lastVisitedPath before app goes to background - */ -function saveCurrentPathBeforeBackground() { - try { - if (!navigationRef.isReady()) { - return; - } - - const currentState = navigationRef.getRootState(); - if (!currentState) { - return; - } - - const currentPath = getPathFromState(currentState, linkingConfig.config); - - if (currentPath) { - Log.info('Saving current path before background', false, {currentPath}); - updateLastVisitedPath(currentPath); - } - } catch (error) { - Log.warn('Failed to save current path before background', {error}); - } -} - let appState: AppStateStatus; AppState.addEventListener('change', (nextAppState) => { if (nextAppState.match(/inactive|background/) && appState === 'active') { Log.info('Flushing logs as app is going inactive', true, {}, true); - saveCurrentPathBeforeBackground(); } appState = nextAppState; }); diff --git a/src/libs/shouldOpenLastVisitedPath/index.native.ts b/src/libs/shouldOpenLastVisitedPath/index.native.ts new file mode 100644 index 000000000000..c63444aaeeb7 --- /dev/null +++ b/src/libs/shouldOpenLastVisitedPath/index.native.ts @@ -0,0 +1,6 @@ +import {getReportIDFromLink} from '@libs/ReportUtils'; +import type {Route} from '@src/ROUTES'; + +export default function shouldOpenLastVisitedPath(lastVisitedPath: Route) { + return !!lastVisitedPath && !!getReportIDFromLink(lastVisitedPath); +} diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index d93eff26bece..868ae112b05f 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -50,7 +50,6 @@ import HapticFeedback from '@libs/HapticFeedback'; import {navigateToParticipantPage} from '@libs/IOUUtils'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; -import navigationRef from '@libs/Navigation/navigationRef'; import {getManagerMcTestParticipant, getParticipantsOption, getReportOption} from '@libs/OptionsListUtils'; import {isPaidGroupPolicy} from '@libs/PolicyUtils'; import {findSelfDMReportID, generateReportID, getPolicyExpenseChat, isArchivedReport, isPolicyExpenseChat} from '@libs/ReportUtils'; @@ -74,7 +73,6 @@ import type {GpsPoint} from '@userActions/IOU'; import {buildOptimisticTransactionAndCreateDraft, removeDraftTransactions, removeTransactionReceipt} from '@userActions/TransactionEdit'; 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 type {Participant} from '@src/types/onyx/IOU'; @@ -532,22 +530,10 @@ function IOURequestStepScan({ const updateScanAndNavigate = useCallback( (file: FileObject, source: string) => { - // Fix for the issue where the navigation state is lost after returning from device settings https://github.com/Expensify/App/issues/65992 - const navigationState = navigationRef.current?.getState(); - const reportsSplitNavigator = navigationState?.routes?.findLast((route) => route.name === 'ReportsSplitNavigator'); - const hasLostNavigationsState = reportsSplitNavigator && !reportsSplitNavigator.state; - if (hasLostNavigationsState) { - if (backTo) { - Navigation.navigate(backTo as Route); - } else { - Navigation.navigate(ROUTES.HOME); - } - } else { - navigateBack(); - } + navigateBack(); replaceReceipt({transactionID: initialTransactionID, file: file as File, source}); }, - [initialTransactionID, backTo], + [initialTransactionID], ); /**