From d17e7f0da781cf0ee0bab0b2c50c3ee31f40305d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Warcho=C5=82?= <61014013+war-in@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:10:01 +0200 Subject: [PATCH] Revert "Bring back new sign-in page" --- __mocks__/@ua/react-native-airship.ts | 9 +- .../ReactNativeHybridApp.kt | 18 -- .../hybrid-app/ios/ReactNativeHybridApp.mm | 12 -- .../src/NativeReactNativeHybridApp.ts | 3 - modules/hybrid-app/src/index.native.ts | 9 - modules/hybrid-app/src/index.ts | 12 -- modules/hybrid-app/src/types.ts | 3 - src/App.tsx | 87 ++++---- src/CONFIG.ts | 5 - src/CONST/index.ts | 6 - src/Expensify.tsx | 11 +- src/HybridAppHandler.tsx | 22 +-- src/ONYXKEYS.ts | 8 +- src/components/BookTravelButton.tsx | 18 +- .../CustomStatusBarAndBackground/index.tsx | 5 +- src/components/ScreenWrapper/index.tsx | 11 +- .../AppleSignIn/index.android.tsx | 8 +- .../SignInButtons/AppleSignIn/index.ios.tsx | 8 +- .../GoogleSignIn/index.native.tsx | 12 +- src/hooks/useOnboardingFlow.ts | 2 +- src/libs/HybridApp.ts | 100 ---------- .../Navigation/AppNavigator/AuthScreens.tsx | 33 ++-- .../Navigation/AppNavigator/PublicScreens.tsx | 4 +- .../Navigation/AppNavigator/index.native.tsx | 17 +- .../PushNotification/index.native.ts | 23 +-- .../subscribeToPushNotifications.ts | 4 +- src/libs/actions/App.ts | 1 - src/libs/actions/Delegate.ts | 1 - src/libs/actions/HybridApp/index.ts | 89 --------- src/libs/actions/HybridApp/types.ts | 11 -- src/libs/actions/QueuedOnyxUpdates.ts | 1 - src/libs/actions/Report.ts | 5 - src/libs/actions/Session/index.ts | 186 ++++++++++-------- src/libs/actions/SignInRedirect.ts | 5 - src/libs/actions/User.ts | 5 - src/pages/ErrorPage/SessionExpiredPage.tsx | 4 +- .../BaseOnboardingAccounting.tsx | 11 +- src/pages/ValidateLoginPage/index.tsx | 15 +- .../FloatingActionButtonAndPopover.tsx | 11 +- src/pages/settings/InitialSettingsPage.tsx | 12 +- .../MergeAccounts/MergeResultPage.tsx | 11 +- src/pages/signin/ChooseSSOOrMagicCode.tsx | 51 ++--- .../signin/SAMLSignInPage/index.native.tsx | 7 +- src/pages/signin/SignInPage.tsx | 11 -- src/pages/signin/SignUpWelcomeForm.tsx | 18 +- .../ValidateCodeForm/BaseValidateCodeForm.tsx | 31 +-- src/types/onyx/HybridApp.ts | 49 ----- src/types/onyx/TryNewDot.ts | 6 +- src/types/onyx/index.ts | 2 - 49 files changed, 299 insertions(+), 694 deletions(-) delete mode 100644 src/libs/HybridApp.ts delete mode 100644 src/libs/actions/HybridApp/index.ts delete mode 100644 src/libs/actions/HybridApp/types.ts delete mode 100644 src/types/onyx/HybridApp.ts diff --git a/__mocks__/@ua/react-native-airship.ts b/__mocks__/@ua/react-native-airship.ts index 08ec1b781fc21..a60053df475e0 100644 --- a/__mocks__/@ua/react-native-airship.ts +++ b/__mocks__/@ua/react-native-airship.ts @@ -6,13 +6,6 @@ enum EventType { PushReceived = 'com.airship.push_received', } -// eslint-disable-next-line no-restricted-syntax -enum PermissionStatus { - Granted = 'granted', - Denied = 'denied', - NotDetermined = 'not_determined', -} - // eslint-disable-next-line @typescript-eslint/no-namespace namespace iOS { /** @@ -78,4 +71,4 @@ const Airship: Partial = { export default Airship; -export {EventType, iOS, PermissionStatus}; +export {EventType, iOS}; diff --git a/modules/hybrid-app/android/src/main/java/com/expensify/reactnativehybridapp/ReactNativeHybridApp.kt b/modules/hybrid-app/android/src/main/java/com/expensify/reactnativehybridapp/ReactNativeHybridApp.kt index 46c7968d6cca5..9a743490ffa3f 100644 --- a/modules/hybrid-app/android/src/main/java/com/expensify/reactnativehybridapp/ReactNativeHybridApp.kt +++ b/modules/hybrid-app/android/src/main/java/com/expensify/reactnativehybridapp/ReactNativeHybridApp.kt @@ -36,22 +36,4 @@ class ReactNativeHybridApp(reactContext: ReactApplicationContext) : override fun sendAuthToken(authToken: String?) { Log.d(NAME, "`sendAuthToken` should never be called in standalone `New Expensify` app") } - - override fun signInToOldDot( - autoGeneratedLogin: String, - autoGeneratedPassword: String, - authToken: String, - email: String, - policyID: String - ) { - Log.d(NAME, "`signInToOldDot` should never be called in standalone `New Expensify` app") - } - - override fun signOutFromOldDot() { - Log.d(NAME, "`signOutFromOldDot` should never be called in standalone `New Expensify` app") - } - - override fun clearOldDotAfterSignOut() { - Log.d(NAME, "`clearOldDotAfterSignOut` should never be called in standalone `New Expensify` app") - } } diff --git a/modules/hybrid-app/ios/ReactNativeHybridApp.mm b/modules/hybrid-app/ios/ReactNativeHybridApp.mm index f94bccf5d5605..6b093b3f26b5b 100644 --- a/modules/hybrid-app/ios/ReactNativeHybridApp.mm +++ b/modules/hybrid-app/ios/ReactNativeHybridApp.mm @@ -27,18 +27,6 @@ - (void)sendAuthToken:(NSString *)authToken { NSLog(@"[ReactNativeHybridApp] `sendAuthToken` should never be called in standalone `New Expensify` app"); } -- (void)signInToOldDot:(NSString *)autoGeneratedLogin autoGeneratedPassword:(NSString *)autoGeneratedPassword authToken:(NSString *)authToken email:(NSString *)email policyID:(NSString *)policyID { - NSLog(@"[ReactNativeHybridApp] `signInToOldDot` should never be called in standalone `New Expensify` app"); -} - -- (void)signOutFromOldDot { - NSLog(@"[ReactNativeHybridApp] `signOutFromOldDot` should never be called in standalone `New Expensify` app"); -} - -- (void)clearOldDotAfterSignOut { - NSLog(@"[ReactNativeHybridApp] `clearOldDotAfterSignOut` should never be called in standalone `New Expensify` app"); -} - - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { diff --git a/modules/hybrid-app/src/NativeReactNativeHybridApp.ts b/modules/hybrid-app/src/NativeReactNativeHybridApp.ts index 4001adacff494..a18f44f87d509 100644 --- a/modules/hybrid-app/src/NativeReactNativeHybridApp.ts +++ b/modules/hybrid-app/src/NativeReactNativeHybridApp.ts @@ -9,9 +9,6 @@ export interface Spec extends TurboModule { completeOnboarding: (status: boolean) => void; switchAccount: (newDotCurrentAccountEmail: string, authToken: string, policyID: string, accountID: string) => void; sendAuthToken: (authToken: string) => void; - signInToOldDot: (autoGeneratedLogin: string, autoGeneratedPassword: string, authToken: string, email: string, policyID: string) => void; - signOutFromOldDot: () => void; - clearOldDotAfterSignOut: () => void; } export default TurboModuleRegistry.getEnforcing('ReactNativeHybridApp'); diff --git a/modules/hybrid-app/src/index.native.ts b/modules/hybrid-app/src/index.native.ts index 83d342cf922f4..50dfd719449a9 100644 --- a/modules/hybrid-app/src/index.native.ts +++ b/modules/hybrid-app/src/index.native.ts @@ -20,15 +20,6 @@ const HybridAppModule: HybridAppModuleType = { sendAuthToken({authToken}) { ReactNativeHybridApp.sendAuthToken(authToken); }, - signInToOldDot({autoGeneratedLogin, autoGeneratedPassword, authToken, email, policyID}) { - ReactNativeHybridApp.signInToOldDot(autoGeneratedLogin, autoGeneratedPassword, authToken, email, policyID); - }, - signOutFromOldDot() { - ReactNativeHybridApp.signOutFromOldDot(); - }, - clearOldDotAfterSignOut() { - ReactNativeHybridApp.clearOldDotAfterSignOut(); - }, }; export default HybridAppModule; diff --git a/modules/hybrid-app/src/index.ts b/modules/hybrid-app/src/index.ts index f9c8bb22ec7d5..ca45aeeb20757 100644 --- a/modules/hybrid-app/src/index.ts +++ b/modules/hybrid-app/src/index.ts @@ -24,18 +24,6 @@ const HybridAppModule: HybridAppModuleType = { // eslint-disable-next-line no-console console.warn('HybridAppModule: `sendAuthToken` should never be called on web'); }, - signInToOldDot() { - // eslint-disable-next-line no-console - console.warn('HybridAppModule: `signInToOldDot` should never be called on web'); - }, - signOutFromOldDot() { - // eslint-disable-next-line no-console - console.warn('HybridAppModule: `signOutFromOldDot` should never be called on web'); - }, - clearOldDotAfterSignOut() { - // eslint-disable-next-line no-console - console.warn('HybridAppModule: `clearOldDotAfterSignOut` should never be called on web'); - }, }; export default HybridAppModule; diff --git a/modules/hybrid-app/src/types.ts b/modules/hybrid-app/src/types.ts index 7d33f31446f06..8a40a1fc5767b 100644 --- a/modules/hybrid-app/src/types.ts +++ b/modules/hybrid-app/src/types.ts @@ -5,9 +5,6 @@ type HybridAppModuleType = { completeOnboarding: (args: {status: boolean}) => void; switchAccount: (args: {newDotCurrentAccountEmail: string; authToken: string; policyID: string; accountID: string}) => void; sendAuthToken: (args: {authToken: string}) => void; - signInToOldDot: (args: {autoGeneratedLogin: string; autoGeneratedPassword: string; authToken: string; email: string; policyID: string}) => void; - signOutFromOldDot: () => void; - clearOldDotAfterSignOut: () => void; }; export default HybridAppModuleType; diff --git a/src/App.tsx b/src/App.tsx index 06f05de7a5018..dc17fe242a550 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -41,7 +41,6 @@ import {CurrentReportIDContextProvider} from './hooks/useCurrentReportID'; import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop'; import HybridAppHandler from './HybridAppHandler'; import OnyxUpdateManager from './libs/actions/OnyxUpdateManager'; -import './libs/HybridApp'; import {AttachmentModalContextProvider} from './pages/media/AttachmentModalScreen/AttachmentModalContext'; import type {Route} from './ROUTES'; import './setup/backgroundTask'; @@ -82,53 +81,47 @@ function App({url, hybridAppSettings}: AppProps) { - - - - - - - - - - - + + + + + + + + diff --git a/src/CONFIG.ts b/src/CONFIG.ts index 569995f679c99..aa6e3a325d499 100644 --- a/src/CONFIG.ts +++ b/src/CONFIG.ts @@ -95,12 +95,7 @@ export default { GOOGLE_SIGN_IN: { // cspell:disable-next-line WEB_CLIENT_ID: '921154746561-gpsoaqgqfuqrfsjdf8l7vohfkfj7b9up.apps.googleusercontent.com', - // cspell:disable-next-line IOS_CLIENT_ID: '921154746561-s3uqn2oe4m85tufi6mqflbfbuajrm2i3.apps.googleusercontent.com', - // cspell:disable-next-line - HYBRID_APP_WEB_CLIENT_ID: '1008697809946-5e095eqem3o6ugtpc2rjf7v880tcp28p.apps.googleusercontent.com', - // cspell:disable-next-line - HYBRID_APP_IOS_CLIENT_ID: '1008697809946-sh04nqq0hea396s1qdqqbj6ia649odb2.apps.googleusercontent.com', }, GCP_GEOLOCATION_API_KEY: googleGeolocationAPIKey, FIREBASE_WEB_CONFIG: { diff --git a/src/CONST/index.ts b/src/CONST/index.ts index b120caa3464f3..9ccf25c579248 100755 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -6724,12 +6724,6 @@ const CONST = { HIDDEN: `hidden`, }, - HYBRID_APP_SIGN_IN_STATE: { - NOT_STARTED: 'notStarted', - STARTED: 'started', - FINISHED: 'finished', - }, - CSV_IMPORT_COLUMNS: { EMAIL: 'email', NAME: 'name', diff --git a/src/Expensify.tsx b/src/Expensify.tsx index cc7586a0e2f0a..0cc71df88ed1b 100644 --- a/src/Expensify.tsx +++ b/src/Expensify.tsx @@ -99,7 +99,6 @@ function Expensify() { const [isSidebarLoaded] = useOnyx(ONYXKEYS.IS_SIDEBAR_LOADED, {canBeMissing: true}); const [screenShareRequest] = useOnyx(ONYXKEYS.SCREEN_SHARE_REQUEST, {canBeMissing: true}); const [lastVisitedPath] = useOnyx(ONYXKEYS.LAST_VISITED_PATH, {canBeMissing: true}); - const [hybridApp] = useOnyx(ONYXKEYS.HYBRID_APP, {canBeMissing: true}); useDebugShortcut(); @@ -115,12 +114,10 @@ function Expensify() { const isAuthenticated = useIsAuthenticated(); const autoAuthState = useMemo(() => session?.autoAuthState ?? '', [session]); - const shouldInit = isNavigationReady && hasAttemptedToOpenPublicRoom && !!preferredLocale && (CONFIG.IS_HYBRID_APP ? !hybridApp?.loggedOutFromOldDot : true); - const shouldHideSplash = - shouldInit && - (CONFIG.IS_HYBRID_APP - ? splashScreenState === CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN && (isAuthenticated || !!hybridApp?.useNewDotSignInPage) - : splashScreenState === CONST.BOOT_SPLASH_STATE.VISIBLE); + const shouldInit = isNavigationReady && hasAttemptedToOpenPublicRoom && !!preferredLocale; + const isSplashVisible = splashScreenState === CONST.BOOT_SPLASH_STATE.VISIBLE; + const isHybridAppReady = splashScreenState === CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN && isAuthenticated; + const shouldHideSplash = shouldInit && (CONFIG.IS_HYBRID_APP ? isHybridAppReady : isSplashVisible); const initializeClient = () => { if (!Visibility.isVisible()) { diff --git a/src/HybridAppHandler.tsx b/src/HybridAppHandler.tsx index 011e8998a43cc..59ec56bc1bcfc 100644 --- a/src/HybridAppHandler.tsx +++ b/src/HybridAppHandler.tsx @@ -1,32 +1,20 @@ import {useContext, useState} from 'react'; -import {useOnyx} from 'react-native-onyx'; import type {AppProps} from './App'; import CONFIG from './CONFIG'; import CONST from './CONST'; -import {parseHybridAppSettings} from './libs/actions/HybridApp'; -import {setupNewDotAfterTransitionFromOldDot} from './libs/actions/Session'; -import ONYXKEYS from './ONYXKEYS'; +import {signInAfterTransitionFromOldDot} from './libs/actions/Session'; import SplashScreenStateContext from './SplashScreenStateContext'; -import isLoadingOnyxValue from './types/utils/isLoadingOnyxValue'; function HybridAppHandler({hybridAppSettings}: AppProps) { const [signInHandled, setSignInHandled] = useState(false); - const {splashScreenState, setSplashScreenState} = useContext(SplashScreenStateContext); - const [tryNewDot, tryNewDotMetadata] = useOnyx(ONYXKEYS.NVP_TRY_NEW_DOT, {canBeMissing: true}); + const {setSplashScreenState} = useContext(SplashScreenStateContext); - const isLoading = isLoadingOnyxValue(tryNewDotMetadata); - - if (!CONFIG.IS_HYBRID_APP || !hybridAppSettings || signInHandled || isLoading) { + if (!CONFIG.IS_HYBRID_APP || !hybridAppSettings || signInHandled) { return null; } - const parsedHybridAppSettings = parseHybridAppSettings(hybridAppSettings); - setupNewDotAfterTransitionFromOldDot(parsedHybridAppSettings, tryNewDot).then(() => { - if (parsedHybridAppSettings.hybridApp?.loggedOutFromOldDot) { - setSplashScreenState(CONST.BOOT_SPLASH_STATE.HIDDEN); - } else if (splashScreenState === CONST.BOOT_SPLASH_STATE.VISIBLE) { - setSplashScreenState(CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN); - } + signInAfterTransitionFromOldDot(hybridAppSettings).then(() => { + setSplashScreenState(CONST.BOOT_SPLASH_STATE.READY_TO_BE_HIDDEN); setSignInHandled(true); }); diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index fd4b64451f793..bce349022a860 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -476,6 +476,9 @@ const ONYXKEYS = { /** Stores recently used currencies */ RECENTLY_USED_CURRENCIES: 'nvp_recentlyUsedCurrencies', + /** States whether we transitioned from OldDot to show only certain group of screens. It should be undefined on pure NewDot. */ + IS_SINGLE_NEW_DOT_ENTRY: 'isSingleNewDotEntry', + /** Company cards custom names */ NVP_EXPENSIFY_COMPANY_CARDS_CUSTOM_NAMES: 'nvp_expensify_ccCustomNames', @@ -532,9 +535,6 @@ const ONYXKEYS = { /** Set this gets redirected from global reimbursements flow */ IS_COMING_FROM_GLOBAL_REIMBURSEMENTS_FLOW: 'isComingFromGlobalReimbursementsFlow', - /** Stores HybridApp specific state required to interoperate with OldDot */ - HYBRID_APP: 'hybridApp', - /** Stores information for OpenUnreportedExpensesPage API call pagination */ HAS_MORE_UNREPORTED_TRANSACTIONS_RESULTS: 'hasMoreUnreportedTransactionsResults', @@ -1172,6 +1172,7 @@ type OnyxValuesMapping = { [ONYXKEYS.APPROVAL_WORKFLOW]: OnyxTypes.ApprovalWorkflowOnyx; [ONYXKEYS.IMPORTED_SPREADSHEET]: OnyxTypes.ImportedSpreadsheet; [ONYXKEYS.LAST_ROUTE]: string; + [ONYXKEYS.IS_SINGLE_NEW_DOT_ENTRY]: boolean | undefined; [ONYXKEYS.IS_USING_IMPORTED_STATE]: boolean; [ONYXKEYS.NVP_EXPENSIFY_COMPANY_CARDS_CUSTOM_NAMES]: Record; [ONYXKEYS.CONCIERGE_REPORT_ID]: string; @@ -1190,7 +1191,6 @@ type OnyxValuesMapping = { [ONYXKEYS.SCHEDULE_CALL_DRAFT]: OnyxTypes.ScheduleCallDraft; [ONYXKEYS.IS_FORCED_TO_CHANGE_CURRENCY]: boolean | undefined; [ONYXKEYS.IS_COMING_FROM_GLOBAL_REIMBURSEMENTS_FLOW]: boolean | undefined; - [ONYXKEYS.HYBRID_APP]: OnyxTypes.HybridApp; [ONYXKEYS.HAS_MORE_UNREPORTED_TRANSACTIONS_RESULTS]: boolean | undefined; [ONYXKEYS.IS_LOADING_UNREPORTED_TRANSACTIONS]: boolean | undefined; [ONYXKEYS.NVP_LAST_ECASH_IOS_LOGIN]: string; diff --git a/src/components/BookTravelButton.tsx b/src/components/BookTravelButton.tsx index 34cedb85eec04..15927fda953e9 100644 --- a/src/components/BookTravelButton.tsx +++ b/src/components/BookTravelButton.tsx @@ -1,6 +1,7 @@ +import HybridAppModule from '@expensify/react-native-hybrid-app'; import {Str} from 'expensify-common'; import type {ReactElement} from 'react'; -import React, {useCallback, useEffect, useState} from 'react'; +import React, {useCallback, useContext, useEffect, useState} from 'react'; import {useOnyx} from 'react-native-onyx'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; @@ -9,7 +10,6 @@ import usePolicy from '@hooks/usePolicy'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import {openTravelDotLink} from '@libs/actions/Link'; -import {closeReactNativeApp} from '@libs/actions/Session'; import {cleanupTravelProvisioningSession} from '@libs/actions/Travel'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; @@ -22,6 +22,7 @@ import ROUTES from '@src/ROUTES'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import Button from './Button'; import ConfirmModal from './ConfirmModal'; +import CustomStatusBarAndBackgroundContext from './CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContext'; import DotIndicatorMessage from './DotIndicatorMessage'; import {RocketDude} from './Icon/Illustrations'; import Text from './Text'; @@ -61,6 +62,7 @@ function BookTravelButton({text, shouldRenderErrorMessageBelowButton = false, se const [travelSettings] = useOnyx(ONYXKEYS.NVP_TRAVEL_SETTINGS, {canBeMissing: false}); const [sessionEmail] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email, canBeMissing: false}); const primaryContactMethod = primaryLogin ?? sessionEmail ?? ''; + const {setRootStatusBarEnabled} = useContext(CustomStatusBarAndBackgroundContext); const {isBlockedFromSpotnanaTravel, isBetaEnabled} = usePermissions(); const [isPreventionModalVisible, setPreventionModalVisibility] = useState(false); const [isVerificationModalVisible, setVerificationModalVisibility] = useState(false); @@ -70,7 +72,7 @@ function BookTravelButton({text, shouldRenderErrorMessageBelowButton = false, se const groupPaidPolicies = activePolicies.filter((activePolicy) => activePolicy.type !== CONST.POLICY.TYPE.PERSONAL && isPaidGroupPolicy(activePolicy)); // Flag indicating whether NewDot was launched exclusively for Travel, // e.g., when the user selects "Trips" from the Expensify Classic menu in HybridApp. - const [hybridApp] = useOnyx(ONYXKEYS.HYBRID_APP, {canBeMissing: true}); + const [wasNewDotLaunchedJustForTravel] = useOnyx(ONYXKEYS.IS_SINGLE_NEW_DOT_ENTRY, {canBeMissing: false}); const hidePreventionModal = () => setPreventionModalVisibility(false); const hideVerificationModal = () => setVerificationModalVisibility(false); @@ -128,14 +130,15 @@ function BookTravelButton({text, shouldRenderErrorMessageBelowButton = false, se openTravelDotLink(policy?.id) ?.then(() => { // When a user selects "Trips" in the Expensify Classic menu, the HybridApp opens the ManageTrips page in NewDot. - // The isSingleNewDotEntry flag indicates if NewDot was launched solely for this purpose. - if (!CONFIG.IS_HYBRID_APP || !hybridApp?.isSingleNewDotEntry) { + // The wasNewDotLaunchedJustForTravel flag indicates if NewDot was launched solely for this purpose. + if (!CONFIG.IS_HYBRID_APP || !wasNewDotLaunchedJustForTravel) { return; } // Close NewDot if it was opened only for Travel, as its purpose is now fulfilled. Log.info('[HybridApp] Returning to OldDot after opening TravelDot'); - closeReactNativeApp({shouldSignOut: false, shouldSetNVP: false}); + HybridAppModule.closeReactNativeApp({shouldSignOut: false, shouldSetNVP: false}); + setRootStatusBarEnabled(false); }) ?.catch(() => { setErrorMessage(translate('travel.errorMessage')); @@ -169,7 +172,8 @@ function BookTravelButton({text, shouldRenderErrorMessageBelowButton = false, se styles.link, StyleUtils, translate, - hybridApp?.isSingleNewDotEntry, + wasNewDotLaunchedJustForTravel, + setRootStatusBarEnabled, isUserValidated, groupPaidPolicies.length, isBetaEnabled, diff --git a/src/components/CustomStatusBarAndBackground/index.tsx b/src/components/CustomStatusBarAndBackground/index.tsx index 6f5c3b0e9c2e3..95ad1fe0f3a80 100644 --- a/src/components/CustomStatusBarAndBackground/index.tsx +++ b/src/components/CustomStatusBarAndBackground/index.tsx @@ -5,8 +5,6 @@ import useTheme from '@hooks/useTheme'; import {navigationRef} from '@libs/Navigation/Navigation'; import StatusBar from '@libs/StatusBar'; import type {StatusBarStyle} from '@styles/index'; -import ONYXKEYS from '@src/ONYXKEYS'; -import {useOnyx} from '../../../__mocks__/react-native-onyx'; import CustomStatusBarAndBackgroundContext from './CustomStatusBarAndBackgroundContext'; import updateGlobalBackgroundColor from './updateGlobalBackgroundColor'; import updateStatusBarAppearance from './updateStatusBarAppearance'; @@ -21,9 +19,8 @@ function CustomStatusBarAndBackground({isNested = false}: CustomStatusBarAndBack const {isRootStatusBarEnabled, setRootStatusBarEnabled} = useContext(CustomStatusBarAndBackgroundContext); const theme = useTheme(); const [statusBarStyle, setStatusBarStyle] = useState(); - const [hybridApp] = useOnyx(ONYXKEYS.HYBRID_APP, {canBeMissing: true}); - const isDisabled = (!isNested && !isRootStatusBarEnabled) || (hybridApp?.closingReactNativeApp ?? false); + const isDisabled = !isNested && !isRootStatusBarEnabled; // Disable the root status bar when a nested status bar is rendered useEffect(() => { diff --git a/src/components/ScreenWrapper/index.tsx b/src/components/ScreenWrapper/index.tsx index 87236fdc67106..c12b133451cbd 100644 --- a/src/components/ScreenWrapper/index.tsx +++ b/src/components/ScreenWrapper/index.tsx @@ -1,3 +1,4 @@ +import HybridAppModule from '@expensify/react-native-hybrid-app'; import {useIsFocused, useNavigation, usePreventRemove} from '@react-navigation/native'; import type {ForwardedRef, ReactNode} from 'react'; import React, {forwardRef, useContext, useEffect, useMemo, useState} from 'react'; @@ -6,6 +7,7 @@ import {Keyboard} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import type {EdgeInsets} from 'react-native-safe-area-context'; import CustomDevMenu from '@components/CustomDevMenu'; +import CustomStatusBarAndBackgroundContext from '@components/CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContext'; import FocusTrapForScreen from '@components/FocusTrap/FocusTrapForScreen'; import type FocusTrapForScreenProps from '@components/FocusTrap/FocusTrapForScreen/FocusTrapProps'; import HeaderGap from '@components/HeaderGap'; @@ -16,7 +18,6 @@ import useNetwork from '@hooks/useNetwork'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings'; import useThemeStyles from '@hooks/useThemeStyles'; -import {closeReactNativeApp} from '@libs/actions/Session'; import NarrowPaneContext from '@libs/Navigation/AppNavigator/Navigators/NarrowPaneContext'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types'; @@ -169,13 +170,15 @@ function ScreenWrapper( const shouldOffsetMobileOfflineIndicator = displaySmallScreenOfflineIndicator && addSmallScreenOfflineIndicatorBottomSafeAreaPadding && isOffline; const {initialURL} = useContext(InitialURLContext); - const [hybridApp] = useOnyx(ONYXKEYS.HYBRID_APP, {canBeMissing: true}); + const [isSingleNewDotEntry] = useOnyx(ONYXKEYS.IS_SINGLE_NEW_DOT_ENTRY, {canBeMissing: true}); + const {setRootStatusBarEnabled} = useContext(CustomStatusBarAndBackgroundContext); - usePreventRemove((hybridApp?.isSingleNewDotEntry ?? false) && initialURL === Navigation.getActiveRouteWithoutParams(), () => { + usePreventRemove((isSingleNewDotEntry ?? false) && initialURL === Navigation.getActiveRouteWithoutParams(), () => { if (!CONFIG.IS_HYBRID_APP) { return; } - closeReactNativeApp({shouldSignOut: false, shouldSetNVP: false}); + HybridAppModule.closeReactNativeApp({shouldSignOut: false, shouldSetNVP: false}); + setRootStatusBarEnabled(false); }); useEffect(() => { diff --git a/src/components/SignInButtons/AppleSignIn/index.android.tsx b/src/components/SignInButtons/AppleSignIn/index.android.tsx index 46cf0e0ab46de..a528fe7c5a10c 100644 --- a/src/components/SignInButtons/AppleSignIn/index.android.tsx +++ b/src/components/SignInButtons/AppleSignIn/index.android.tsx @@ -1,9 +1,8 @@ import {appleAuthAndroid} from '@invertase/react-native-apple-authentication'; import React from 'react'; import IconButton from '@components/SignInButtons/IconButton'; -import {setNewDotSignInState} from '@libs/actions/HybridApp'; import Log from '@libs/Log'; -import {beginAppleSignIn} from '@userActions/Session'; +import * as Session from '@userActions/Session'; import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import type {AppleSignInProps} from '.'; @@ -38,10 +37,7 @@ function appleSignInRequest(): Promise { function AppleSignIn({onPress = () => {}}: AppleSignInProps) { const handleSignIn = () => { appleSignInRequest() - .then((token) => { - setNewDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.STARTED); - beginAppleSignIn(token); - }) + .then((token) => Session.beginAppleSignIn(token)) .catch((error: Record) => { if (error.message === appleAuthAndroid.Error.SIGNIN_CANCELLED) { return null; diff --git a/src/components/SignInButtons/AppleSignIn/index.ios.tsx b/src/components/SignInButtons/AppleSignIn/index.ios.tsx index de808ecd49cb7..57aae97b9c48f 100644 --- a/src/components/SignInButtons/AppleSignIn/index.ios.tsx +++ b/src/components/SignInButtons/AppleSignIn/index.ios.tsx @@ -2,9 +2,8 @@ import appleAuth from '@invertase/react-native-apple-authentication'; import type {AppleError} from '@invertase/react-native-apple-authentication'; import React from 'react'; import IconButton from '@components/SignInButtons/IconButton'; -import {setNewDotSignInState} from '@libs/actions/HybridApp'; import Log from '@libs/Log'; -import {beginAppleSignIn} from '@userActions/Session'; +import * as Session from '@userActions/Session'; import CONST from '@src/CONST'; import type {AppleSignInProps} from '.'; @@ -37,10 +36,7 @@ function appleSignInRequest(): Promise { function AppleSignIn({onPress = () => {}}: AppleSignInProps) { const handleSignIn = () => { appleSignInRequest() - .then((token) => { - setNewDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.STARTED); - beginAppleSignIn(token); - }) + .then((token) => Session.beginAppleSignIn(token)) .catch((error: {code: AppleError}) => { if (error.code === appleAuth.Error.CANCELED) { return null; diff --git a/src/components/SignInButtons/GoogleSignIn/index.native.tsx b/src/components/SignInButtons/GoogleSignIn/index.native.tsx index afdc9edb0bd36..4a70a10ef0171 100644 --- a/src/components/SignInButtons/GoogleSignIn/index.native.tsx +++ b/src/components/SignInButtons/GoogleSignIn/index.native.tsx @@ -1,9 +1,8 @@ import {GoogleSignin, statusCodes} from '@react-native-google-signin/google-signin'; import React from 'react'; import IconButton from '@components/SignInButtons/IconButton'; -import {setNewDotSignInState} from '@libs/actions/HybridApp'; import Log from '@libs/Log'; -import {beginGoogleSignIn} from '@userActions/Session'; +import * as Session from '@userActions/Session'; import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import type {GoogleSignInProps} from '.'; @@ -14,8 +13,8 @@ import type GoogleError from './types'; */ function googleSignInRequest() { GoogleSignin.configure({ - webClientId: CONFIG.IS_HYBRID_APP ? CONFIG.GOOGLE_SIGN_IN.HYBRID_APP_WEB_CLIENT_ID : CONFIG.GOOGLE_SIGN_IN.WEB_CLIENT_ID, - iosClientId: CONFIG.IS_HYBRID_APP ? CONFIG.GOOGLE_SIGN_IN.HYBRID_APP_IOS_CLIENT_ID : CONFIG.GOOGLE_SIGN_IN.IOS_CLIENT_ID, + webClientId: CONFIG.GOOGLE_SIGN_IN.WEB_CLIENT_ID, + iosClientId: CONFIG.GOOGLE_SIGN_IN.IOS_CLIENT_ID, offlineAccess: false, }); @@ -26,10 +25,7 @@ function googleSignInRequest() { GoogleSignin.signIn() .then((response) => response.idToken) - .then((token) => { - setNewDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.STARTED); - beginGoogleSignIn(token); - }) + .then((token) => Session.beginGoogleSignIn(token)) .catch((error: GoogleError | undefined) => { // Handle unexpected error shape if (error?.code === undefined) { diff --git a/src/hooks/useOnboardingFlow.ts b/src/hooks/useOnboardingFlow.ts index 3462ff52f0233..bf229b62ea289 100644 --- a/src/hooks/useOnboardingFlow.ts +++ b/src/hooks/useOnboardingFlow.ts @@ -32,7 +32,7 @@ function useOnboardingFlowRouter() { const [dismissedProductTraining, dismissedProductTrainingMetadata] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); - const [isSingleNewDotEntry, isSingleNewDotEntryMetadata] = useOnyx(ONYXKEYS.HYBRID_APP, {selector: (data) => data?.isSingleNewDotEntry, canBeMissing: true}); + const [isSingleNewDotEntry, isSingleNewDotEntryMetadata] = useOnyx(ONYXKEYS.IS_SINGLE_NEW_DOT_ENTRY, {canBeMissing: true}); useEffect(() => { // This should delay opening the onboarding modal so it does not interfere with the ongoing ReportScreen params changes diff --git a/src/libs/HybridApp.ts b/src/libs/HybridApp.ts deleted file mode 100644 index d37d919ccb6b8..0000000000000 --- a/src/libs/HybridApp.ts +++ /dev/null @@ -1,100 +0,0 @@ -import HybridAppModule from '@expensify/react-native-hybrid-app'; -import Onyx from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx'; -import CONFIG from '@src/CONFIG'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import type {Credentials, HybridApp, Session, TryNewDot} from '@src/types/onyx'; -import {setNewDotSignInState, setReadyToShowAuthScreens, setUseNewDotSignInPage} from './actions/HybridApp'; -import {closeReactNativeApp} from './actions/Session'; -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, currentCredentials); - }, -}); - -Onyx.connect({ - key: ONYXKEYS.NVP_TRY_NEW_DOT, - callback: (tryNewDot) => { - handleChangeInHybridAppSignInFlow(currentHybridApp, tryNewDot, currentCredentials); - }, -}); - -Onyx.connect({ - key: ONYXKEYS.CREDENTIALS, - callback: (credentials) => { - currentCredentials = credentials; - handleChangeInHybridAppSignInFlow(currentHybridApp, currentTryNewDot, credentials); - }, -}); - -let currentSession: OnyxEntry; -Onyx.connect({ - key: ONYXKEYS.SESSION, - callback: (session: OnyxEntry) => { - if (!currentSession?.authToken && session?.authToken && currentHybridApp?.newDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.STARTED) { - setNewDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED); - } - currentSession = session; - }, -}); - -let activePolicyID: OnyxEntry; -Onyx.connect({ - key: ONYXKEYS.NVP_ACTIVE_POLICY_ID, - callback: (newActivePolicyID) => { - activePolicyID = newActivePolicyID; - }, -}); - -function shouldUseOldApp(tryNewDot?: TryNewDot) { - if (!!tryNewDot && !tryNewDot.classicRedirect) { - return true; - } - return tryNewDot?.classicRedirect?.dismissed === true; -} - -function handleChangeInHybridAppSignInFlow(hybridApp: OnyxEntry, tryNewDot: OnyxEntry, credentials: OnyxEntry) { - if (!CONFIG.IS_HYBRID_APP) { - return; - } - - if (!hybridApp?.useNewDotSignInPage) { - currentHybridApp = hybridApp; - currentTryNewDot = tryNewDot; - return; - } - - if (hybridApp?.newDotSignInState === CONST.HYBRID_APP_SIGN_IN_STATE.FINISHED && tryNewDot !== undefined && !!credentials?.autoGeneratedLogin && !!credentials?.autoGeneratedPassword) { - // It's better to not pass function directly to Log.info to avoid bugs with evaluation - const shouldUseOD = shouldUseOldApp(tryNewDot); - Log.info(`[HybridApp] Performing sign-in${shouldUseOD ? '' : ' (in background)'} on OldDot side`); - HybridAppModule.signInToOldDot({ - autoGeneratedLogin: credentials.autoGeneratedLogin, - autoGeneratedPassword: credentials.autoGeneratedPassword, - authToken: currentSession?.authToken ?? '', - email: getCurrentUserEmail() ?? '', - // eslint-disable-next-line rulesdir/no-default-id-values - policyID: activePolicyID ?? '', - }); - setUseNewDotSignInPage(false).then(() => { - if (shouldUseOD) { - closeReactNativeApp({shouldSignOut: false, shouldSetNVP: 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.'); - setReadyToShowAuthScreens(true); - } - }); - } - - currentHybridApp = hybridApp; - currentTryNewDot = tryNewDot; -} diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index d4b3409b0865a..d40102010bc1b 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -307,23 +307,26 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie init(); } - // If we are on this screen then we are "logged in", but the user might not have "just logged in". They could be reopening the app - // or returning from background. If so, we'll assume they have some app data already and we can call reconnectApp() instead of openApp() and connect() for delegator from OldDot. - if (SessionUtils.didUserLogInDuringSession() || delegatorEmail) { - if (delegatorEmail) { - connect(delegatorEmail, true) - ?.then((success) => { - App.setAppLoading(!!success); - }) - .finally(() => { - setIsDelegatorFromOldDotIsReady(true); - }); + // In Hybrid App we decide to call one of those method when booting ND and we don't want to duplicate calls + if (!CONFIG.IS_HYBRID_APP) { + // If we are on this screen then we are "logged in", but the user might not have "just logged in". They could be reopening the app + // or returning from background. If so, we'll assume they have some app data already and we can call reconnectApp() instead of openApp() and connect() for delegator from OldDot. + if (SessionUtils.didUserLogInDuringSession() || delegatorEmail) { + if (delegatorEmail) { + connect(delegatorEmail, true) + ?.then((success) => { + App.setAppLoading(!!success); + }) + .finally(() => { + setIsDelegatorFromOldDotIsReady(true); + }); + } else { + App.openApp(); + } } else { - App.openApp(); + Log.info('[AuthScreens] Sending ReconnectApp'); + App.reconnectApp(initialLastUpdateIDAppliedToClient); } - } else { - Log.info('[AuthScreens] Sending ReconnectApp'); - App.reconnectApp(initialLastUpdateIDAppliedToClient); } App.setUpPoliciesAndNavigate(session); diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.tsx b/src/libs/Navigation/AppNavigator/PublicScreens.tsx index 0c66afec9bf3c..9204ba8b9563c 100644 --- a/src/libs/Navigation/AppNavigator/PublicScreens.tsx +++ b/src/libs/Navigation/AppNavigator/PublicScreens.tsx @@ -5,6 +5,7 @@ import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigati import {InternalPlatformAnimations} from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation'; import type {PublicScreensParamList} from '@navigation/types'; import ConnectionCompletePage from '@pages/ConnectionCompletePage'; +import SessionExpiredPage from '@pages/ErrorPage/SessionExpiredPage'; import LogInWithShortLivedAuthTokenPage from '@pages/LogInWithShortLivedAuthTokenPage'; import AppleSignInDesktopPage from '@pages/signin/AppleSignInDesktopPage'; import GoogleSignInDesktopPage from '@pages/signin/GoogleSignInDesktopPage'; @@ -12,6 +13,7 @@ import SAMLSignInPage from '@pages/signin/SAMLSignInPage'; import SignInPage from '@pages/signin/SignInPage'; import UnlinkLoginPage from '@pages/UnlinkLoginPage'; import ValidateLoginPage from '@pages/ValidateLoginPage'; +import CONFIG from '@src/CONFIG'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import defaultScreenOptions from './defaultScreenOptions'; @@ -31,7 +33,7 @@ function PublicScreens() { { - if (!CONFIG.IS_HYBRID_APP) { - return authenticated; - } - - return authenticated && hybridApp?.readyToShowAuthScreens; - }, [hybridApp?.readyToShowAuthScreens, authenticated]); - - if (shouldShowAuthScreens) { + if (authenticated) { const AuthScreens = require('./AuthScreens').default; // These are the protected screens and only accessible when an authToken is present diff --git a/src/libs/Notification/PushNotification/index.native.ts b/src/libs/Notification/PushNotification/index.native.ts index 854aeba8074f2..a38e9d98a8e45 100644 --- a/src/libs/Notification/PushNotification/index.native.ts +++ b/src/libs/Notification/PushNotification/index.native.ts @@ -1,8 +1,7 @@ import type {PushPayload} from '@ua/react-native-airship'; -import Airship, {EventType, PermissionStatus} from '@ua/react-native-airship'; +import Airship, {EventType} from '@ua/react-native-airship'; import Log from '@libs/Log'; import ShortcutManager from '@libs/ShortcutManager'; -import CONFIG from '@src/CONFIG'; import ForegroundNotifications from './ForegroundNotifications'; import type {NotificationDataMap, NotificationTypes} from './NotificationType'; import NotificationType from './NotificationType'; @@ -80,28 +79,18 @@ const register: Register = (notificationID) => { Airship.contact .getNamedUserId() .then((userID) => { - // In the HybridApp, the contact identity is set on the YAPL side after sign-in. - // Since the Airship instance is shared between NewDot and OldDot, - // NewDot users won't see the push notification permission prompt as we return early in this case. - // Therefore, we cannot handle the HybridApp scenario here. - if (!CONFIG.IS_HYBRID_APP && userID === notificationID.toString()) { + if (userID === notificationID.toString()) { // No need to register again for this notificationID. return; } - // Get permissions to display push notifications if not determined (prompts user on iOS, but not Android) - Airship.push.getNotificationStatus().then(({notificationPermissionStatus}) => { - if (notificationPermissionStatus !== PermissionStatus.NotDetermined) { + // Get permissions to display push notifications (prompts user on iOS, but not Android) + Airship.push.enableUserNotifications().then((isEnabled) => { + if (isEnabled) { return; } - Airship.push.enableUserNotifications().then((isEnabled) => { - if (isEnabled) { - return; - } - - Log.info('[PushNotification] User has disabled visible push notifications for this app.'); - }); + Log.info('[PushNotification] User has disabled visible push notifications for this app.'); }); // Register this device as a named user in AirshipAPI. diff --git a/src/libs/Notification/PushNotification/subscribeToPushNotifications.ts b/src/libs/Notification/PushNotification/subscribeToPushNotifications.ts index 95b308b1f8c06..88acb4687054b 100644 --- a/src/libs/Notification/PushNotification/subscribeToPushNotifications.ts +++ b/src/libs/Notification/PushNotification/subscribeToPushNotifications.ts @@ -41,12 +41,12 @@ Onyx.connect({ let isSingleNewDotEntry: boolean | undefined; Onyx.connect({ - key: ONYXKEYS.HYBRID_APP, + key: ONYXKEYS.IS_SINGLE_NEW_DOT_ENTRY, callback: (value) => { if (!value) { return; } - isSingleNewDotEntry = value?.isSingleNewDotEntry; + isSingleNewDotEntry = value; }, }); diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index f1298c4866f9e..017d10ded4989 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -152,7 +152,6 @@ const KEYS_TO_PRESERVE: OnyxKey[] = [ ONYXKEYS.NVP_PREFERRED_LOCALE, ONYXKEYS.CREDENTIALS, ONYXKEYS.PRESERVED_USER_SESSION, - ONYXKEYS.HYBRID_APP, ]; Onyx.connect({ diff --git a/src/libs/actions/Delegate.ts b/src/libs/actions/Delegate.ts index 0a06a3627c820..f60b5b1dfd881 100644 --- a/src/libs/actions/Delegate.ts +++ b/src/libs/actions/Delegate.ts @@ -70,7 +70,6 @@ const KEYS_TO_PRESERVE_DELEGATE_ACCESS = [ ONYXKEYS.IS_LOADING_APP, ONYXKEYS.HAS_LOADED_APP, ONYXKEYS.STASHED_CREDENTIALS, - ONYXKEYS.HYBRID_APP, // We need to preserve the sidebar loaded state since we never unmount the sidebar when connecting as a delegate // This allows the report screen to load correctly when the delegate token expires and the delegate is returned to their original account. diff --git a/src/libs/actions/HybridApp/index.ts b/src/libs/actions/HybridApp/index.ts deleted file mode 100644 index 6f655b83a4bb4..0000000000000 --- a/src/libs/actions/HybridApp/index.ts +++ /dev/null @@ -1,89 +0,0 @@ -import Onyx from 'react-native-onyx'; -import type {ValueOf} from 'type-fest'; -import CONFIG from '@src/CONFIG'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import type {HybridApp} from '@src/types/onyx'; -import type HybridAppSettings from './types'; - -/* - * Parses initial settings passed from OldDot app - */ -function parseHybridAppSettings(hybridAppSettings: string): HybridAppSettings { - return JSON.parse(hybridAppSettings) as HybridAppSettings; -} - -/* - * Changes value of `readyToShowAuthScreens` - */ -function setReadyToShowAuthScreens(readyToShowAuthScreens: boolean) { - // This value is only relevant for HybridApp, so we can skip it in other environments. - if (!CONFIG.IS_HYBRID_APP) { - return; - } - Onyx.merge(ONYXKEYS.HYBRID_APP, {readyToShowAuthScreens}); -} - -/* - * Changes NewDot sign-in state - */ -function setNewDotSignInState(newDotSignInState: ValueOf) { - // This value is only relevant for HybridApp, so we can skip it in other environments. - if (!CONFIG.IS_HYBRID_APP) { - return; - } - Onyx.merge(ONYXKEYS.HYBRID_APP, {newDotSignInState}); -} - -function setUseNewDotSignInPage(useNewDotSignInPage: boolean) { - // This value is only relevant for HybridApp, so we can skip it in other environments. - if (!CONFIG.IS_HYBRID_APP) { - return Promise.resolve(); - } - return Onyx.merge(ONYXKEYS.HYBRID_APP, {useNewDotSignInPage}); -} - -function setClosingReactNativeApp(closingReactNativeApp: boolean) { - // This value is only relevant for HybridApp, so we can skip it in other environments. - if (!CONFIG.IS_HYBRID_APP) { - return; - } - Onyx.merge(ONYXKEYS.HYBRID_APP, {closingReactNativeApp}); -} - -/* - * Starts HybridApp sign-in flow from the beginning. - */ -function resetSignInFlow() { - // This value is only relevant for HybridApp, so we can skip it in other environments. - if (!CONFIG.IS_HYBRID_APP) { - return; - } - - Onyx.merge(ONYXKEYS.HYBRID_APP, { - readyToShowAuthScreens: false, - newDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.NOT_STARTED, - useNewDotSignInPage: true, - }); -} - -/* - * Updates Onyx state after start of React Native runtime based on initial `useNewDotSignInPage` value - */ -function prepareHybridAppAfterTransitionToNewDot(hybridApp: HybridApp) { - if (hybridApp?.useNewDotSignInPage) { - return Onyx.merge(ONYXKEYS.HYBRID_APP, { - ...hybridApp, - readyToShowAuthScreens: !(hybridApp?.useNewDotSignInPage ?? false), - newDotSignInState: CONST.HYBRID_APP_SIGN_IN_STATE.NOT_STARTED, - }); - } - - // When we transition with useNewDotSignInPage === false, it means that we're already authenticated on NewDot side. - return Onyx.merge(ONYXKEYS.HYBRID_APP, { - ...hybridApp, - readyToShowAuthScreens: true, - }); -} - -export {parseHybridAppSettings, setReadyToShowAuthScreens, setNewDotSignInState, resetSignInFlow, prepareHybridAppAfterTransitionToNewDot, setUseNewDotSignInPage, setClosingReactNativeApp}; diff --git a/src/libs/actions/HybridApp/types.ts b/src/libs/actions/HybridApp/types.ts deleted file mode 100644 index 5d4ab1431cbc7..0000000000000 --- a/src/libs/actions/HybridApp/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type ONYXKEYS from '@src/ONYXKEYS'; -import type {TryNewDot} from '@src/types/onyx'; -import type HybridApp from '@src/types/onyx/HybridApp'; - -type HybridAppSettings = { - [ONYXKEYS.HYBRID_APP]: HybridApp; - [ONYXKEYS.NVP_TRY_NEW_DOT]?: TryNewDot; - [ONYXKEYS.ACCOUNT]?: {shouldUseStagingServer: boolean}; -}; - -export default HybridAppSettings; diff --git a/src/libs/actions/QueuedOnyxUpdates.ts b/src/libs/actions/QueuedOnyxUpdates.ts index e419c759950f1..ef3f2c9c8ad81 100644 --- a/src/libs/actions/QueuedOnyxUpdates.ts +++ b/src/libs/actions/QueuedOnyxUpdates.ts @@ -32,7 +32,6 @@ function flushQueue(): Promise { if (!currentAccountID && !CONFIG.IS_TEST_ENV && !CONFIG.E2E_TESTING) { const preservedKeys: OnyxKey[] = [ - ONYXKEYS.NVP_TRY_NEW_DOT, ONYXKEYS.NVP_TRY_FOCUS_MODE, ONYXKEYS.PREFERRED_THEME, ONYXKEYS.NVP_PREFERRED_LOCALE, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 312de5f7c9260..91f5655ef8f28 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3388,11 +3388,6 @@ function openReportFromDeepLink(url: string) { return; } - if (CONST.REGEX.ROUTES.VALIDATE_LOGIN.test(`${route}`)) { - Navigation.navigate(route as Route); - return; - } - // Navigate to the report after sign-in/sign-up. InteractionManager.runAfterInteractions(() => { waitForUserSignIn().then(() => { diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts index 33f86174d3a9d..d3fe1afedb53b 100644 --- a/src/libs/actions/Session/index.ts +++ b/src/libs/actions/Session/index.ts @@ -3,7 +3,7 @@ import throttle from 'lodash/throttle'; import type {ChannelAuthorizationData} from 'pusher-js/types/src/core/auth/options'; import type {ChannelAuthorizationCallback} from 'pusher-js/with-encryption'; import {InteractionManager, Linking} from 'react-native'; -import type {OnyxEntry, OnyxKey, OnyxUpdate} from 'react-native-onyx'; +import type {OnyxEntry, OnyxUpdate} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import * as PersistedRequests from '@libs/actions/PersistedRequests'; import * as API from '@libs/API'; @@ -41,16 +41,12 @@ import NetworkConnection from '@libs/NetworkConnection'; import Pusher from '@libs/Pusher'; import {getReportIDFromLink, parseReportRouteParams as parseReportRouteParamsReportUtils} 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'; -import {KEYS_TO_PRESERVE, openApp} from '@userActions/App'; +import {KEYS_TO_PRESERVE, openApp, reconnectApp} from '@userActions/App'; import {KEYS_TO_PRESERVE_DELEGATE_ACCESS} from '@userActions/Delegate'; import * as Device from '@userActions/Device'; -import * as HybridAppActions from '@userActions/HybridApp'; -import {setClosingReactNativeApp} from '@userActions/HybridApp'; -import type HybridAppSettings from '@userActions/HybridApp/types'; import redirectToSignIn from '@userActions/SignInRedirect'; import Timing from '@userActions/Timing'; import * as Welcome from '@userActions/Welcome'; @@ -60,7 +56,6 @@ 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 Locale from '@src/types/onyx/Locale'; import type Response from '@src/types/onyx/Response'; @@ -73,7 +68,6 @@ const INVALID_TOKEN = 'pizza'; let session: Session = {}; let authPromiseResolver: ((value: boolean) => void) | null = null; -let isSetUpReady = false; let hasSwitchedAccountInHybridMode = false; @@ -88,7 +82,7 @@ Onyx.connect({ authPromiseResolver(true); authPromiseResolver = null; } - if (CONFIG.IS_HYBRID_APP && session.authToken && session.authToken !== INVALID_TOKEN && isSetUpReady) { + if (CONFIG.IS_HYBRID_APP && session.authToken && session.authToken !== INVALID_TOKEN) { HybridAppModule.sendAuthToken({authToken: session.authToken}); } }, @@ -247,7 +241,7 @@ function isExpiredSession(sessionCreationDate: number): boolean { return new Date().getTime() - sessionCreationDate >= CONST.SESSION_EXPIRATION_TIME_MS; } -function signOutAndRedirectToSignIn(shouldResetToHome?: boolean, shouldStashSession?: boolean, shouldSignOutFromOldDot = true, shouldForceUseStashedSession?: boolean) { +function signOutAndRedirectToSignIn(shouldResetToHome?: boolean, shouldStashSession?: boolean, shouldKillHybridApp = true, shouldForceUseStashedSession?: boolean) { Log.info('Redirecting to Sign In because signOut() was called'); hideContextMenu(false); @@ -267,9 +261,10 @@ function signOutAndRedirectToSignIn(shouldResetToHome?: boolean, shouldStashSess return; } - // When signing out from the HybridApp, we need to sign out from the oldDot app as well - if (CONFIG.IS_HYBRID_APP && shouldSignOutFromOldDot) { - HybridAppModule.signOutFromOldDot(); + // In the HybridApp, we want the Old Dot to handle the sign out process + if (CONFIG.IS_HYBRID_APP && shouldKillHybridApp) { + HybridAppModule.closeReactNativeApp({shouldSignOut: true, shouldSetNVP: false}); + return; } const isSupportal = isSupportAuthToken(); @@ -519,89 +514,127 @@ function signUpUser() { API.write(WRITE_COMMANDS.SIGN_UP_USER, params, {optimisticData, successData, failureData}); } -function setupNewDotAfterTransitionFromOldDot(hybridAppSettings: HybridAppSettings, tryNewDot?: TryNewDot) { - const {hybridApp, ...newDotOnyxValues} = hybridAppSettings; - - const clearOnyxBeforeSignIn = () => { - if (!hybridApp.useNewDotSignInPage) { - return Promise.resolve(); - } +function getLastUpdateIDAppliedToClient(): Promise { + return new Promise((resolve) => { + Onyx.connect({ + key: ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT, + callback: (value) => resolve(value ?? 0), + }); + }); +} - return redirectToSignIn(); - }; +type HybridAppSettings = { + email: string; + authToken: string; + accountID: number; + autoGeneratedLogin: string; + autoGeneratedPassword: string; + clearOnyxOnStart: boolean; + completedHybridAppOnboarding: boolean; + isSingleNewDotEntry: boolean; + isStaging: boolean; + primaryLogin: string; + encryptedAuthToken: string; + nudgeMigrationTimestamp?: string; + oldDotOriginalAccountEmail?: string; + stashedAuthToken?: string; + stashedAccountID?: string; + requiresTwoFactorAuth: boolean; + needsTwoFactorAuthSetup: boolean; +}; - const resetDidUserLoginDuringSessionIfNeeded = () => { - if (newDotOnyxValues.nvp_tryNewDot === undefined || tryNewDot?.classicRedirect?.dismissed !== true) { +function signInAfterTransitionFromOldDot(hybridAppSettings: string) { + const { + email, + authToken, + encryptedAuthToken, + accountID, + autoGeneratedLogin, + autoGeneratedPassword, + clearOnyxOnStart, + completedHybridAppOnboarding, + nudgeMigrationTimestamp, + isSingleNewDotEntry, + isStaging, + primaryLogin, + oldDotOriginalAccountEmail, + stashedAuthToken, + stashedAccountID, + requiresTwoFactorAuth, + needsTwoFactorAuthSetup, + } = JSON.parse(hybridAppSettings) as HybridAppSettings; + + const clearOnyxForNewAccount = () => { + if (!clearOnyxOnStart) { return Promise.resolve(); } - Log.info("[HybridApp] OpenApp hasn't been called yet. Calling `resetDidUserLogInDuringSession`"); - resetDidUserLogInDuringSession(); + // We also need to reset: + // - IS_LOADING_APP after sign in to ensure the condition to show ExplanationModal runs once + // https://github.com/Expensify/App/issues/57575#issuecomment-2780189425 + return Onyx.clear(KEYS_TO_PRESERVE) + .then(() => Onyx.merge(ONYXKEYS.ACCOUNT, {delegatedAccess: null})) + .then(() => Onyx.merge(ONYXKEYS.IS_LOADING_APP, null)); }; - return clearOnyxBeforeSignIn() + return clearOnyxForNewAccount() .then(() => { // This section controls copilot changes const currentUserEmail = getCurrentUserEmail(); - // If ND and OD account are the same - do nothing - if (hybridApp?.delegateAccessData?.oldDotCurrentUserEmail === currentUserEmail) { + // If OD is in copilot, stash the original account data + if (oldDotOriginalAccountEmail && oldDotOriginalAccountEmail !== email) { + return Onyx.multiSet({ + [ONYXKEYS.STASHED_SESSION]: {email: oldDotOriginalAccountEmail, authToken: stashedAuthToken, accountID: Number(stashedAccountID)}, + [ONYXKEYS.STASHED_CREDENTIALS]: {autoGeneratedLogin, autoGeneratedPassword}, + }); + } + + // If OD and ND account are the same - do nothing + if (email === currentUserEmail) { return; } - const stashedData = hybridApp?.delegateAccessData?.isDelegateAccess - ? { - [ONYXKEYS.STASHED_CREDENTIALS]: credentials, - [ONYXKEYS.STASHED_SESSION]: session, - } - : { - [ONYXKEYS.STASHED_CREDENTIALS]: {}, - [ONYXKEYS.STASHED_SESSION]: {}, - }; - - // Account was changed on OD side - clear onyx and apply data - return Onyx.clear(KEYS_TO_PRESERVE_DELEGATE_ACCESS).then(() => - Onyx.multiSet({ - ...stashedData, - [ONYXKEYS.SESSION]: { - email: hybridApp?.delegateAccessData?.oldDotCurrentUserEmail, - authToken: hybridApp?.delegateAccessData?.oldDotCurrentAuthToken, - encryptedAuthToken: decodeURIComponent(hybridApp?.delegateAccessData?.oldDotCurrentEncryptedAuthToken ?? ''), - accountID: hybridApp?.delegateAccessData?.oldDotCurrentAccountID, - }, - [ONYXKEYS.CREDENTIALS]: { - autoGeneratedLogin: credentials?.autoGeneratedLogin, - autoGeneratedPassword: credentials?.autoGeneratedPassword, - }, - }) - .then(() => Onyx.merge(ONYXKEYS.ACCOUNT, {primaryLogin: hybridApp?.delegateAccessData?.oldDotCurrentUserEmail})) - .then(() => openApp()), - ); + // If account was changed to original one on OD side - clear onyx + if (!oldDotOriginalAccountEmail) { + return Onyx.clear(KEYS_TO_PRESERVE_DELEGATE_ACCESS); + } + + // If we're already logged in - do nothing, data will be set in next step + if (currentUserEmail) { + return; + } + + // If we're not logged in - set stashed data + return Onyx.multiSet({ + [ONYXKEYS.STASHED_CREDENTIALS]: {autoGeneratedLogin, autoGeneratedPassword}, + }); }) .then(() => - HybridAppActions.prepareHybridAppAfterTransitionToNewDot({ - ...hybridApp, - closingReactNativeApp: false, - }), + Onyx.multiSet({ + [ONYXKEYS.SESSION]: {email, authToken, encryptedAuthToken: decodeURIComponent(encryptedAuthToken), accountID: Number(accountID)}, + [ONYXKEYS.CREDENTIALS]: {autoGeneratedLogin, autoGeneratedPassword}, + [ONYXKEYS.IS_SINGLE_NEW_DOT_ENTRY]: isSingleNewDotEntry, + [ONYXKEYS.NVP_TRY_NEW_DOT]: { + classicRedirect: {completedHybridAppOnboarding}, + nudgeMigration: nudgeMigrationTimestamp ? {timestamp: new Date(nudgeMigrationTimestamp)} : undefined, + }, + [ONYXKEYS.ACCOUNT]: {shouldUseStagingServer: isStaging}, + }).then(() => Onyx.merge(ONYXKEYS.ACCOUNT, {primaryLogin, requiresTwoFactorAuth, needsTwoFactorAuthSetup})), ) - .then(resetDidUserLoginDuringSessionIfNeeded) - .then(() => Promise.all(Object.entries(newDotOnyxValues).map(([key, value]) => Onyx.merge(key as OnyxKey, value ?? {})))) .then(() => { - isSetUpReady = true; - return Promise.resolve(); + if (clearOnyxOnStart) { + return openApp(); + } + return getLastUpdateIDAppliedToClient().then((lastUpdateId) => { + return reconnectApp(lastUpdateId); + }); }) .catch((error) => { Log.hmmm('[HybridApp] Initialization of HybridApp has failed. Forcing transition', {error}); }); } -function closeReactNativeApp({shouldSignOut, shouldSetNVP}: {shouldSignOut: boolean; shouldSetNVP: boolean}) { - if (CONFIG.IS_HYBRID_APP) { - setClosingReactNativeApp(true); - } - HybridAppModule.closeReactNativeApp({shouldSignOut, shouldSetNVP}); -} - /** * Given an idToken from Sign in with Apple, checks the API to see if an account * exists for that email address and signs the user in if so. @@ -700,11 +733,7 @@ function signIn(validateCode: string, twoFactorAuthCode?: string) { params.validateCode = validateCode || credentials.validateCode; } - API.write(WRITE_COMMANDS.SIGN_IN_USER, params, { - optimisticData, - successData, - failureData, - }); + API.write(WRITE_COMMANDS.SIGN_IN_USER, params, {optimisticData, successData, failureData}); }); } @@ -1440,10 +1469,9 @@ export { isSupportAuthToken, hasStashedSession, signUpUser, - setupNewDotAfterTransitionFromOldDot, + signInAfterTransitionFromOldDot, AddWorkEmail, MergeIntoAccountAndLogin, resetSMSDeliveryFailureStatus, clearDisableTwoFactorAuthErrors, - closeReactNativeApp, }; diff --git a/src/libs/actions/SignInRedirect.ts b/src/libs/actions/SignInRedirect.ts index da39079dc5123..626641927b687 100644 --- a/src/libs/actions/SignInRedirect.ts +++ b/src/libs/actions/SignInRedirect.ts @@ -1,10 +1,8 @@ import Onyx from 'react-native-onyx'; import {getMicroSecondOnyxErrorWithMessage} from '@libs/ErrorUtils'; import {clearSessionStorage} from '@libs/Navigation/helpers/lastVisitedTabPathUtils'; -import CONFIG from '@src/CONFIG'; import type {OnyxKey} from '@src/ONYXKEYS'; import ONYXKEYS from '@src/ONYXKEYS'; -import {resetSignInFlow} from './HybridApp'; import {clearAllPolicies} from './Policy/Policy'; let currentIsOffline: boolean | undefined; @@ -35,9 +33,6 @@ function clearStorageAndRedirect(errorMessage?: string): Promise { } return Onyx.clear(keysToPreserve).then(() => { - if (CONFIG.IS_HYBRID_APP) { - resetSignInFlow(); - } clearAllPolicies(); if (!errorMessage) { return; diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index b2b6f67d246d4..3697bc1b6242b 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -117,11 +117,6 @@ function closeAccount(reason: string) { optimisticData, failureData, }); - - // On HybridApp, we need to sign out from the oldDot app as well to keep state of both apps in sync - if (CONFIG.IS_HYBRID_APP) { - HybridAppModule.signOutFromOldDot(); - } } /** diff --git a/src/pages/ErrorPage/SessionExpiredPage.tsx b/src/pages/ErrorPage/SessionExpiredPage.tsx index b2a6200e2c709..85dd6724a3bdd 100644 --- a/src/pages/ErrorPage/SessionExpiredPage.tsx +++ b/src/pages/ErrorPage/SessionExpiredPage.tsx @@ -1,3 +1,4 @@ +import HybridAppModule from '@expensify/react-native-hybrid-app'; import React from 'react'; import {View} from 'react-native'; import Icon from '@components/Icon'; @@ -8,7 +9,6 @@ import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import {closeReactNativeApp} from '@libs/actions/Session'; import Navigation from '@libs/Navigation/Navigation'; import {clearSignInData} from '@userActions/Session'; import CONFIG from '@src/CONFIG'; @@ -39,7 +39,7 @@ function SessionExpiredPage() { Navigation.goBack(); return; } - closeReactNativeApp({shouldSignOut: true, shouldSetNVP: false}); + HybridAppModule.closeReactNativeApp({shouldSignOut: true, shouldSetNVP: false}); }} > {translate('deeplinkWrapper.signIn')} diff --git a/src/pages/OnboardingAccounting/BaseOnboardingAccounting.tsx b/src/pages/OnboardingAccounting/BaseOnboardingAccounting.tsx index fe113f33060ac..e3f32bd02c76f 100644 --- a/src/pages/OnboardingAccounting/BaseOnboardingAccounting.tsx +++ b/src/pages/OnboardingAccounting/BaseOnboardingAccounting.tsx @@ -1,8 +1,10 @@ -import React, {useCallback, useEffect, useMemo, useState} from 'react'; +import HybridAppModule from '@expensify/react-native-hybrid-app'; +import React, {useCallback, useContext, useEffect, useMemo, useState} from 'react'; import {InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import type {SvgProps} from 'react-native-svg'; import Button from '@components/Button'; +import CustomStatusBarAndBackgroundContext from '@components/CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContext'; import FixedFooter from '@components/FixedFooter'; import FormHelpMessage from '@components/FormHelpMessage'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -26,7 +28,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {openOldDotLink} from '@libs/actions/Link'; import {createWorkspace, generatePolicyID} from '@libs/actions/Policy/Policy'; import {completeOnboarding} from '@libs/actions/Report'; -import {closeReactNativeApp} from '@libs/actions/Session'; import {setOnboardingAdminsChatReportID, setOnboardingPolicyID} from '@libs/actions/Welcome'; import navigateAfterOnboarding from '@libs/navigateAfterOnboarding'; import Navigation from '@libs/Navigation/Navigation'; @@ -100,6 +101,7 @@ function BaseOnboardingAccounting({shouldUseNativeStyles}: BaseOnboardingAccount const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); const {onboardingMessages} = useOnboardingMessages(); + const {setRootStatusBarEnabled} = useContext(CustomStatusBarAndBackgroundContext); // We need to use isSmallScreenWidth, see navigateAfterOnboarding function comment // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth @@ -136,13 +138,14 @@ function BaseOnboardingAccounting({shouldUseNativeStyles}: BaseOnboardingAccount } if (CONFIG.IS_HYBRID_APP) { - closeReactNativeApp({shouldSignOut: false, shouldSetNVP: true}); + HybridAppModule.closeReactNativeApp({shouldSignOut: false, shouldSetNVP: true}); + setRootStatusBarEnabled(false); return; } waitForIdle().then(() => { openOldDotLink(CONST.OLDDOT_URLS.INBOX, true); }); - }, [isLoading, prevIsLoading]); + }, [isLoading, prevIsLoading, setRootStatusBarEnabled]); const accountingOptions: OnboardingListItem[] = useMemo(() => { const createAccountingOption = (integration: Integration): OnboardingListItem => ({ diff --git a/src/pages/ValidateLoginPage/index.tsx b/src/pages/ValidateLoginPage/index.tsx index b3d24a4f84332..dc38916fdd109 100644 --- a/src/pages/ValidateLoginPage/index.tsx +++ b/src/pages/ValidateLoginPage/index.tsx @@ -2,9 +2,7 @@ import React, {useEffect} from 'react'; import {useOnyx} from 'react-native-onyx'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Navigation from '@libs/Navigation/Navigation'; -import {setNewDotSignInState} from '@userActions/HybridApp'; -import {handleExitToNavigation, signInWithValidateCodeAndNavigate} from '@userActions/Session'; -import CONFIG from '@src/CONFIG'; +import * as Session from '@userActions/Session'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type ValidateLoginPageProps from './types'; @@ -14,7 +12,7 @@ function ValidateLoginPage({ params: {accountID, validateCode, exitTo}, }, }: ValidateLoginPageProps) { - const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: true}); + const [session] = useOnyx(ONYXKEYS.SESSION); useEffect(() => { // Wait till navigation becomes available @@ -23,17 +21,12 @@ function ValidateLoginPage({ // If already signed in, do not show the validate code if not on web, // because we don't want to block the user with the interstitial page. if (exitTo) { - handleExitToNavigation(exitTo); + Session.handleExitToNavigation(exitTo); return; } Navigation.goBack(); } else { - // On HybridApp we need to orchestrate the sign-in flow of both apps so we need to set the state to STARTED here - if (CONFIG.IS_HYBRID_APP) { - setNewDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.STARTED); - } - - signInWithValidateCodeAndNavigate(Number(accountID), validateCode, '', exitTo); + Session.signInWithValidateCodeAndNavigate(Number(accountID), validateCode, '', exitTo); } }); // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx index 7854a74162919..cfd009a63f825 100644 --- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx @@ -1,12 +1,14 @@ +import HybridAppModule from '@expensify/react-native-hybrid-app'; import {useIsFocused} from '@react-navigation/native'; import {Str} from 'expensify-common'; import type {ImageContentFit} from 'expo-image'; import type {ForwardedRef} from 'react'; -import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; +import React, {forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import {InteractionManager, View} from 'react-native'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import {useOnyx} from 'react-native-onyx'; import ConfirmModal from '@components/ConfirmModal'; +import CustomStatusBarAndBackgroundContext from '@components/CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContext'; import FloatingActionButton from '@components/FloatingActionButton'; import * as Expensicons from '@components/Icon/Expensicons'; import type {PopoverMenuItem} from '@components/PopoverMenu'; @@ -24,7 +26,7 @@ import {startMoneyRequest} from '@libs/actions/IOU'; import {openOldDotLink, openTravelDotLink} from '@libs/actions/Link'; import {navigateToQuickAction} from '@libs/actions/QuickActionNavigation'; import {createNewReport, startNewChat} from '@libs/actions/Report'; -import {closeReactNativeApp, isAnonymousUser} from '@libs/actions/Session'; +import {isAnonymousUser} from '@libs/actions/Session'; import {completeTestDriveTask} from '@libs/actions/Task'; import getIconForAction from '@libs/getIconForAction'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; @@ -132,6 +134,8 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT const viewTourReportID = introSelected?.viewTour; const [viewTourReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${viewTourReportID}`, {canBeMissing: true}); + const {setRootStatusBarEnabled} = useContext(CustomStatusBarAndBackgroundContext); + const groupPoliciesWithChatEnabled = getGroupPaidPoliciesWithExpenseChatEnabled(); /** @@ -569,7 +573,8 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT onConfirm={() => { setModalVisible(false); if (CONFIG.IS_HYBRID_APP) { - closeReactNativeApp({shouldSignOut: false, shouldSetNVP: true}); + HybridAppModule.closeReactNativeApp({shouldSignOut: false, shouldSetNVP: true}); + setRootStatusBarEnabled(false); return; } openOldDotLink(CONST.OLDDOT_URLS.INBOX); diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index e26a273f682f5..bf8614a4daaca 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -1,3 +1,4 @@ +import HybridAppModule from '@expensify/react-native-hybrid-app/src'; import {findFocusedRoute, useNavigationState, useRoute} from '@react-navigation/native'; import React, {useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react'; // eslint-disable-next-line no-restricted-imports @@ -8,6 +9,7 @@ import type {ValueOf} from 'type-fest'; import AccountSwitcher from '@components/AccountSwitcher'; import AccountSwitcherSkeletonView from '@components/AccountSwitcherSkeletonView'; import ConfirmModal from '@components/ConfirmModal'; +import CustomStatusBarAndBackgroundContext from '@components/CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContext'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; @@ -28,9 +30,7 @@ import useSingleExecution from '@hooks/useSingleExecution'; import useSubscriptionPlan from '@hooks/useSubscriptionPlan'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import '@libs/actions/Delegate'; import {resetExitSurveyForm} from '@libs/actions/ExitSurvey'; -import {closeReactNativeApp} from '@libs/actions/Session'; import {checkIfFeedConnectionIsBroken} from '@libs/CardUtils'; import {convertToDisplayString} from '@libs/CurrencyUtils'; import useIsSidebarRouteActive from '@libs/Navigation/helpers/useIsSidebarRouteActive'; @@ -102,6 +102,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr const {translate} = useLocalize(); const focusedRouteName = useNavigationState((state) => findFocusedRoute(state)?.name); const emojiCode = currentUserPersonalDetails?.status?.emojiCode ?? ''; + const {setRootStatusBarEnabled} = useContext(CustomStatusBarAndBackgroundContext); const isScreenFocused = useIsSidebarRouteActive(NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, shouldUseNarrowLayout); const hasActivatedWallet = ([CONST.WALLET.TIER_NAME.GOLD, CONST.WALLET.TIER_NAME.PLATINUM] as string[]).includes(userWallet?.tierName ?? ''); @@ -237,7 +238,10 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr icon: Expensicons.ExpensifyLogoNew, ...(CONFIG.IS_HYBRID_APP ? { - action: () => closeReactNativeApp({shouldSignOut: false, shouldSetNVP: true}), + action: () => { + HybridAppModule.closeReactNativeApp({shouldSignOut: false, shouldSetNVP: true}); + setRootStatusBarEnabled(false); + }, } : { action() { @@ -278,7 +282,7 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr }, ], }; - }, [styles.pt4, shouldOpenSurveyReasonPage, signOut]); + }, [styles.pt4, setRootStatusBarEnabled, shouldOpenSurveyReasonPage, signOut]); /** * Return JSX.Element with menu items diff --git a/src/pages/settings/Security/MergeAccounts/MergeResultPage.tsx b/src/pages/settings/Security/MergeAccounts/MergeResultPage.tsx index dd6ebbf608927..1f623d61a56d3 100644 --- a/src/pages/settings/Security/MergeAccounts/MergeResultPage.tsx +++ b/src/pages/settings/Security/MergeAccounts/MergeResultPage.tsx @@ -1,10 +1,12 @@ +import HybridAppModule from '@expensify/react-native-hybrid-app'; import {useRoute} from '@react-navigation/native'; -import React, {useEffect, useMemo} from 'react'; +import React, {useContext, useEffect, useMemo} from 'react'; import {InteractionManager} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import ConfirmationPage from '@components/ConfirmationPage'; import type {ConfirmationPageProps} from '@components/ConfirmationPage'; +import CustomStatusBarAndBackgroundContext from '@components/CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContext'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Illustrations from '@components/Icon/Illustrations'; import LottieAnimations from '@components/LottieAnimations'; @@ -13,7 +15,6 @@ import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import {closeReactNativeApp} from '@libs/actions/Session'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; @@ -28,6 +29,7 @@ import SCREENS from '@src/SCREENS'; function MergeResultPage() { const styles = useThemeStyles(); const {translate} = useLocalize(); + const {setRootStatusBarEnabled} = useContext(CustomStatusBarAndBackgroundContext); const [userEmailOrPhone] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email, canBeMissing: true}); const {params} = useRoute>(); const {result, login} = params; @@ -151,7 +153,8 @@ function MergeResultPage() { secondaryButtonText: translate('mergeAccountsPage.mergePendingSAML.goToExpensifyClassic'), onSecondaryButtonPress: () => { if (CONFIG.IS_HYBRID_APP) { - closeReactNativeApp({shouldSignOut: false, shouldSetNVP: true}); + HybridAppModule.closeReactNativeApp({shouldSignOut: false, shouldSetNVP: true}); + setRootStatusBarEnabled(false); return; } openOldDotLink(CONST.OLDDOT_URLS.INBOX, false); @@ -231,7 +234,7 @@ function MergeResultPage() { illustration: Illustrations.LockClosedOrange, }, }; - }, [login, translate, userEmailOrPhone, styles]); + }, [setRootStatusBarEnabled, login, translate, userEmailOrPhone, styles]); useEffect(() => { /** diff --git a/src/pages/signin/ChooseSSOOrMagicCode.tsx b/src/pages/signin/ChooseSSOOrMagicCode.tsx index fab3cd258008e..2551fe34a21b1 100644 --- a/src/pages/signin/ChooseSSOOrMagicCode.tsx +++ b/src/pages/signin/ChooseSSOOrMagicCode.tsx @@ -1,7 +1,7 @@ -import {useFocusEffect} from '@react-navigation/native'; -import React, {useCallback} from 'react'; +import React, {useEffect} from 'react'; import {Keyboard, View} from 'react-native'; -import {useOnyx} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import Button from '@components/Button'; import FormHelpMessage from '@components/FormHelpMessage'; import Text from '@components/Text'; @@ -10,40 +10,44 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import {getLatestErrorMessage} from '@libs/ErrorUtils'; +import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; -import {clearSignInData, resendValidateCode} from '@userActions/Session'; +import * as Session from '@userActions/Session'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {Account, Credentials} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import ChangeExpensifyLoginLink from './ChangeExpensifyLoginLink'; import Terms from './Terms'; -type ChooseSSOOrMagicCodeProps = { +type ChooseSSOOrMagicCodeOnyxProps = { + /** The credentials of the logged in person */ + credentials: OnyxEntry; + + /** The details about the account that the user is signing in with */ + account: OnyxEntry; +}; + +type ChooseSSOOrMagicCodeProps = ChooseSSOOrMagicCodeOnyxProps & { /** Function that returns whether the user is using SAML or magic codes to log in */ setIsUsingMagicCode: (value: boolean) => void; }; -function ChooseSSOOrMagicCode({setIsUsingMagicCode}: ChooseSSOOrMagicCodeProps) { +function ChooseSSOOrMagicCode({credentials, account, setIsUsingMagicCode}: ChooseSSOOrMagicCodeProps) { const styles = useThemeStyles(); const {isKeyboardShown} = useKeyboardState(); const {translate} = useLocalize(); const {isOffline} = useNetwork(); const {shouldUseNarrowLayout} = useResponsiveLayout(); - const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: false}); - const [credentials] = useOnyx(ONYXKEYS.CREDENTIALS, {canBeMissing: true}); - // This view doesn't have a field for user input, so dismiss the device keyboard if shown - useFocusEffect( - useCallback(() => { - if (!isKeyboardShown) { - return; - } - Keyboard.dismiss(); - }, [isKeyboardShown]), - ); + useEffect(() => { + if (!isKeyboardShown) { + return; + } + Keyboard.dismiss(); + }, [isKeyboardShown]); return ( <> @@ -74,12 +78,12 @@ function ChooseSSOOrMagicCode({setIsUsingMagicCode}: ChooseSSOOrMagicCodeProps) text={translate('samlSignIn.useMagicCode')} isLoading={account?.isLoading && account?.loadingForm === (account?.requiresTwoFactorAuth ? CONST.FORMS.VALIDATE_TFA_CODE_FORM : CONST.FORMS.VALIDATE_CODE_FORM)} onPress={() => { - resendValidateCode(credentials?.login); + Session.resendValidateCode(credentials?.login); setIsUsingMagicCode(true); }} /> - {!!account && !isEmptyObject(account.errors) && } - clearSignInData()} /> + {!!account && !isEmptyObject(account.errors) && } + Session.clearSignInData()} /> @@ -90,4 +94,7 @@ function ChooseSSOOrMagicCode({setIsUsingMagicCode}: ChooseSSOOrMagicCodeProps) ChooseSSOOrMagicCode.displayName = 'ChooseSSOOrMagicCode'; -export default ChooseSSOOrMagicCode; +export default withOnyx({ + credentials: {key: ONYXKEYS.CREDENTIALS}, + account: {key: ONYXKEYS.ACCOUNT}, +})(ChooseSSOOrMagicCode); diff --git a/src/pages/signin/SAMLSignInPage/index.native.tsx b/src/pages/signin/SAMLSignInPage/index.native.tsx index 3d37272549afe..2daa8ebce16ba 100644 --- a/src/pages/signin/SAMLSignInPage/index.native.tsx +++ b/src/pages/signin/SAMLSignInPage/index.native.tsx @@ -7,7 +7,6 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import SAMLLoadingIndicator from '@components/SAMLLoadingIndicator'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; -import {setNewDotSignInState} from '@libs/actions/HybridApp'; import getPlatform from '@libs/getPlatform'; import getUAForWebView from '@libs/getUAForWebView'; import Log from '@libs/Log'; @@ -15,13 +14,12 @@ import {handleSAMLLoginError, postSAMLLogin} from '@libs/LoginUtils'; import Navigation from '@libs/Navigation/Navigation'; import {clearSignInData, setAccountError, signInWithShortLivedAuthToken} from '@userActions/Session'; import CONFIG from '@src/CONFIG'; -import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; function SAMLSignInPage() { - const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: false}); - const [credentials] = useOnyx(ONYXKEYS.CREDENTIALS, {canBeMissing: true}); + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const [credentials] = useOnyx(ONYXKEYS.CREDENTIALS); const [showNavigation, shouldShowNavigation] = useState(true); const [SAMLUrl, setSAMLUrl] = useState(''); const webViewRef = useRef(null); @@ -71,7 +69,6 @@ function SAMLSignInPage() { if (!account?.isLoading && credentials?.login && !!shortLivedAuthToken) { Log.info('SAMLSignInPage - Successfully received shortLivedAuthToken. Signing in...'); signInWithShortLivedAuthToken(shortLivedAuthToken); - setNewDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.STARTED); } // If the login attempt is unsuccessful, set the error message for the account and redirect to sign in page diff --git a/src/pages/signin/SignInPage.tsx b/src/pages/signin/SignInPage.tsx index 8ad0b93fc44e8..1cd6b2c04ef63 100644 --- a/src/pages/signin/SignInPage.tsx +++ b/src/pages/signin/SignInPage.tsx @@ -1,4 +1,3 @@ -import HybridAppModule from '@expensify/react-native-hybrid-app'; import {Str} from 'expensify-common'; import React, {forwardRef, useEffect, useImperativeHandle, useRef, useState} from 'react'; import type {ForwardedRef} from 'react'; @@ -22,7 +21,6 @@ import Performance from '@libs/Performance'; import Visibility from '@libs/Visibility'; import {setLocale} from '@userActions/App'; import {clearSignInData} from '@userActions/Session'; -import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -184,7 +182,6 @@ function SignInPage({shouldEnableMaxHeight = true}: SignInPageInnerProps, ref: F // We need to show "Another login page is opened" message if the page isn't active and visible // eslint-disable-next-line rulesdir/no-negated-variables const shouldShowAnotherLoginPageOpenedMessage = Visibility.isVisible() && !isClientTheLeader; - const [hybridApp] = useOnyx(ONYXKEYS.HYBRID_APP, {canBeMissing: true}); useEffect(() => Performance.measureTTI(), []); useEffect(() => { @@ -302,14 +299,6 @@ function SignInPage({shouldEnableMaxHeight = true}: SignInPageInnerProps, ref: F useImperativeHandle(ref, () => ({ navigateBack, })); - - useEffect(() => { - if (!CONFIG.IS_HYBRID_APP || !hybridApp?.loggedOutFromOldDot) { - return; - } - HybridAppModule.clearOldDotAfterSignOut(); - }, [hybridApp?.loggedOutFromOldDot]); - return ( // Bottom SafeAreaView is removed so that login screen svg displays correctly on mobile. // The SVG should flow under the Home Indicator on iOS. diff --git a/src/pages/signin/SignUpWelcomeForm.tsx b/src/pages/signin/SignUpWelcomeForm.tsx index a52efa042e8d1..1f8687c218b71 100644 --- a/src/pages/signin/SignUpWelcomeForm.tsx +++ b/src/pages/signin/SignUpWelcomeForm.tsx @@ -6,10 +6,8 @@ import FormHelpMessage from '@components/FormHelpMessage'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; -import {getLatestErrorMessage} from '@libs/ErrorUtils'; -import {setNewDotSignInState, setReadyToShowAuthScreens} from '@userActions/HybridApp'; -import {clearSignInData, signUpUser} from '@userActions/Session'; -import CONST from '@src/CONST'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import * as Session from '@userActions/Session'; import ONYXKEYS from '@src/ONYXKEYS'; import ChangeExpensifyLoginLink from './ChangeExpensifyLoginLink'; import Terms from './Terms'; @@ -18,8 +16,8 @@ function SignUpWelcomeForm() { const network = useNetwork(); const styles = useThemeStyles(); const {translate} = useLocalize(); - const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: false}); - const serverErrorText = useMemo(() => (account ? getLatestErrorMessage(account) : ''), [account]); + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const serverErrorText = useMemo(() => (account ? ErrorUtils.getLatestErrorMessage(account) : ''), [account]); return ( <> @@ -30,11 +28,7 @@ function SignUpWelcomeForm() { large text={translate('welcomeSignUpForm.join')} isLoading={account?.isLoading} - onPress={() => { - setNewDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.STARTED); - signUpUser(); - setReadyToShowAuthScreens(true); - }} + onPress={() => Session.signUpUser()} pressOnEnter style={[styles.mb2]} /> @@ -44,7 +38,7 @@ function SignUpWelcomeForm() { message={serverErrorText} /> )} - clearSignInData()} /> + Session.clearSignInData()} /> diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx index 5448995d36fb1..063ca96f48f46 100755 --- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx +++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx @@ -24,10 +24,8 @@ import {getLatestErrorMessage} from '@libs/ErrorUtils'; import {isValidRecoveryCode, isValidTwoFactorCode, isValidValidateCode} from '@libs/ValidationUtils'; import ChangeExpensifyLoginLink from '@pages/signin/ChangeExpensifyLoginLink'; import Terms from '@pages/signin/Terms'; -import {resetSignInFlow, setNewDotSignInState} from '@userActions/HybridApp'; -import {clearAccountMessages, isAnonymousUser as isAnonymousUserUtil, clearSignInData as sessionActionsClearSignInData, signIn, signInWithValidateCode} from '@userActions/Session'; +import {clearAccountMessages, clearSignInData as sessionActionsClearSignInData, signIn, signInWithValidateCode} from '@userActions/Session'; import {resendValidateCode as userActionsResendValidateCode} from '@userActions/User'; -import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -52,7 +50,6 @@ function BaseValidateCodeForm({autoComplete, isUsingRecoveryCode, setIsUsingReco const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: true}); const [credentials] = useOnyx(ONYXKEYS.CREDENTIALS, {canBeMissing: true}); const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false}); - const [hybridApp] = useOnyx(ONYXKEYS.HYBRID_APP, {canBeMissing: false}); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); @@ -156,10 +153,6 @@ function BaseValidateCodeForm({autoComplete, isUsingRecoveryCode, setIsUsingReco * Trigger the reset validate code flow and ensure the 2FA input field is reset to avoid it being permanently hidden */ const resendValidateCode = () => { - if (CONFIG.IS_HYBRID_APP) { - resetSignInFlow(); - } - userActionsResendValidateCode(credentials?.login ?? ''); inputValidateCodeRef.current?.clear(); // Give feedback to the user to let them know the email was sent so that they don't spam the button. @@ -239,15 +232,9 @@ function BaseValidateCodeForm({autoComplete, isUsingRecoveryCode, setIsUsingReco * Check that all the form fields are valid, then trigger the submit callback */ const validateAndSubmitForm = useCallback(() => { - const isAnonymousUser = isAnonymousUserUtil(session); - - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - if (account?.isLoading || hybridApp?.readyToShowAuthScreens || (session?.authToken && !isAnonymousUser)) { + if (account?.isLoading) { return; } - if (CONFIG.IS_HYBRID_APP) { - resetSignInFlow(); - } if (account?.errors) { clearAccountMessages(); } @@ -295,25 +282,13 @@ function BaseValidateCodeForm({autoComplete, isUsingRecoveryCode, setIsUsingReco const recoveryCodeOr2faCode = isUsingRecoveryCode ? recoveryCode : twoFactorAuthCode; - setNewDotSignInState(CONST.HYBRID_APP_SIGN_IN_STATE.STARTED); const accountID = credentials?.accountID; if (accountID) { signInWithValidateCode(accountID, validateCode, recoveryCodeOr2faCode); } else { signIn(validateCode, recoveryCodeOr2faCode); } - }, [ - account?.isLoading, - account?.errors, - account?.requiresTwoFactorAuth, - hybridApp?.readyToShowAuthScreens, - session, - isUsingRecoveryCode, - recoveryCode, - twoFactorAuthCode, - credentials?.accountID, - validateCode, - ]); + }, [account?.isLoading, account?.errors, account?.requiresTwoFactorAuth, isUsingRecoveryCode, recoveryCode, twoFactorAuthCode, credentials?.accountID, validateCode]); return ( diff --git a/src/types/onyx/HybridApp.ts b/src/types/onyx/HybridApp.ts deleted file mode 100644 index b6fee12920cf0..0000000000000 --- a/src/types/onyx/HybridApp.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type {ValueOf} from 'type-fest'; -import type CONST from '@src/CONST'; - -/** Data structure holding user's OldDot access information */ -type HybridAppDelegateAccessData = { - /** Indicates if OldDot is accessed in a delegate mode */ - isDelegateAccess?: boolean; - - /** Email address through which the user is currently authenticated in OldDot */ - oldDotCurrentUserEmail?: string; - - /** Authentication token used in OldDot */ - oldDotCurrentAuthToken?: string; - - /** Encrypted authentication token used in OldDot */ - oldDotCurrentEncryptedAuthToken?: string; - - /** Account ID for the user in OldDot */ - oldDotCurrentAccountID?: number; -}; - -/** State and configuration of a HybridApp */ -type HybridApp = { - /** Stores the information if HybridApp uses NewDot's sign-in flow */ - useNewDotSignInPage?: boolean; - - /** Determines if the AuthScreens are ready to be displayed */ - readyToShowAuthScreens?: boolean; - - /** Specifies if the transition from OldDot was made to display a specific subset of screens in NewDot */ - isSingleNewDotEntry?: boolean; - - /** Indicates if the last sign out action was performed from OldDot */ - loggedOutFromOldDot?: boolean; - - /** Determines whether to remove delegated access */ - shouldRemoveDelegatedAccess?: boolean; - - /** Describes the current state of NewDot sign-in process */ - newDotSignInState?: ValueOf; - - /** Holds delegate access information */ - delegateAccessData?: HybridAppDelegateAccessData; - - /** Indicates if the NewDot is being closed */ - closingReactNativeApp?: boolean; -}; - -export default HybridApp; diff --git a/src/types/onyx/TryNewDot.ts b/src/types/onyx/TryNewDot.ts index 4d79b0f36c49b..8d34b2efa18c2 100644 --- a/src/types/onyx/TryNewDot.ts +++ b/src/types/onyx/TryNewDot.ts @@ -5,11 +5,11 @@ type TryNewDot = { /** * This key is mostly used on OldDot. In NewDot, we only use `completedHybridAppOnboarding`. */ - classicRedirect?: { + classicRedirect: { /** * Indicates if transition from OldDot to NewDot should happen in HybridApp. */ - dismissed: boolean; + dismissed: boolean | string; /** * Indicates timestamp of an action. */ @@ -23,7 +23,7 @@ type TryNewDot = { /** * This key is added when user is migrated from OldDot to NewDot with nudge migration as part of a cohort. */ - nudgeMigration?: { + nudgeMigration: { /** Indicates timestamp of an action. */ timestamp: Date; }; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index e61b5fdac6537..24a921c1c9e5c 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -32,7 +32,6 @@ import type ExpensifyCardSettings from './ExpensifyCardSettings'; import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; import type {FundList} from './Fund'; import type Fund from './Fund'; -import type HybridApp from './HybridApp'; import type ImportedSpreadsheet from './ImportedSpreadsheet'; import type IntroSelected from './IntroSelected'; import type InvitedEmailsToAccountIDs from './InvitedEmailsToAccountIDs'; @@ -264,5 +263,4 @@ export type { ScheduleCallDraft, ValidateUserAndGetAccessiblePolicies, BillingReceiptDetails, - HybridApp, };