diff --git a/src/App.tsx b/src/App.tsx
index 0e247d5faa53..a2d353a026af 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -13,6 +13,7 @@ import CustomStatusBarAndBackground from './components/CustomStatusBarAndBackgro
import CustomStatusBarAndBackgroundContextProvider from './components/CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContextProvider';
import ErrorBoundary from './components/ErrorBoundary';
import HTMLEngineProvider from './components/HTMLEngineProvider';
+import InitialURLContextProvider from './components/InitialURLContextProvider';
import {LocaleContextProvider} from './components/LocaleContextProvider';
import OnyxProvider from './components/OnyxProvider';
import PopoverContextProvider from './components/PopoverProvider';
@@ -30,12 +31,11 @@ import {WindowDimensionsProvider} from './components/withWindowDimensions';
import Expensify from './Expensify';
import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop';
import OnyxUpdateManager from './libs/actions/OnyxUpdateManager';
-import InitialUrlContext from './libs/InitialUrlContext';
import {ReportAttachmentsProvider} from './pages/home/report/ReportAttachmentsContext';
import type {Route} from './ROUTES';
type AppProps = {
- /** If we have an authToken this is true */
+ /** URL passed to our top-level React Native component by HybridApp. Will always be undefined in "pure" NewDot builds. */
url?: Route;
};
@@ -52,7 +52,7 @@ function App({url}: AppProps) {
useDefaultDragAndDrop();
OnyxUpdateManager();
return (
-
+
-
+
);
}
diff --git a/src/components/InitialURLContextProvider.tsx b/src/components/InitialURLContextProvider.tsx
new file mode 100644
index 000000000000..a3df93844ca9
--- /dev/null
+++ b/src/components/InitialURLContextProvider.tsx
@@ -0,0 +1,33 @@
+import React, {createContext, useEffect, useState} from 'react';
+import type {ReactNode} from 'react';
+import {Linking} from 'react-native';
+import type {Route} from '@src/ROUTES';
+
+/** Initial url that will be opened when NewDot is embedded into Hybrid App. */
+const InitialURLContext = createContext(undefined);
+
+type InitialURLContextProviderProps = {
+ /** URL passed to our top-level React Native component by HybridApp. Will always be undefined in "pure" NewDot builds. */
+ url?: Route;
+
+ /** Children passed to the context provider */
+ children: ReactNode;
+};
+
+function InitialURLContextProvider({children, url}: InitialURLContextProviderProps) {
+ const [initialURL, setInitialURL] = useState(url);
+ useEffect(() => {
+ if (initialURL) {
+ return;
+ }
+ Linking.getInitialURL().then((initURL) => {
+ setInitialURL(initURL as Route);
+ });
+ }, [initialURL]);
+ return {children};
+}
+
+InitialURLContextProvider.displayName = 'InitialURLContextProvider';
+
+export default InitialURLContextProvider;
+export {InitialURLContext};
diff --git a/src/libs/InitialUrlContext/index.ts b/src/libs/InitialUrlContext/index.ts
deleted file mode 100644
index a87417fe4cc6..000000000000
--- a/src/libs/InitialUrlContext/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import {createContext} from 'react';
-import type {Route} from '@src/ROUTES';
-
-/** Initial url that will be opened when NewDot is embedded into Hybrid App. */
-const InitialUrlContext = createContext(undefined);
-
-export default InitialUrlContext;
diff --git a/src/libs/Navigation/AppNavigator/index.tsx b/src/libs/Navigation/AppNavigator/index.tsx
index 24f0f42c5d64..9729a2f812ce 100644
--- a/src/libs/Navigation/AppNavigator/index.tsx
+++ b/src/libs/Navigation/AppNavigator/index.tsx
@@ -1,6 +1,6 @@
import React, {useContext, useEffect} from 'react';
import {NativeModules} from 'react-native';
-import InitialUrlContext from '@libs/InitialUrlContext';
+import {InitialURLContext} from '@components/InitialURLContextProvider';
import Navigation from '@libs/Navigation/Navigation';
type AppNavigatorProps = {
@@ -9,7 +9,7 @@ type AppNavigatorProps = {
};
function AppNavigator({authenticated}: AppNavigatorProps) {
- const initUrl = useContext(InitialUrlContext);
+ const initUrl = useContext(InitialURLContext);
useEffect(() => {
if (!NativeModules.HybridAppModule || !initUrl) {
diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx
index 3df7a4cdb9f3..37402ea8b048 100644
--- a/src/pages/LogOutPreviousUserPage.tsx
+++ b/src/pages/LogOutPreviousUserPage.tsx
@@ -1,22 +1,27 @@
import type {StackScreenProps} from '@react-navigation/stack';
-import React, {useEffect} from 'react';
-import {Linking} from 'react-native';
+import React, {useContext, useEffect} from 'react';
+import {NativeModules} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
-import Navigation from '@libs/Navigation/Navigation';
+import {InitialURLContext} from '@components/InitialURLContextProvider';
import * as SessionUtils from '@libs/SessionUtils';
+import Navigation from '@navigation/Navigation';
import type {AuthScreensParamList} from '@navigation/types';
import * as SessionActions from '@userActions/Session';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
+import type {Route} from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type {Session} from '@src/types/onyx';
type LogOutPreviousUserPageOnyxProps = {
/** The data about the current session which will be set once the user is authenticated and we return to this component as an AuthScreen */
session: OnyxEntry;
+
+ /** Is the account loading? */
+ isAccountLoading: boolean;
};
type LogOutPreviousUserPageProps = LogOutPreviousUserPageOnyxProps & StackScreenProps;
@@ -25,42 +30,55 @@ type LogOutPreviousUserPageProps = LogOutPreviousUserPageOnyxProps & StackScreen
// out if the transition is for another user.
//
// This component should not do any other navigation as that handled in App.setUpPoliciesAndNavigate
-function LogOutPreviousUserPage({session, route}: LogOutPreviousUserPageProps) {
+function LogOutPreviousUserPage({session, route, isAccountLoading}: LogOutPreviousUserPageProps) {
+ const initialURL = useContext(InitialURLContext);
useEffect(() => {
- Linking.getInitialURL().then((transitionURL) => {
- const sessionEmail = session?.email;
- const isLoggingInAsNewUser = SessionUtils.isLoggingInAsNewUser(transitionURL ?? undefined, sessionEmail);
- const isSupportalLogin = route.params.authTokenType === CONST.AUTH_TOKEN_TYPES.SUPPORT;
+ const sessionEmail = session?.email;
+ const transitionURL = NativeModules.HybridAppModule ? `${CONST.DEEPLINK_BASE_URL}${initialURL ?? ''}` : initialURL;
+ const isLoggingInAsNewUser = SessionUtils.isLoggingInAsNewUser(transitionURL ?? undefined, sessionEmail);
+ const isSupportalLogin = route.params.authTokenType === CONST.AUTH_TOKEN_TYPES.SUPPORT;
- if (isLoggingInAsNewUser) {
- SessionActions.signOutAndRedirectToSignIn(false, isSupportalLogin);
- }
+ if (isLoggingInAsNewUser) {
+ SessionActions.signOutAndRedirectToSignIn(false, isSupportalLogin);
+ return;
+ }
- if (isSupportalLogin) {
- SessionActions.signInWithSupportAuthToken(route.params.shortLivedAuthToken ?? '');
- Navigation.isNavigationReady().then(() => {
- // We must call goBack() to remove the /transition route from history
- Navigation.goBack();
- Navigation.navigate(ROUTES.HOME);
- });
- return;
- }
+ if (isSupportalLogin) {
+ SessionActions.signInWithSupportAuthToken(route.params.shortLivedAuthToken ?? '');
+ Navigation.isNavigationReady().then(() => {
+ // We must call goBack() to remove the /transition route from history
+ Navigation.goBack();
+ Navigation.navigate(ROUTES.HOME);
+ });
+ return;
+ }
- // We need to signin and fetch a new authToken, if a user was already authenticated in NewDot, and was redirected to OldDot
- // and their authToken stored in Onyx becomes invalid.
- // This workflow is triggered while setting up VBBA. User is redirected from NewDot to OldDot to set up 2FA, and then redirected back to NewDot
- // On Enabling 2FA, authToken stored in Onyx becomes expired and hence we need to fetch new authToken
- const shouldForceLogin = route.params.shouldForceLogin === 'true';
- if (shouldForceLogin) {
- const email = route.params.email ?? '';
- const shortLivedAuthToken = route.params.shortLivedAuthToken ?? '';
- SessionActions.signInWithShortLivedAuthToken(email, shortLivedAuthToken);
- }
- });
+ // We need to signin and fetch a new authToken, if a user was already authenticated in NewDot, and was redirected to OldDot
+ // and their authToken stored in Onyx becomes invalid.
+ // This workflow is triggered while setting up VBBA. User is redirected from NewDot to OldDot to set up 2FA, and then redirected back to NewDot
+ // On Enabling 2FA, authToken stored in Onyx becomes expired and hence we need to fetch new authToken
+ const shouldForceLogin = route.params.shouldForceLogin === 'true';
+ if (shouldForceLogin) {
+ const email = route.params.email ?? '';
+ const shortLivedAuthToken = route.params.shortLivedAuthToken ?? '';
+ SessionActions.signInWithShortLivedAuthToken(email, shortLivedAuthToken);
+ }
+ const exitTo = route.params.exitTo as Route | null;
+ // We don't want to navigate to the exitTo route when creating a new workspace from a deep link,
+ // because we already handle creating the optimistic policy and navigating to it in App.setUpPoliciesAndNavigate,
+ // which is already called when AuthScreens mounts.
+ if (exitTo && exitTo !== ROUTES.WORKSPACE_NEW && !isAccountLoading && !isLoggingInAsNewUser) {
+ Navigation.isNavigationReady().then(() => {
+ // remove this screen and navigate to exit route
+ const exitUrl = NativeModules.HybridAppModule ? Navigation.parseHybridAppUrl(exitTo) : exitTo;
+ Navigation.goBack();
+ Navigation.navigate(exitUrl);
+ });
+ }
// We only want to run this effect once on mount (when the page first loads after transitioning from OldDot)
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ }, [initialURL, isAccountLoading]);
return ;
}
@@ -68,6 +86,10 @@ function LogOutPreviousUserPage({session, route}: LogOutPreviousUserPageProps) {
LogOutPreviousUserPage.displayName = 'LogOutPreviousUserPage';
export default withOnyx({
+ isAccountLoading: {
+ key: ONYXKEYS.ACCOUNT,
+ selector: (account) => account?.isLoading ?? false,
+ },
session: {
key: ONYXKEYS.SESSION,
},