diff --git a/src/pages/signin/EmailDeliveryFailurePage.tsx b/src/pages/signin/EmailDeliveryFailurePage.tsx index 0a294e3a6b86..ff16af7dffd9 100644 --- a/src/pages/signin/EmailDeliveryFailurePage.tsx +++ b/src/pages/signin/EmailDeliveryFailurePage.tsx @@ -9,7 +9,7 @@ import TextLink from '@components/TextLink'; import useKeyboardState from '@hooks/useKeyboardState'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import redirectToSignIn from '@userActions/SignInRedirect'; +import * as Session from '@userActions/Session'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Credentials} from '@src/types/onyx'; @@ -74,7 +74,7 @@ function EmailDeliveryFailurePage({credentials}: EmailDeliveryFailurePageProps) redirectToSignIn()} + onPress={() => Session.clearSignInData()} role="button" accessibilityLabel={translate('common.back')} // disable hover dim for switch diff --git a/src/pages/signin/SignInModal.tsx b/src/pages/signin/SignInModal.tsx index 5bce895ab251..bad93b29f8af 100644 --- a/src/pages/signin/SignInModal.tsx +++ b/src/pages/signin/SignInModal.tsx @@ -1,4 +1,4 @@ -import React, {useEffect} from 'react'; +import React, {useEffect, useRef} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -12,6 +12,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import SCREENS from '@src/SCREENS'; import type {Session} from '@src/types/onyx'; import SignInPage from './SignInPage'; +import type {SignInPageRef} from './SignInPage'; type SignInModalOnyxProps = { session: OnyxEntry; @@ -22,6 +23,7 @@ type SignInModalProps = SignInModalOnyxProps; function SignInModal({session}: SignInModalProps) { const theme = useTheme(); const StyleUtils = useStyleUtils(); + const siginPageRef = useRef(null); useEffect(() => { const isAnonymousUser = session?.authTokenType === CONST.AUTH_TOKEN_TYPES.ANONYMOUS; @@ -40,8 +42,19 @@ function SignInModal({session}: SignInModalProps) { shouldShowOfflineIndicator={false} testID={SignInModal.displayName} > - Navigation.goBack()} /> - + { + if (!siginPageRef.current) { + Navigation.goBack(); + return; + } + siginPageRef.current?.navigateBack(); + }} + /> + ); } diff --git a/src/pages/signin/SignInPage.tsx b/src/pages/signin/SignInPage.tsx index 567612bb1aa6..729faae5e90b 100644 --- a/src/pages/signin/SignInPage.tsx +++ b/src/pages/signin/SignInPage.tsx @@ -1,5 +1,6 @@ import {Str} from 'expensify-common'; -import React, {useEffect, useRef, useState} from 'react'; +import React, {forwardRef, useEffect, useImperativeHandle, useRef, useState} from 'react'; +import type {ForwardedRef, RefAttributes} from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import ColorSchemeWrapper from '@components/ColorSchemeWrapper'; @@ -34,6 +35,7 @@ import type {SignInPageLayoutRef} from './SignInPageLayout/types'; import SignUpWelcomeForm from './SignUpWelcomeForm'; import UnlinkLoginForm from './UnlinkLoginForm'; import ValidateCodeForm from './ValidateCodeForm'; +import type {BaseValidateCodeFormRef} from './ValidateCodeForm/BaseValidateCodeForm'; type SignInPageInnerOnyxProps = { /** The details about the account that the user is signing in with */ @@ -53,6 +55,10 @@ type SignInPageInnerProps = SignInPageInnerOnyxProps & { shouldEnableMaxHeight?: boolean; }; +type SignInPageRef = { + navigateBack: () => void; +}; + type RenderOption = { shouldShowLoginForm: boolean; shouldShowEmailDeliveryFailurePage: boolean; @@ -141,7 +147,7 @@ function getRenderOptions({ }; } -function SignInPage({credentials, account, activeClients = [], preferredLocale, shouldEnableMaxHeight = true}: SignInPageInnerProps) { +function SignInPage({credentials, account, activeClients = [], preferredLocale, shouldEnableMaxHeight = true}: SignInPageInnerProps, ref: ForwardedRef) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate, formatPhoneNumber} = useLocalize(); @@ -149,6 +155,8 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale, const safeAreaInsets = useSafeAreaInsets(); const signInPageLayoutRef = useRef(null); const loginFormRef = useRef(null); + const validateCodeFormRef = useRef(null); + /** This state is needed to keep track of if user is using recovery code instead of 2fa code, * and we need it here since welcome text(`welcomeText`) also depends on it */ const [isUsingRecoveryCode, setIsUsingRecoveryCode] = useState(false); @@ -262,6 +270,25 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale, loginFormRef.current?.clearDataAndFocus(); }; + const navigateBack = () => { + if ( + shouldShouldSignUpWelcomeForm || + (!shouldShowAnotherLoginPageOpenedMessage && (shouldShowEmailDeliveryFailurePage || shouldShowUnlinkLoginForm || shouldShowChooseSSOOrMagicCode)) + ) { + Session.clearSignInData(); + return; + } + + if (shouldShowValidateCodeForm) { + validateCodeFormRef.current?.clearSignInData(); + return; + } + + Navigation.goBack(); + }; + useImperativeHandle(ref, () => ({ + navigateBack, + })); return ( // Bottom SafeAreaView is removed so that login screen svg displays correctly on mobile. // The SVG should flow under the Home Indicator on iOS. @@ -296,6 +323,7 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale, isVisible={!shouldShowAnotherLoginPageOpenedMessage} isUsingRecoveryCode={isUsingRecoveryCode} setIsUsingRecoveryCode={setIsUsingRecoveryCode} + ref={validateCodeFormRef} /> )} {!shouldShowAnotherLoginPageOpenedMessage && ( @@ -312,14 +340,16 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale, type SignInPageProps = SignInPageInnerProps; type SignInPageOnyxProps = SignInPageInnerOnyxProps; +const SignInPageWithRef = forwardRef(SignInPage); -function SignInPageThemeWrapper(props: SignInPageProps) { +function SignInPageThemeWrapper(props: SignInPageProps, ref: ForwardedRef) { return ( - @@ -331,7 +361,7 @@ function SignInPageThemeWrapper(props: SignInPageProps) { SignInPageThemeWrapper.displayName = 'SignInPage'; -export default withOnyx({ +export default withOnyx, SignInPageOnyxProps>({ account: {key: ONYXKEYS.ACCOUNT}, credentials: {key: ONYXKEYS.CREDENTIALS}, /** @@ -345,4 +375,6 @@ export default withOnyx({ preferredLocale: { key: ONYXKEYS.NVP_PREFERRED_LOCALE, }, -})(SignInPageThemeWrapper); +})(forwardRef(SignInPageThemeWrapper)); + +export type {SignInPageRef}; diff --git a/src/pages/signin/SignUpWelcomeForm.tsx b/src/pages/signin/SignUpWelcomeForm.tsx index 1d8010be14cb..68bb7d10796a 100644 --- a/src/pages/signin/SignUpWelcomeForm.tsx +++ b/src/pages/signin/SignUpWelcomeForm.tsx @@ -7,7 +7,6 @@ import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; import * as Session from '@userActions/Session'; -import redirectToSignIn from '@userActions/SignInRedirect'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Account} from '@src/types/onyx'; import ChangeExpensifyLoginLink from './ChangeExpensifyLoginLink'; @@ -38,11 +37,7 @@ function SignUpWelcomeForm({account}: SignUpWelcomeFormProps) { pressOnEnter style={[styles.mb2]} /> - { - redirectToSignIn(); - }} - /> + Session.clearSignInData()} /> diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx index bf0be21adb97..f23b136c76d0 100755 --- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx +++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.tsx @@ -1,5 +1,6 @@ import {useIsFocused} from '@react-navigation/native'; -import React, {useCallback, useEffect, useRef, useState} from 'react'; +import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react'; +import type {ForwardedRef} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; @@ -51,11 +52,18 @@ type BaseValidateCodeFormProps = WithToggleVisibilityViewProps & autoComplete: 'sms-otp' | 'one-time-code'; }; +type BaseValidateCodeFormRef = { + clearSignInData: () => void; +}; + type ValidateCodeFormVariant = 'validateCode' | 'twoFactorAuthCode' | 'recoveryCode'; type FormError = Partial>; -function BaseValidateCodeForm({account, credentials, session, autoComplete, isUsingRecoveryCode, setIsUsingRecoveryCode, isVisible}: BaseValidateCodeFormProps) { +function BaseValidateCodeForm( + {account, credentials, session, autoComplete, isUsingRecoveryCode, setIsUsingRecoveryCode, isVisible}: BaseValidateCodeFormProps, + forwardedRef: ForwardedRef, +) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); @@ -168,21 +176,25 @@ function BaseValidateCodeForm({account, credentials, session, autoComplete, isUs /** * Clear local sign in states */ - const clearLocalSignInData = () => { + const clearLocalSignInData = useCallback(() => { setTwoFactorAuthCode(''); setFormError({}); setValidateCode(''); setIsUsingRecoveryCode(false); setRecoveryCode(''); - }; + }, [setIsUsingRecoveryCode]); /** * Clears local and Onyx sign in states */ - const clearSignInData = () => { + const clearSignInData = useCallback(() => { clearLocalSignInData(); SessionActions.clearSignInData(); - }; + }, [clearLocalSignInData]); + + useImperativeHandle(forwardedRef, () => ({ + clearSignInData, + })); useEffect(() => { if (!needToClearError) { @@ -415,5 +427,7 @@ export default withToggleVisibilityView( account: {key: ONYXKEYS.ACCOUNT}, credentials: {key: ONYXKEYS.CREDENTIALS}, session: {key: ONYXKEYS.SESSION}, - })(BaseValidateCodeForm), + })(forwardRef(BaseValidateCodeForm)), ); + +export type {BaseValidateCodeFormRef}; diff --git a/src/pages/signin/ValidateCodeForm/index.android.tsx b/src/pages/signin/ValidateCodeForm/index.android.tsx index 1edd17517539..1cb05a0470f0 100644 --- a/src/pages/signin/ValidateCodeForm/index.android.tsx +++ b/src/pages/signin/ValidateCodeForm/index.android.tsx @@ -1,11 +1,14 @@ -import React from 'react'; +import React, {forwardRef} from 'react'; +import type {ForwardedRef} from 'react'; import BaseValidateCodeForm from './BaseValidateCodeForm'; +import type {BaseValidateCodeFormRef} from './BaseValidateCodeForm'; import type ValidateCodeFormProps from './types'; -function ValidateCodeForm(props: ValidateCodeFormProps) { +function ValidateCodeForm(props: ValidateCodeFormProps, ref: ForwardedRef) { return ( @@ -14,4 +17,4 @@ function ValidateCodeForm(props: ValidateCodeFormProps) { ValidateCodeForm.displayName = 'ValidateCodeForm'; -export default ValidateCodeForm; +export default forwardRef(ValidateCodeForm); diff --git a/src/pages/signin/ValidateCodeForm/index.tsx b/src/pages/signin/ValidateCodeForm/index.tsx index 8c1528ae7409..c656b049345e 100644 --- a/src/pages/signin/ValidateCodeForm/index.tsx +++ b/src/pages/signin/ValidateCodeForm/index.tsx @@ -1,11 +1,14 @@ -import React from 'react'; +import React, {forwardRef} from 'react'; +import type {ForwardedRef} from 'react'; import BaseValidateCodeForm from './BaseValidateCodeForm'; +import type {BaseValidateCodeFormRef} from './BaseValidateCodeForm'; import type ValidateCodeFormProps from './types'; -function ValidateCodeForm(props: ValidateCodeFormProps) { +function ValidateCodeForm(props: ValidateCodeFormProps, ref: ForwardedRef) { return ( @@ -14,4 +17,4 @@ function ValidateCodeForm(props: ValidateCodeFormProps) { ValidateCodeForm.displayName = 'ValidateCodeForm'; -export default ValidateCodeForm; +export default forwardRef(ValidateCodeForm);