diff --git a/native/account/qr-auth-progress-screen.react.js b/native/account/qr-auth-progress-screen.react.js --- a/native/account/qr-auth-progress-screen.react.js +++ b/native/account/qr-auth-progress-screen.react.js @@ -70,21 +70,8 @@ const { qrAuthInProgress, registerErrorListener } = useSecondaryDeviceQRAuthContext(); - const userDataRestoreStatus = useSelector( - state => state.restoreBackupState.status, - ); - - useFocusEffect( - React.useCallback(() => { - if (userDataRestoreStatus === 'user_data_restore_failed') { - props.navigation.navigate(RestoreBackupErrorScreenRouteName, { - errorInfo: { - type: 'restore_failed', - restoreType: 'secondary', - }, - }); - } - }, [props.navigation, userDataRestoreStatus]), + const userDataRestoreStarted = useSelector( + state => state.restoreBackupState.status !== 'no_backup', ); useFocusEffect( @@ -94,7 +81,7 @@ } const subscription = registerErrorListener((error, isUserDataError) => { if (isUserDataError) { - // user data errors are handled by selector + // user data errors are handled by LogInHandler return; } @@ -125,7 +112,6 @@ }, [registerErrorListener, props.navigation]), ); - const userDataRestoreStarted = userDataRestoreStatus !== 'no_backup'; const step: 'authenticating' | 'restoring' = qrAuthInProgress && !userDataRestoreStarted ? 'authenticating' diff --git a/native/account/restore-backup-screen.react.js b/native/account/restore-backup-screen.react.js --- a/native/account/restore-backup-screen.react.js +++ b/native/account/restore-backup-screen.react.js @@ -65,9 +65,6 @@ const restore = useRestore(); const performV1Login = useV1Login(); - const isRestoreError = useSelector( - state => state.restoreBackupState.status === 'user_data_restore_failed', - ); const restoreHasStarted = useSelector( state => state.restoreBackupState.status !== 'no_backup', ); @@ -81,15 +78,6 @@ e.preventDefault(); } }); - if (isRestoreError && fullBackupSupport) { - props.navigation.navigate(RestoreBackupErrorScreenRouteName, { - errorInfo: { - type: 'restore_failed', - restoreType: 'primary', - }, - }); - return removeListener; - } if ((restoreHasStarted || !shouldStartRestore) && fullBackupSupport) { return removeListener; } @@ -161,12 +149,7 @@ } else if (step === 'user_keys_restore') { alertDetails = userKeysRestoreErrorAlertDetails; } else if (step === 'user_data_restore') { - props.navigation.navigate(RestoreBackupErrorScreenRouteName, { - errorInfo: { - type: 'restore_failed', - restoreType: 'primary', - }, - }); + // this is handled by LogInHandler return; } diff --git a/native/navigation/navigation-handler.react.js b/native/navigation/navigation-handler.react.js --- a/native/navigation/navigation-handler.react.js +++ b/native/navigation/navigation-handler.react.js @@ -1,5 +1,6 @@ // @flow +import { CommonActions } from '@react-navigation/core'; import * as React from 'react'; import { useIsLoggedInToIdentityAndAuthoritativeKeyserver } from 'lib/hooks/account-hooks.js'; @@ -9,12 +10,19 @@ import { logInActionType, logOutActionType } from './action-types.js'; import ModalPruner from './modal-pruner.react.js'; import NavFromReduxHandler from './nav-from-redux-handler.react.js'; -import { useIsAppLoggedIn } from './nav-selectors.js'; +import { useIsAppLoggedIn, useCurrentLeafRouteName } from './nav-selectors.js'; import { NavContext, type NavAction } from './navigation-context.js'; import PolicyAcknowledgmentHandler from './policy-acknowledgment-handler.react.js'; +import { + RestoreBackupScreenRouteName, + RestoreBackupErrorScreenRouteName, + QRAuthProgressScreenRouteName, + AuthRouteName, +} from './route-names.js'; import ThreadScreenTracker from './thread-screen-tracker.react.js'; import { MissingRegistrationDataHandler } from '../account/registration/missing-registration-data/missing-registration-data-handler.react.js'; import DevTools from '../redux/dev-tools.react.js'; +import { useSelector } from '../redux/redux-utils.js'; const NavigationHandler: React.ComponentType<{}> = React.memo<{}>( function NavigationHandler() { @@ -61,22 +69,76 @@ const loggedIn = useIsLoggedInToIdentityAndAuthoritativeKeyserver(); const userDataReady = useIsUserDataReady(); - const appLoggedIn = loggedIn && userDataReady; + + const isRestoreError = useSelector( + state => state.restoreBackupState.status === 'user_data_restore_failed', + ); const navLoggedIn = useIsAppLoggedIn(); - const prevLoggedInRef = React.useRef(); + const currentRouteName = useCurrentLeafRouteName(); + const prevStateRef = React.useRef(); React.useEffect(() => { - if (appLoggedIn === prevLoggedInRef.current) { + const currentStateHash = [ + loggedIn.toString(), + userDataReady.toString(), + isRestoreError.toString(), + ].join('#'); + if (currentStateHash === prevStateRef.current) { return; } - prevLoggedInRef.current = appLoggedIn; - if (appLoggedIn && !navLoggedIn) { - dispatch({ type: (logInActionType: 'LOG_IN') }); - } else if (!appLoggedIn && navLoggedIn) { + prevStateRef.current = currentStateHash; + + const appLoggedIn = loggedIn && userDataReady; + if (!loggedIn && navLoggedIn) { + // User logged out - show auth flow dispatch({ type: (logOutActionType: 'LOG_OUT') }); + } else if (loggedIn && !userDataReady) { + // User is authenticated but data not ready + if ( + isRestoreError && + currentRouteName !== RestoreBackupErrorScreenRouteName + ) { + // Show error screen if not already there + dispatch( + CommonActions.navigate({ + name: AuthRouteName, + params: { + screen: RestoreBackupErrorScreenRouteName, + params: { + errorInfo: { + type: 'restore_failed', + }, + }, + }, + }), + ); + } else if ( + currentRouteName !== RestoreBackupScreenRouteName && + currentRouteName !== QRAuthProgressScreenRouteName + ) { + // Show restore screen if not already there + dispatch( + CommonActions.navigate({ + name: AuthRouteName, + params: { + screen: RestoreBackupScreenRouteName, + }, + }), + ); + } + } else if (appLoggedIn && !navLoggedIn) { + // User fully authenticated and data ready - show main app + dispatch({ type: (logInActionType: 'LOG_IN') }); } - }, [navLoggedIn, appLoggedIn, dispatch]); + }, [ + loggedIn, + userDataReady, + navLoggedIn, + isRestoreError, + currentRouteName, + dispatch, + ]); return null; });