diff --git a/src/Expensify.js b/src/Expensify.js index 0707ba069241..074790b81fed 100644 --- a/src/Expensify.js +++ b/src/Expensify.js @@ -79,6 +79,9 @@ const propTypes = { /** Whether we should display the notification alerting the user that focus mode has been auto-enabled */ focusModeNotification: PropTypes.bool, + /** Last visited path in the app */ + lastVisitedPath: PropTypes.string, + ...withLocalizePropTypes, }; @@ -92,6 +95,7 @@ const defaultProps = { screenShareRequest: null, isCheckingPublicRoom: true, focusModeNotification: false, + lastVisitedPath: undefined, }; const SplashScreenHiddenContext = React.createContext({}); @@ -102,6 +106,7 @@ function Expensify(props) { const [isOnyxMigrated, setIsOnyxMigrated] = useState(false); const [isSplashHidden, setIsSplashHidden] = useState(false); const [hasAttemptedToOpenPublicRoom, setAttemptedToOpenPublicRoom] = useState(false); + const [initialUrl, setInitialUrl] = useState(null); useEffect(() => { if (props.isCheckingPublicRoom) { @@ -182,6 +187,7 @@ function Expensify(props) { // If the app is opened from a deep link, get the reportID (if exists) from the deep link and navigate to the chat report Linking.getInitialURL().then((url) => { + setInitialUrl(url); Report.openReportFromDeepLink(url, isAuthenticated); }); @@ -237,6 +243,8 @@ function Expensify(props) { )} @@ -272,6 +280,9 @@ export default compose( key: ONYXKEYS.FOCUS_MODE_NOTIFICATION, initWithStoredValues: false, }, + lastVisitedPath: { + key: ONYXKEYS.LAST_VISITED_PATH, + }, }), )(Expensify); diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 98e3856f4544..e205a3b01967 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -240,6 +240,9 @@ const ONYXKEYS = { // Max width supported for HTML element MAX_CANVAS_WIDTH: 'maxCanvasWidth', + // Stores last visited path + LAST_VISITED_PATH: 'lastVisitedPath', + /** Collection Keys */ COLLECTION: { DOWNLOAD: 'download_', @@ -432,6 +435,7 @@ type OnyxValues = { [ONYXKEYS.MAX_CANVAS_AREA]: number; [ONYXKEYS.MAX_CANVAS_HEIGHT]: number; [ONYXKEYS.MAX_CANVAS_WIDTH]: number; + [ONYXKEYS.LAST_VISITED_PATH]: string | undefined; // Collections [ONYXKEYS.COLLECTION.DOWNLOAD]: OnyxTypes.Download; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index e25a6865a71d..5c6e64801750 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -12,7 +12,7 @@ function getUrlWithBackToParam(url: TUrl, backTo?: string): } const ROUTES = { - HOME: '', + HOME: 'home', ALL_SETTINGS: 'all-settings', diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx index 31a68131da73..5405bc079fe5 100644 --- a/src/libs/Navigation/NavigationRoot.tsx +++ b/src/libs/Navigation/NavigationRoot.tsx @@ -6,7 +6,11 @@ import useFlipper from '@hooks/useFlipper'; import useTheme from '@hooks/useTheme'; import useWindowDimensions from '@hooks/useWindowDimensions'; import Log from '@libs/Log'; +import {getPathFromURL} from '@libs/Url'; +import {updateLastVisitedPath} from '@userActions/App'; +import type {Route} from '@src/ROUTES'; import AppNavigator from './AppNavigator'; +import getStateFromPath from './getStateFromPath'; import linkingConfig from './linkingConfig'; import Navigation, {navigationRef} from './Navigation'; @@ -14,6 +18,12 @@ type NavigationRootProps = { /** Whether the current user is logged in with an authToken */ authenticated: boolean; + /** Stores path of last visited page */ + lastVisitedPath: Route; + + /** Initial url */ + initialUrl: string | null; + /** Fired when react-navigation is ready */ onReady: () => void; }; @@ -27,6 +37,7 @@ function parseAndLogRoute(state: NavigationState) { } const currentPath = getPathFromState(state, linkingConfig.config); + updateLastVisitedPath(currentPath); // Don't log the route transitions from OldDot because they contain authTokens if (currentPath.includes('/transition')) { @@ -38,7 +49,7 @@ function parseAndLogRoute(state: NavigationState) { Navigation.setIsNavigationReady(); } -function NavigationRoot({authenticated, onReady}: NavigationRootProps) { +function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady}: NavigationRootProps) { useFlipper(navigationRef); const firstRenderRef = useRef(true); const theme = useTheme(); @@ -46,6 +57,25 @@ function NavigationRoot({authenticated, onReady}: NavigationRootProps) { const currentReportIDValue = useCurrentReportID(); const {isSmallScreenWidth} = useWindowDimensions(); + const initialState = useMemo( + () => { + if (!lastVisitedPath) { + return undefined; + } + + const path = initialUrl ? getPathFromURL(initialUrl) : null; + + // For non-nullable paths we don't want to set initial state + if (path) { + return; + } + + return getStateFromPath(lastVisitedPath); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [], + ); + // https://reactnavigation.org/docs/themes const navigationTheme = useMemo( () => ({ @@ -86,6 +116,7 @@ function NavigationRoot({authenticated, onReady}: NavigationRootProps) { return (