From 68ed5168bb4eaac39b13ed1fe66cb8c180867884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Warcho=C5=82?= <61014013+war-in@users.noreply.github.com> Date: Mon, 9 Dec 2024 13:41:39 +0100 Subject: [PATCH] Dont sign in in old dot (#150) * wip * wip * remove comment * clean * remove unused parameters and fix sign up flow * block sign in logic when OD sign-in was performed * simplify blocking logic * fix crash when switching apps * Fix bug where OpenApp is called after opening app from background --------- Co-authored-by: war-in Co-authored-by: Mateusz Rajski --- src/App.tsx | 2 - src/CONST.ts | 3 - src/components/InitialURLContextProvider.tsx | 19 +++- src/libs/API/types.ts | 4 +- src/libs/HybridApp.ts | 103 +++++++----------- .../Navigation/AppNavigator/PublicScreens.tsx | 1 - .../Navigation/AppNavigator/index.native.tsx | 7 +- src/libs/actions/HybridApp/index.ts | 93 +--------------- src/libs/actions/Session/index.ts | 36 ++++-- src/libs/actions/SignInRedirect.ts | 6 - src/pages/settings/InitialSettingsPage.tsx | 72 +----------- src/pages/signin/SignUpWelcomeForm.tsx | 4 +- .../ValidateCodeForm/BaseValidateCodeForm.tsx | 21 +--- src/types/modules/react-native.d.ts | 2 +- src/types/onyx/HybridApp.ts | 8 +- 15 files changed, 105 insertions(+), 276 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 0f09216a3fe6..34d4acb6c4d6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -36,7 +36,6 @@ import Expensify from './Expensify'; import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop'; import {ReportIDsContextProvider} from './hooks/useReportIDs'; import OnyxUpdateManager from './libs/actions/OnyxUpdateManager'; -import HybridApp from './libs/HybridApp'; import {ReportAttachmentsProvider} from './pages/home/report/ReportAttachmentsContext'; import type {Route} from './ROUTES'; import {SplashScreenStateContextProvider} from './SplashScreenStateContext'; @@ -65,7 +64,6 @@ const StrictModeWrapper = CONFIG.USE_REACT_STRICT_MODE_IN_DEV ? React.StrictMode function App({url, hybridAppSettings}: AppProps) { useDefaultDragAndDrop(); OnyxUpdateManager(); - HybridApp.init(); return ( diff --git a/src/CONST.ts b/src/CONST.ts index 6964fd99fd53..5cd9499d0e0f 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -6299,9 +6299,6 @@ const CONST = { NOT_STARTED: 'notStarted', STARTED: 'started', FINISHED: 'finished', - WAITING_FOR_SIGN_OUT: 'waitingForSignOut', - RETRYING_AFTER_FAILURE: 'retryingAfterFailure', - FAILED_AGAIN: 'failedAgain', }, CSV_IMPORT_COLUMNS: { diff --git a/src/components/InitialURLContextProvider.tsx b/src/components/InitialURLContextProvider.tsx index 61f18de4d034..d6162231c694 100644 --- a/src/components/InitialURLContextProvider.tsx +++ b/src/components/InitialURLContextProvider.tsx @@ -1,4 +1,4 @@ -import React, {createContext, useEffect, useMemo, useState} from 'react'; +import React, {createContext, useEffect, useMemo, useRef, useState} from 'react'; import type {ReactNode} from 'react'; import {Linking} from 'react-native'; import {useOnyx} from 'react-native-onyx'; @@ -9,6 +9,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import {useSplashScreenStateContext} from '@src/SplashScreenStateContext'; +import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; type InitialUrlContextType = { initialURL: Route | undefined; @@ -35,6 +36,9 @@ function InitialURLContextProvider({children, url, hybridAppSettings}: InitialUR const [initialURL, setInitialURL] = useState | undefined>(url); const [lastVisitedPath] = useOnyx(ONYXKEYS.LAST_VISITED_PATH); const {splashScreenState, setSplashScreenState} = useSplashScreenStateContext(); + const [tryNewDot, tryNewDotMetadata] = useOnyx(ONYXKEYS.NVP_TRYNEWDOT); + // We use `setupCalled` ref to guarantee that `signInAfterTransitionFromOldDot` is called once. + const setupCalled = useRef(false); useEffect(() => { if (url !== CONST.HYBRID_APP.REORDERING_REACT_NATIVE_ACTIVITY_TO_FRONT) { @@ -53,16 +57,19 @@ function InitialURLContextProvider({children, url, hybridAppSettings}: InitialUR } if (url && hybridAppSettings) { - setupNewDotAfterTransitionFromOldDot(url, hybridAppSettings).then((route) => { - setInitialURL(route); - setSplashScreenState(CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN); - }); + if (!isLoadingOnyxValue(tryNewDotMetadata) && !setupCalled.current) { + setupCalled.current = true; + setupNewDotAfterTransitionFromOldDot(url, hybridAppSettings, tryNewDot).then((route) => { + setInitialURL(route); + setSplashScreenState(CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN); + }); + } return; } Linking.getInitialURL().then((initURL) => { setInitialURL(initURL as Route); }); - }, [hybridAppSettings, setSplashScreenState, url]); + }, [hybridAppSettings, setSplashScreenState, tryNewDot, tryNewDotMetadata, url]); const initialUrlContext = useMemo( () => ({ diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index c0485fcbd1b5..a5014c67091d 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -306,7 +306,6 @@ const WRITE_COMMANDS = { TRANSACTION_MERGE: 'Transaction_Merge', RESOLVE_DUPLICATES: 'ResolveDuplicates', UPDATE_SUBSCRIPTION_TYPE: 'UpdateSubscriptionType', - SIGN_UP_USER: 'SignUpUser', UPDATE_SUBSCRIPTION_AUTO_RENEW: 'UpdateSubscriptionAutoRenew', UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY: 'UpdateSubscriptionAddNewUsersAutomatically', UPDATE_SUBSCRIPTION_SIZE: 'UpdateSubscriptionSize', @@ -756,7 +755,6 @@ type WriteCommandParameters = { [WRITE_COMMANDS.TRANSACTION_MERGE]: Parameters.TransactionMergeParams; [WRITE_COMMANDS.RESOLVE_DUPLICATES]: Parameters.ResolveDuplicatesParams; [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_TYPE]: Parameters.UpdateSubscriptionTypeParams; - [WRITE_COMMANDS.SIGN_UP_USER]: Parameters.SignUpUserParams; [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_AUTO_RENEW]: Parameters.UpdateSubscriptionAutoRenewParams; [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY]: Parameters.UpdateSubscriptionAddNewUsersAutomaticallyParams; [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_SIZE]: Parameters.UpdateSubscriptionSizeParams; @@ -1030,6 +1028,7 @@ const SIDE_EFFECT_REQUEST_COMMANDS = { COMPLETE_HYBRID_APP_ONBOARDING: 'CompleteHybridAppOnboarding', CONNECT_POLICY_TO_QUICKBOOKS_DESKTOP: 'ConnectPolicyToQuickbooksDesktop', SIGN_IN_USER: 'SigninUser', + SIGN_UP_USER: 'SignUpUser', // PayMoneyRequestOnSearch only works online (pattern C) and we need to play the success sound only when the request is successful PAY_MONEY_REQUEST_ON_SEARCH: 'PayMoneyRequestOnSearch', @@ -1054,6 +1053,7 @@ type SideEffectRequestCommandParameters = { [SIDE_EFFECT_REQUEST_COMMANDS.COMPLETE_HYBRID_APP_ONBOARDING]: EmptyObject; [SIDE_EFFECT_REQUEST_COMMANDS.CONNECT_POLICY_TO_QUICKBOOKS_DESKTOP]: Parameters.ConnectPolicyToQuickBooksDesktopParams; [SIDE_EFFECT_REQUEST_COMMANDS.SIGN_IN_USER]: SignInUserParams; + [SIDE_EFFECT_REQUEST_COMMANDS.SIGN_UP_USER]: Parameters.SignUpUserParams; [SIDE_EFFECT_REQUEST_COMMANDS.PAY_MONEY_REQUEST_ON_SEARCH]: Parameters.PayMoneyRequestOnSearchParams; }; diff --git a/src/libs/HybridApp.ts b/src/libs/HybridApp.ts index 257191af8eca..99843665f1d7 100644 --- a/src/libs/HybridApp.ts +++ b/src/libs/HybridApp.ts @@ -1,27 +1,36 @@ -import {DeviceEventEmitter, NativeModules} from 'react-native'; +import {NativeModules} from 'react-native'; import Onyx from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Credentials, HybridApp, Session, TryNewDot} from '@src/types/onyx'; import * as HybridAppActions from './actions/HybridApp'; -import type {Init} from './ActiveClientManager/types'; import Log from './Log'; +import {getCurrentUserEmail} from './Network/NetworkStore'; let currentHybridApp: OnyxEntry; let currentTryNewDot: OnyxEntry; +let currentCredentials: OnyxEntry; Onyx.connect({ key: ONYXKEYS.HYBRID_APP, callback: (hybridApp) => { - handleChangeInHybridAppSignInFlow(hybridApp, currentTryNewDot); + handleChangeInHybridAppSignInFlow(hybridApp, currentTryNewDot, currentCredentials); }, }); Onyx.connect({ key: ONYXKEYS.NVP_TRYNEWDOT, callback: (tryNewDot) => { - handleChangeInHybridAppSignInFlow(currentHybridApp, tryNewDot); + handleChangeInHybridAppSignInFlow(currentHybridApp, tryNewDot, currentCredentials); + }, +}); + +Onyx.connect({ + key: ONYXKEYS.CREDENTIALS, + callback: (credentials) => { + currentCredentials = credentials; + handleChangeInHybridAppSignInFlow(currentHybridApp, currentTryNewDot, credentials); }, }); @@ -36,11 +45,11 @@ Onyx.connect({ }, }); -let credentials: OnyxEntry; +let activePolicyID: OnyxEntry; Onyx.connect({ - key: ONYXKEYS.CREDENTIALS, - callback: (newCredentials) => { - credentials = newCredentials; + key: ONYXKEYS.NVP_ACTIVE_POLICY_ID, + callback: (newActivePolicyID) => { + activePolicyID = newActivePolicyID; }, }); @@ -48,71 +57,39 @@ function shouldUseOldApp(tryNewDot?: TryNewDot) { return tryNewDot?.classicRedirect.dismissed === true; } -function handleChangeInHybridAppSignInFlow(hybridApp: OnyxEntry, tryNewDot: OnyxEntry) { +function handleChangeInHybridAppSignInFlow(hybridApp: OnyxEntry, tryNewDot: OnyxEntry, credentials: OnyxEntry) { if (!NativeModules.HybridAppModule) { return; } - if (currentHybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.RETRYING_AFTER_FAILURE && hybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED) { - if (hybridApp?.oldDotSignInError) { - Log.info('[HybridApp] Unable to open OldDot. Sign-in has failed again'); - HybridAppActions.setOldDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.FAILED_AGAIN); - return; - } - - Log.info('[HybridApp] Closing NewDot as retrying sign-in to OldDot succeeded'); - NativeModules.HybridAppModule.closeReactNativeApp(false, true); - } - - if ( - currentHybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.STARTED && - hybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED && - tryNewDot !== undefined && - shouldUseOldApp(tryNewDot) - ) { - if (hybridApp?.oldDotSignInError) { - Log.info('[HybridApp] Unable to open OldDot. Sign-in has failed'); - return; - } - - Log.info('[HybridApp] Closing NewDot as sign-in to OldDot succeeded'); - NativeModules.HybridAppModule.closeReactNativeApp(false, true); + if (!hybridApp?.useNewDotSignInPage) { + currentHybridApp = hybridApp; + currentTryNewDot = tryNewDot; + return; } - if ( - hybridApp?.newDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED && - hybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.NOT_STARTED && - credentials?.autoGeneratedLogin && - credentials?.autoGeneratedPassword && - tryNewDot !== undefined - ) { - if (!shouldUseOldApp(tryNewDot)) { - Log.info('[HybridApp] The user should see NewDot. There is no need to block the user on the `SignInPage` until the sign-in process is completed on the OldDot side.'); - HybridAppActions.setReadyToShowAuthScreens(true); - } - + if (hybridApp?.newDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED && tryNewDot !== undefined && !!credentials?.autoGeneratedLogin && !!credentials?.autoGeneratedPassword) { Log.info(`[HybridApp] Performing sign-in${shouldUseOldApp(tryNewDot) ? '' : ' (in background)'} on OldDot side`); - HybridAppActions.startOldDotSignIn(credentials.autoGeneratedLogin, credentials.autoGeneratedPassword); + NativeModules.HybridAppModule.signInToOldDot( + credentials.autoGeneratedLogin, + credentials.autoGeneratedPassword, + currentSession?.authToken ?? '', + currentSession?.encryptedAuthToken ?? '', + getCurrentUserEmail() ?? '', + activePolicyID ?? '', + ); + HybridAppActions.setUseNewDotSignInPage(false).then(() => { + if (shouldUseOldApp(tryNewDot)) { + NativeModules.HybridAppModule.closeReactNativeApp(false, false); + } else { + Log.info('[HybridApp] The user should see NewDot. There is no need to block the user on the `SignInPage` until the sign-in process is completed on the OldDot side.'); + HybridAppActions.setReadyToShowAuthScreens(true); + } + }); } currentHybridApp = hybridApp; currentTryNewDot = tryNewDot; } -function onOldDotSignInFinished(data: string) { - const eventData = JSON.parse(data) as {errorMessage: string}; - Log.info(`[HybridApp] onSignInFinished event received`, true, {eventData}); - HybridAppActions.finishOldDotSignIn(eventData.errorMessage); -} - -const init: Init = () => { - if (!NativeModules.HybridAppModule) { - return; - } - - DeviceEventEmitter.addListener(CONST.EVENTS.HYBRID_APP.ON_SIGN_IN_FINISHED, onOldDotSignInFinished); -}; - -export default {init}; - -export {shouldUseOldApp}; +export default {shouldUseOldApp}; diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.tsx b/src/libs/Navigation/AppNavigator/PublicScreens.tsx index fa880a5246f2..3a4e867e8e84 100644 --- a/src/libs/Navigation/AppNavigator/PublicScreens.tsx +++ b/src/libs/Navigation/AppNavigator/PublicScreens.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import {NativeModules} from 'react-native'; import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator'; import type {PublicScreensParamList} from '@navigation/types'; import ConnectionCompletePage from '@pages/ConnectionCompletePage'; diff --git a/src/libs/Navigation/AppNavigator/index.native.tsx b/src/libs/Navigation/AppNavigator/index.native.tsx index 16c867afb622..48f1ef2f2dd5 100644 --- a/src/libs/Navigation/AppNavigator/index.native.tsx +++ b/src/libs/Navigation/AppNavigator/index.native.tsx @@ -2,6 +2,7 @@ import React, {memo, useContext, useEffect, useMemo} from 'react'; import {NativeModules} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import {InitialURLContext} from '@components/InitialURLContextProvider'; +import HybridApp from '@libs/HybridApp'; import Navigation from '@libs/Navigation/Navigation'; import ONYXKEYS from '@src/ONYXKEYS'; import type {TryNewDot} from '@src/types/onyx'; @@ -12,10 +13,6 @@ type AppNavigatorProps = { authenticated: boolean; }; -function shouldUseOldApp(tryNewDot?: TryNewDot) { - return tryNewDot?.classicRedirect.dismissed === true; -} - function AppNavigator({authenticated}: AppNavigatorProps) { const {initialURL, setInitialURL} = useContext(InitialURLContext); const [tryNewDot] = useOnyx(ONYXKEYS.NVP_TRYNEWDOT); @@ -25,7 +22,7 @@ function AppNavigator({authenticated}: AppNavigatorProps) { if (!NativeModules.HybridAppModule) { return authenticated; } - if (shouldUseOldApp(tryNewDot) && !hybridApp?.isSingleNewDotEntry) { + if (HybridApp.shouldUseOldApp(tryNewDot) && !hybridApp?.isSingleNewDotEntry) { return false; } diff --git a/src/libs/actions/HybridApp/index.ts b/src/libs/actions/HybridApp/index.ts index 073cf2f3ae8a..0bcda22b8b2c 100644 --- a/src/libs/actions/HybridApp/index.ts +++ b/src/libs/actions/HybridApp/index.ts @@ -1,7 +1,5 @@ -import {NativeModules} from 'react-native'; import Onyx from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; -import * as Session from '@userActions/Session'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {HybridApp} from '@src/types/onyx'; @@ -28,88 +26,18 @@ function setNewDotSignInState(newDotSignInState: ValueOf) { - Onyx.merge(ONYXKEYS.HYBRID_APP, {oldDotSignInState}); +function setUseNewDotSignInPage(useNewDotSignInPage: boolean) { + return Onyx.merge(ONYXKEYS.HYBRID_APP, {useNewDotSignInPage}); } /* * Starts HybridApp sign-in flow from the beginning. - * In certain cases, it can perform sign-out if necessary */ -function resetSignInFlow(signOut = false) { - if (signOut) { - Onyx.merge(ONYXKEYS.HYBRID_APP, { - oldDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.WAITING_FOR_SIGN_OUT, - newDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.WAITING_FOR_SIGN_OUT, - }); - - Session.signOut(); - - Onyx.merge(ONYXKEYS.SESSION, null); - } - +function resetSignInFlow() { Onyx.merge(ONYXKEYS.HYBRID_APP, { readyToShowAuthScreens: false, - oldDotSignInError: null, - oldDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.NOT_STARTED, newDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.NOT_STARTED, - }); -} - -/* - * Sets proper sign-in state after sign-out on NewDot side - */ -function resetStateAfterSignOut() { - Onyx.merge(ONYXKEYS.HYBRID_APP, { useNewDotSignInPage: true, - readyToShowAuthScreens: false, - oldDotSignInError: null, - oldDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.NOT_STARTED, - newDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.NOT_STARTED, - }); -} - -/* - * Starts OldDot sign-in flow - */ -function startOldDotSignIn(autoGeneratedLogin: string, autoGeneratedPassword: string) { - Onyx.merge(ONYXKEYS.HYBRID_APP, { - oldDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.STARTED, - }); - - NativeModules.HybridAppModule.signInToOldDot(autoGeneratedLogin, autoGeneratedPassword, false, '', '', '', ''); -} - -/* - * Retries sign-in on OldDot side - */ -function retryOldDotSignInAfterFailure( - autoGeneratedLogin: string, - autoGeneratedPassword: string, - isNewUser: boolean, - authToken: string, - encryptedAuthToken: string, - email: string, - policyID: string, -) { - Onyx.merge(ONYXKEYS.HYBRID_APP, { - oldDotSignInError: null, - oldDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.RETRYING_AFTER_FAILURE, - }); - - NativeModules.HybridAppModule.signInToOldDot(autoGeneratedLogin, autoGeneratedPassword, isNewUser, authToken, encryptedAuthToken, email, policyID); -} - -/* - * Updates Onyx state after successful OldDot sign-in - */ -function finishOldDotSignIn(errorMessage: string | null) { - Onyx.merge(ONYXKEYS.HYBRID_APP, { - oldDotSignInError: errorMessage, - oldDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED, }); } @@ -121,8 +49,6 @@ function prepareHybridAppAfterTransitionToNewDot(hybridApp: HybridApp) { return Onyx.merge(ONYXKEYS.HYBRID_APP, { ...hybridApp, readyToShowAuthScreens: false, - oldDotSignInError: null, - oldDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.NOT_STARTED, newDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.NOT_STARTED, }); } @@ -134,15 +60,4 @@ function prepareHybridAppAfterTransitionToNewDot(hybridApp: HybridApp) { }); } -export { - parseHybridAppSettings, - setReadyToShowAuthScreens, - setNewDotSignInState, - setOldDotSignInState, - resetSignInFlow, - retryOldDotSignInAfterFailure, - finishOldDotSignIn, - startOldDotSignIn, - prepareHybridAppAfterTransitionToNewDot, - resetStateAfterSignOut, -}; +export {parseHybridAppSettings, setReadyToShowAuthScreens, setNewDotSignInState, resetSignInFlow, prepareHybridAppAfterTransitionToNewDot, setUseNewDotSignInPage}; diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index 7c09abc55951..5c71e562c1cb 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -37,6 +37,7 @@ import NetworkConnection from '@libs/NetworkConnection'; import * as Pusher from '@libs/Pusher/pusher'; import * as ReportUtils from '@libs/ReportUtils'; import * as SessionUtils from '@libs/SessionUtils'; +import {resetDidUserLogInDuringSession} from '@libs/SessionUtils'; import {clearSoundAssetsCache} from '@libs/Sound'; import Timers from '@libs/Timers'; import {hideContextMenu} from '@pages/home/report/ContextMenu/ReportActionContextMenu'; @@ -54,6 +55,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {HybridAppRoute, Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; +import type {TryNewDot} from '@src/types/onyx'; import type Credentials from '@src/types/onyx/Credentials'; import type Session from '@src/types/onyx/Session'; import type {AutoAuthState} from '@src/types/onyx/Session'; @@ -485,10 +487,16 @@ function signUpUser() { const params: SignUpUserParams = {email: credentials.login, preferredLocale}; - API.write(WRITE_COMMANDS.SIGN_UP_USER, params, {optimisticData, successData, failureData}); + // eslint-disable-next-line rulesdir/no-api-side-effects-method + API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.SIGN_UP_USER, params, {optimisticData, successData, failureData}).then((response) => { + if (!response) { + return; + } + Onyx.merge(ONYXKEYS.NVP_TRYNEWDOT, {classicRedirect: {dismissed: !response.tryNewDot}}); + }); } -function setupNewDotAfterTransitionFromOldDot(route: Route, hybridAppSettings: string) { +function setupNewDotAfterTransitionFromOldDot(route: Route, hybridAppSettings: string, tryNewDot: TryNewDot | undefined) { const parsedHybridAppSettings = HybridAppActions.parseHybridAppSettings(hybridAppSettings); const {initialOnyxValues} = parsedHybridAppSettings; const {hybridApp, ...newDotOnyxValues} = initialOnyxValues; @@ -501,16 +509,28 @@ function setupNewDotAfterTransitionFromOldDot(route: Route, hybridAppSettings: s return Onyx.clear(); }; + const resetDidUserLoginDuringSessionIfNeeded = () => { + if (newDotOnyxValues.nvp_tryNewDot === undefined || tryNewDot?.classicRedirect.dismissed !== true) { + return Promise.resolve(); + } + + Log.info("[HybridApp] OpenApp hasn't been called yet. Calling `resetDidUserLogInDuringSession`"); + resetDidUserLogInDuringSession(); + }; + + const handleDelegateAccess = () => { + if (!hybridApp.shouldRemoveDelegatedAccess) { + return; + } + return Onyx.clear(KEYS_TO_PRESERVE_DELEGATE_ACCESS); + }; + return new Promise((resolve) => { clearOnyxBeforeSignIn() .then(() => HybridAppActions.prepareHybridAppAfterTransitionToNewDot(hybridApp)) + .then(resetDidUserLoginDuringSessionIfNeeded) .then(() => Onyx.multiSet(newDotOnyxValues)) - .then(() => { - if (!hybridApp.shouldRemoveDelegatedAccess) { - return; - } - return Onyx.clear(KEYS_TO_PRESERVE_DELEGATE_ACCESS); - }) + .then(handleDelegateAccess) .catch((error) => { Log.hmmm('[HybridApp] Initialization of HybridApp has failed. Forcing transition', {error}); }) diff --git a/src/libs/actions/SignInRedirect.ts b/src/libs/actions/SignInRedirect.ts index ca4cf7529d47..2c81fe01fb0f 100644 --- a/src/libs/actions/SignInRedirect.ts +++ b/src/libs/actions/SignInRedirect.ts @@ -1,9 +1,7 @@ -import {NativeModules} from 'react-native'; import Onyx from 'react-native-onyx'; import * as ErrorUtils from '@libs/ErrorUtils'; import type {OnyxKey} from '@src/ONYXKEYS'; import ONYXKEYS from '@src/ONYXKEYS'; -import * as HybridAppActions from './HybridApp'; import * as Policy from './Policy/Policy'; let currentIsOffline: boolean | undefined; @@ -41,10 +39,6 @@ function clearStorageAndRedirect(errorMessage?: string): Promise { // `Onyx.clear` reinitializes the Onyx instance with initial values so use `Onyx.merge` instead of `Onyx.set` Onyx.merge(ONYXKEYS.SESSION, {errors: ErrorUtils.getMicroSecondOnyxErrorWithMessage(errorMessage)}); - - if (NativeModules.HybridAppModule) { - HybridAppActions.resetStateAfterSignOut(); - } }); } diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 6d1a557890fe..07071736cd10 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -1,9 +1,8 @@ import {useRoute} from '@react-navigation/native'; import React, {useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react'; -import type {ReactNode} from 'react'; // eslint-disable-next-line no-restricted-imports import type {GestureResponderEvent, ScrollView as RNScrollView, ScrollViewProps, StyleProp, ViewStyle} from 'react-native'; -import {ActivityIndicator, NativeModules, View} from 'react-native'; +import {NativeModules, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import AccountSwitcher from '@components/AccountSwitcher'; @@ -33,7 +32,6 @@ import useWaitForNavigation from '@hooks/useWaitForNavigation'; import {resetExitSurveyForm} from '@libs/actions/ExitSurvey'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; -import {getCurrentUserEmail} from '@libs/Network/NetworkStore'; import * as SubscriptionUtils from '@libs/SubscriptionUtils'; import * as UserUtils from '@libs/UserUtils'; import {hasGlobalWorkspaceSettingsRBR} from '@libs/WorkspacesSettingsUtils'; @@ -74,9 +72,6 @@ type MenuData = { iconRight?: IconAsset; badgeText?: string; badgeStyle?: ViewStyle; - shouldShowRightComponent?: boolean; - rightComponent?: ReactNode; - disabled?: boolean; }; type Menu = {sectionStyle: StyleProp; sectionTranslationKey: TranslationPaths; items: MenuData[]}; @@ -89,11 +84,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST); const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); const [privatePersonalDetails] = useOnyx(ONYXKEYS.PRIVATE_PERSONAL_DETAILS); - const [hybridApp] = useOnyx(ONYXKEYS.HYBRID_APP); - const [credentials] = useOnyx(ONYXKEYS.CREDENTIALS); const [tryNewDot] = useOnyx(ONYXKEYS.NVP_TRYNEWDOT); - const [session] = useOnyx(ONYXKEYS.SESSION); - const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate}); @@ -250,34 +241,11 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr { translationKey: 'exitSurvey.goToExpensifyClassic', icon: Expensicons.ExpensifyLogoNew, - shouldShowRightComponent: hybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.RETRYING_AFTER_FAILURE, - disabled: hybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.RETRYING_AFTER_FAILURE, - rightComponent: ( - - - - ), ...(NativeModules.HybridAppModule ? { action: () => { - if (hybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED && !hybridApp?.oldDotSignInError) { - NativeModules.HybridAppModule.closeReactNativeApp(false, true); - setInitialURL(undefined); - return; - } - - HybridAppActions.retryOldDotSignInAfterFailure( - credentials?.autoGeneratedLogin ?? '', - credentials?.autoGeneratedPassword ?? '', - !credentials?.autoGeneratedLogin, - session?.authToken ?? '', - session?.encryptedAuthToken ?? '', - getCurrentUserEmail() ?? '', - activePolicyID ?? '', - ); + NativeModules.HybridAppModule.closeReactNativeApp(false, true); + setInitialURL(undefined); }, } : { @@ -316,27 +284,12 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr icon: Expensicons.Exit, action: () => { signOut(false); - HybridAppActions.resetStateAfterSignOut(); + HybridAppActions.resetSignInFlow(); }, }, ], }; - }, [ - styles.pt4, - styles.popoverMenuIcon, - hybridApp?.oldDotSignInState, - hybridApp?.oldDotSignInError, - theme.spinner, - credentials?.autoGeneratedLogin, - credentials?.autoGeneratedPassword, - session?.authToken, - session?.encryptedAuthToken, - activePolicyID, - setInitialURL, - shouldOpenBookACall, - signOut, - isActingAsDelegate - ]); + }, [styles.pt4, setInitialURL, shouldOpenBookACall, signOut, isActingAsDelegate]); /** * Retuns JSX.Element with menu items @@ -373,7 +326,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr title={keyTitle} icon={item.icon} iconType={item.iconType} - disabled={isExecuting || item.disabled} + disabled={isExecuting} onPress={singleExecution(() => { if (item.action) { item.action(); @@ -399,8 +352,6 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr !!item.routeName && !!(activeCentralPaneRoute.name.toLowerCase().replaceAll('_', '') === item.routeName.toLowerCase().replaceAll('/', '')) } - shouldShowRightComponent={item.shouldShowRightComponent} - rightComponent={item.rightComponent} iconRight={item.iconRight} shouldShowRightIcon={item.shouldShowRightIcon} shouldIconUseAutoWidthStyle @@ -503,17 +454,6 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr onConfirm={() => signOut(true)} onCancel={() => toggleSignoutConfirmModal(false)} /> - { - HybridAppActions.setOldDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED); - }} - shouldShowCancelButton={false} - /> { + setNewDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.STARTED); Session.signUpUser(); setReadyToShowAuthScreens(true); }} diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx index 9dd5082c08ca..64b4d83284a6 100755 --- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx +++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx @@ -21,7 +21,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; import AccountUtils from '@libs/AccountUtils'; import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus'; import * as ErrorUtils from '@libs/ErrorUtils'; -import {shouldUseOldApp} from '@libs/HybridApp'; import * as ValidationUtils from '@libs/ValidationUtils'; import ChangeExpensifyLoginLink from '@pages/signin/ChangeExpensifyLoginLink'; import Terms from '@pages/signin/Terms'; @@ -52,10 +51,6 @@ function BaseValidateCodeForm({autoComplete, isUsingRecoveryCode, setIsUsingReco const [account] = useOnyx(ONYXKEYS.ACCOUNT); const [credentials] = useOnyx(ONYXKEYS.CREDENTIALS); const [session] = useOnyx(ONYXKEYS.SESSION); - const [tryNewDot] = useOnyx(ONYXKEYS.NVP_TRYNEWDOT); - const [hybridApp] = useOnyx(ONYXKEYS.HYBRID_APP, { - initialValue: {oldDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.NOT_STARTED, newDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.NOT_STARTED}, - }); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); @@ -75,7 +70,7 @@ function BaseValidateCodeForm({autoComplete, isUsingRecoveryCode, setIsUsingReco const input2FARef = useRef(); const timerRef = useRef(); - const hasError = (!!account && !isEmptyObject(account?.errors) && !needToClearError) || !!hybridApp?.oldDotSignInError; + const hasError = !!account && !isEmptyObject(account?.errors) && !needToClearError; const isLoadingResendValidationForm = account?.loadingForm === CONST.FORMS.RESEND_VALIDATE_CODE_FORM; const shouldDisableResendValidateCode = isOffline ?? account?.isLoading; const isValidateCodeFormSubmitting = AccountUtils.isValidateCodeFormSubmitting(account); @@ -184,13 +179,9 @@ function BaseValidateCodeForm({autoComplete, isUsingRecoveryCode, setIsUsingReco * Clears local and Onyx sign in states */ const clearSignInData = useCallback(() => { - if (NativeModules.HybridAppModule && session?.authToken) { - HybridAppActions.resetSignInFlow(true); - } - clearLocalSignInData(); SessionActions.clearSignInData(); - }, [clearLocalSignInData, session?.authToken]); + }, [clearLocalSignInData]); useImperativeHandle(forwardedRef, () => ({ clearSignInData, @@ -247,7 +238,7 @@ function BaseValidateCodeForm({autoComplete, isUsingRecoveryCode, setIsUsingReco */ const validateAndSubmitForm = useCallback(() => { if (NativeModules.HybridAppModule && session?.authToken) { - HybridAppActions.resetSignInFlow(true); + HybridAppActions.resetSignInFlow(); } if (account?.isLoading) { @@ -381,7 +372,7 @@ function BaseValidateCodeForm({autoComplete, isUsingRecoveryCode, setIsUsingReco key="validateCode" testID="validateCode" /> - {hasError && } + {hasError && } {timeRemaining > 0 && !isOffline ? ( @@ -413,9 +404,7 @@ function BaseValidateCodeForm({autoComplete, isUsingRecoveryCode, setIsUsingReco large style={[styles.mv3]} text={translate('common.signIn')} - isLoading={ - shouldUseOldApp(tryNewDot) ? isValidateCodeFormSubmitting || hybridApp?.oldDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.STARTED : isValidateCodeFormSubmitting - } + isLoading={isValidateCodeFormSubmitting} onPress={validateAndSubmitForm} /> diff --git a/src/types/modules/react-native.d.ts b/src/types/modules/react-native.d.ts index 7d083c07076b..a1b2b0c587b8 100644 --- a/src/types/modules/react-native.d.ts +++ b/src/types/modules/react-native.d.ts @@ -9,7 +9,7 @@ type HybridAppModule = { closeReactNativeApp: (shouldSignOut: boolean, shouldSetNVP: boolean) => void; completeOnboarding: (status: boolean) => void; switchAccount: (newDotCurrentAccount: string) => void; - signInToOldDot: (autoGeneratedLogin: string, autoGeneratedPassword: string, isNewUser: boolean, authToken: string, encryptedAuthToken: string, email: string, policyID: string) => void; + signInToOldDot: (autoGeneratedLogin: string, autoGeneratedPassword: string, authToken: string, encryptedAuthToken: string, email: string, policyID: string) => void; signOutFromOldDot: () => void; exitApp: () => void; }; diff --git a/src/types/onyx/HybridApp.ts b/src/types/onyx/HybridApp.ts index 688ac01d05ed..d7ab1b0cf61f 100644 --- a/src/types/onyx/HybridApp.ts +++ b/src/types/onyx/HybridApp.ts @@ -6,16 +6,13 @@ type HybridApp = { /** Stores the information if HybridApp uses NewDot's sign-in flow */ useNewDotSignInPage?: boolean; - /** Stores the information about error that occurred on OldDot side during sign-in */ - oldDotSignInError?: string | null; - /** Tells if we can show AuthScreens */ readyToShowAuthScreens?: boolean; /** States whether we transitioned from OldDot to show only certain group of screens */ isSingleNewDotEntry?: boolean; - /** stores infromation if last log out was performed from OldDot */ + /** Stores information if last log out was performed from OldDot */ loggedOutFromOldDot?: boolean; /** */ @@ -23,9 +20,6 @@ type HybridApp = { /** Describes current stage of NewDot sign-in */ newDotSignInState?: ValueOf; - - /** Describes current stage of OldDot sign-in */ - oldDotSignInState?: ValueOf; }; export default HybridApp;