diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 296b76593f6..893fd59e38b 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -193,7 +193,7 @@ const ROUTES = { }, SETTINGS_CONTACT_METHOD_DETAILS: { route: 'settings/profile/contact-methods/:contactMethod/details', - getRoute: (contactMethod: string) => `settings/profile/contact-methods/${encodeURIComponent(contactMethod)}/details` as const, + getRoute: (contactMethod: string, backTo?: string) => getUrlWithBackToParam(`settings/profile/contact-methods/${encodeURIComponent(contactMethod)}/details`, backTo), }, SETTINGS_NEW_CONTACT_METHOD: { route: 'settings/profile/contact-methods/new', diff --git a/src/components/ValidateAccountMessage.tsx b/src/components/ValidateAccountMessage.tsx new file mode 100644 index 00000000000..be43c298596 --- /dev/null +++ b/src/components/ValidateAccountMessage.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; +import useLocalize from '@hooks/useLocalize'; +import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import variables from '@styles/variables'; +import * as Session from '@userActions/Session'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import Icon from './Icon'; +import * as Expensicons from './Icon/Expensicons'; +import Text from './Text'; +import TextLink from './TextLink'; + +type ValidateAccountMessageProps = {backTo?: string | undefined}; +function ValidateAccountMessage({backTo}: ValidateAccountMessageProps) { + const theme = useTheme(); + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST); + const loginNames = Object.keys(loginList ?? {}); + + return ( + + + + + {translate('bankAccount.validateAccountError.phrase1')} + Session.signOutAndRedirectToSignIn()} + > + {translate('bankAccount.validateAccountError.phrase2')} + + {translate('bankAccount.validateAccountError.phrase3')} + { + const login = loginList?.[loginNames?.[0]] ?? {}; + Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHOD_DETAILS.getRoute(login?.partnerUserID ?? loginNames?.[0], backTo)); + }} + > + {translate('bankAccount.validateAccountError.phrase4')} + + . + + + ); +} + +export default ValidateAccountMessage; diff --git a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts index 1bb9cce7e64..611831544bd 100644 --- a/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts +++ b/src/libs/Navigation/linkingConfig/getAdaptedStateFromPath.ts @@ -124,11 +124,7 @@ function getMatchingRootRouteForRHPRoute(route: NavigationPartialRoute): Navigat // If there is rhpNavigator in the state generated for backTo url, we want to get root route matching to this rhp screen. if (rhpNavigator && rhpNavigator.state) { - const isRHPinState = stateForBackTo.routes[0].name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR; - - if (isRHPinState) { - return getMatchingRootRouteForRHPRoute(findFocusedRoute(stateForBackTo) as NavigationPartialRoute); - } + return getMatchingRootRouteForRHPRoute(findFocusedRoute(stateForBackTo) as NavigationPartialRoute); } // If we know that backTo targets the root route (central pane or full screen) we want to use it. diff --git a/src/pages/ReimbursementAccount/BankAccountStep.tsx b/src/pages/ReimbursementAccount/BankAccountStep.tsx index 689b646f465..69e60587872 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.tsx +++ b/src/pages/ReimbursementAccount/BankAccountStep.tsx @@ -14,16 +14,14 @@ import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; +import ValidateAccountMessage from '@components/ValidateAccountMessage'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import getPlaidDesktopMessage from '@libs/getPlaidDesktopMessage'; -import Navigation from '@libs/Navigation/Navigation'; -import variables from '@styles/variables'; import * as BankAccounts from '@userActions/BankAccounts'; import * as Link from '@userActions/Link'; import * as ReimbursementAccount from '@userActions/ReimbursementAccount'; -import * as Session from '@userActions/Session'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -38,9 +36,6 @@ type BankAccountStepOnyxProps = { /** If the plaid button has been disabled */ isPlaidDisabled: OnyxEntry; - - /** Login list for the user that is signed in */ - loginList: OnyxEntry; }; type BankAccountStepProps = BankAccountStepOnyxProps & { @@ -73,7 +68,6 @@ function BankAccountStep({ receivedRedirectURI, reimbursementAccount, onBackButtonPress, - loginList, isPlaidDisabled = false, }: BankAccountStepProps) { const theme = useTheme(); @@ -86,7 +80,6 @@ function BankAccountStep({ } const plaidDesktopMessage = getPlaidDesktopMessage(); const bankAccountRoute = `${ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute('new', policyID, ROUTES.WORKSPACE_INITIAL.getRoute(policyID))}`; - const loginNames = Object.keys(loginList ?? {}); const removeExistingBankAccountDetails = () => { const bankAccountData: Partial = { @@ -168,35 +161,7 @@ function BankAccountStep({ /> - {!user?.validated && ( - - - - - {translate('bankAccount.validateAccountError.phrase1')} - Session.signOutAndRedirectToSignIn()} - > - {translate('bankAccount.validateAccountError.phrase2')} - - {translate('bankAccount.validateAccountError.phrase3')} - { - const login = loginList?.[loginNames?.[0]] ?? {}; - Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHOD_DETAILS.getRoute(login?.partnerUserID ?? loginNames?.[0])); - }} - > - {translate('bankAccount.validateAccountError.phrase4')} - - . - - - )} + {!user?.validated && } {translate('common.privacy')} ({ isPlaidDisabled: { key: ONYXKEYS.IS_PLAID_DISABLED, }, - loginList: { - key: ONYXKEYS.LOGIN_LIST, - }, })(BankAccountStep); diff --git a/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.tsx b/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.tsx index edda91d4a8e..dd3d3b87a12 100644 --- a/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.tsx +++ b/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.tsx @@ -1,3 +1,5 @@ +import type {RouteProp} from '@react-navigation/native'; +import {useRoute} from '@react-navigation/native'; import React, {useEffect, useState} from 'react'; import {ActivityIndicator, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; @@ -10,13 +12,14 @@ import PressableWithDelayToggle from '@components/Pressable/PressableWithDelayTo import ScrollView from '@components/ScrollView'; import Section from '@components/Section'; import Text from '@components/Text'; +import ValidateAccountMessage from '@components/ValidateAccountMessage'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import Clipboard from '@libs/Clipboard'; import localFileDownload from '@libs/localFileDownload'; -import type {BackToParams} from '@libs/Navigation/types'; +import type {BackToParams, SettingsNavigatorParamList} from '@libs/Navigation/types'; import StepWrapper from '@pages/settings/Security/TwoFactorAuth/StepWrapper/StepWrapper'; import useTwoFactorAuthContext from '@pages/settings/Security/TwoFactorAuth/TwoFactorAuthContext/useTwoFactorAuth'; import type {BaseTwoFactorAuthFormOnyxProps} from '@pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/types'; @@ -24,26 +27,30 @@ import * as Session from '@userActions/Session'; import * as TwoFactorAuthActions from '@userActions/TwoFactorAuthActions'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; type CodesStepProps = BaseTwoFactorAuthFormOnyxProps & BackToParams; -function CodesStep({account, backTo}: CodesStepProps) { +function CodesStep({account, user, backTo}: CodesStepProps) { const theme = useTheme(); const styles = useThemeStyles(); const {translate} = useLocalize(); const {isExtraSmallScreenWidth, isSmallScreenWidth} = useResponsiveLayout(); const [error, setError] = useState(''); + const isUserValidated = user?.validated; + const route = useRoute>(); const {setStep} = useTwoFactorAuthContext(); useEffect(() => { // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - if (account?.requiresTwoFactorAuth || account?.recoveryCodes) { + if (account?.requiresTwoFactorAuth || account?.recoveryCodes || !isUserValidated) { return; } Session.toggleTwoFactorAuth(true); // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps -- We want to run this when component mounts - }, []); + }, [isUserValidated]); return ( TwoFactorAuthActions.quitAndNavigateBack(backTo)} > -
- - {translate('twoFactorAuth.codesLoseAccess')} - - - {account?.isLoading ? ( - - - - ) : ( - <> - - {!!account?.recoveryCodes && - account?.recoveryCodes?.split(', ').map((code) => ( - - {code} - - ))} + {isUserValidated && ( +
+ + {translate('twoFactorAuth.codesLoseAccess')} + + + {account?.isLoading ? ( + + - - { - Clipboard.setString(account?.recoveryCodes ?? ''); - setError(''); - TwoFactorAuthActions.setCodesAreCopied(); - }} - styles={[styles.button, styles.buttonMedium, styles.twoFactorAuthCodesButton]} - textStyles={[styles.buttonMediumText]} - accessible={false} - tooltipText="" - tooltipTextChecked="" - /> - { - localFileDownload('two-factor-auth-codes', account?.recoveryCodes ?? ''); - setError(''); - TwoFactorAuthActions.setCodesAreCopied(); - }} - inline={false} - styles={[styles.button, styles.buttonMedium, styles.twoFactorAuthCodesButton]} - textStyles={[styles.buttonMediumText]} - accessible={false} - tooltipText="" - tooltipTextChecked="" - /> - - - )} - -
+ ) : ( + <> + + {!!account?.recoveryCodes && + account?.recoveryCodes?.split(', ').map((code) => ( + + {code} + + ))} + + + { + Clipboard.setString(account?.recoveryCodes ?? ''); + setError(''); + TwoFactorAuthActions.setCodesAreCopied(); + }} + styles={[styles.button, styles.buttonMedium, styles.twoFactorAuthCodesButton]} + textStyles={[styles.buttonMediumText]} + accessible={false} + tooltipText="" + tooltipTextChecked="" + /> + { + localFileDownload('two-factor-auth-codes', account?.recoveryCodes ?? ''); + setError(''); + TwoFactorAuthActions.setCodesAreCopied(); + }} + inline={false} + styles={[styles.button, styles.buttonMedium, styles.twoFactorAuthCodesButton]} + textStyles={[styles.buttonMediumText]} + accessible={false} + tooltipText="" + tooltipTextChecked="" + /> + + + )} +
+
+ )} + {!isUserValidated && } {!!error && ( { if (!account?.codesAreCopied) { @@ -151,4 +162,7 @@ CodesStep.displayName = 'CodesStep'; export default withOnyx({ account: {key: ONYXKEYS.ACCOUNT}, + user: { + key: ONYXKEYS.USER, + }, })(CodesStep); diff --git a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/types.ts b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/types.ts index baac250a3d6..97510a2a3a2 100644 --- a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/types.ts +++ b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/types.ts @@ -1,9 +1,10 @@ import type {ForwardedRef} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; -import type {Account} from '@src/types/onyx'; +import type {Account, User} from '@src/types/onyx'; type BaseTwoFactorAuthFormOnyxProps = { account: OnyxEntry; + user?: OnyxEntry; }; type BaseTwoFactorAuthFormRef = {