diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 27504998c49c..6c3491117b46 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -151,6 +151,7 @@ const ROUTES = { SETTINGS_ABOUT: 'settings/about', SETTINGS_APP_DOWNLOAD_LINKS: 'settings/about/app-download-links', SETTINGS_WALLET: 'settings/wallet', + SETTINGS_WALLET_VERIFY_ACCOUNT: {route: 'settings/wallet/verify', getRoute: (backTo?: string) => getUrlWithBackToParam('settings/wallet/verify', backTo)}, SETTINGS_WALLET_DOMAINCARD: { route: 'settings/wallet/card/:cardID?', getRoute: (cardID: string) => `settings/wallet/card/${cardID}` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 8168afba89ab..05bccc82079e 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -112,6 +112,7 @@ const SCREENS = { CARD_ACTIVATE: 'Settings_Wallet_Card_Activate', REPORT_VIRTUAL_CARD_FRAUD: 'Settings_Wallet_ReportVirtualCardFraud', CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS: 'Settings_Wallet_Cards_Digital_Details_Update_Address', + VERIFY_ACCOUNT: 'Settings_Wallet_Verify_Account', }, EXIT_SURVEY: { diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index b41b58530a6b..5e125f30c9ce 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -211,6 +211,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/Wallet/TransferBalancePage').default, [SCREENS.SETTINGS.WALLET.CHOOSE_TRANSFER_ACCOUNT]: () => require('../../../../pages/settings/Wallet/ChooseTransferAccountPage').default, [SCREENS.SETTINGS.WALLET.ENABLE_PAYMENTS]: () => require('../../../../pages/EnablePayments/EnablePayments').default, + [SCREENS.SETTINGS.WALLET.VERIFY_ACCOUNT]: () => require('../../../../pages/settings/Wallet/VerifyAccountPage').default, [SCREENS.SETTINGS.ADD_DEBIT_CARD]: () => require('../../../../pages/settings/Wallet/AddDebitCardPage').default, [SCREENS.SETTINGS.ADD_BANK_ACCOUNT]: () => require('../../../../pages/AddPersonalBankAccountPage').default, [SCREENS.SETTINGS.PROFILE.STATUS]: () => require('../../../../pages/settings/Profile/CustomStatus/StatusPage').default, diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts index 609162bedd13..495554dae58f 100755 --- a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts @@ -37,6 +37,7 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = SCREENS.SETTINGS.WALLET.CARD_ACTIVATE, SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD, SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS, + SCREENS.SETTINGS.WALLET.VERIFY_ACCOUNT, ], [SCREENS.SETTINGS.SECURITY]: [ SCREENS.SETTINGS.TWO_FACTOR_AUTH, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 2ca2db10a1a7..44db290fc3e5 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -161,6 +161,10 @@ const config: LinkingOptions['config'] = { path: ROUTES.SETTINGS_CLOSE, exact: true, }, + [SCREENS.SETTINGS.WALLET.VERIFY_ACCOUNT]: { + path: ROUTES.SETTINGS_WALLET_VERIFY_ACCOUNT.route, + exact: true, + }, [SCREENS.SETTINGS.WALLET.DOMAIN_CARD]: { path: ROUTES.SETTINGS_WALLET_DOMAINCARD.route, exact: true, diff --git a/src/pages/AddPersonalBankAccountPage.tsx b/src/pages/AddPersonalBankAccountPage.tsx index 4f0edb630f59..04cce885bd07 100644 --- a/src/pages/AddPersonalBankAccountPage.tsx +++ b/src/pages/AddPersonalBankAccountPage.tsx @@ -8,17 +8,13 @@ import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; -import ValidateCodeActionModal from '@components/ValidateCodeActionModal'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as ErrorUtils from '@libs/ErrorUtils'; import getPlaidOAuthReceivedRedirectURI from '@libs/getPlaidOAuthReceivedRedirectURI'; import Navigation from '@libs/Navigation/Navigation'; import * as BankAccounts from '@userActions/BankAccounts'; import * as PaymentMethods from '@userActions/PaymentMethods'; -import * as User from '@userActions/User'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; import type {PersonalBankAccount, PlaidData} from '@src/types/onyx'; @@ -35,23 +31,8 @@ function AddPersonalBankAccountPage({personalBankAccount, plaidData}: AddPersona const {translate} = useLocalize(); const [selectedPlaidAccountId, setSelectedPlaidAccountId] = useState(''); const [isUserValidated] = useOnyx(ONYXKEYS.USER, {selector: (user) => !!user?.validated}); - const [isValidateCodeActionModalVisible, setIsValidateCodeActionModalVisible] = useState(!isUserValidated); const shouldShowSuccess = personalBankAccount?.shouldShowSuccess ?? false; - const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST); - const [account] = useOnyx(ONYXKEYS.ACCOUNT); - const primaryLogin = account?.primaryLogin; - const loginData = loginList?.[primaryLogin ?? '']; - const validateLoginError = ErrorUtils.getEarliestErrorField(loginData, 'validateLogin'); - - const handleSubmitForm = useCallback( - (submitCode: string) => { - User.validateSecondaryLogin(loginList, primaryLogin ?? '', submitCode); - Navigation.navigate(ROUTES.SETTINGS_ADD_BANK_ACCOUNT); - }, - [loginList, primaryLogin], - ); - const submitBankAccountForm = useCallback(() => { const bankAccounts = plaidData?.bankAccounts ?? []; const selectedPlaidBankAccount = bankAccounts.find((bankAccount) => bankAccount.plaidAccountID === selectedPlaidAccountId); @@ -86,58 +67,43 @@ function AddPersonalBankAccountPage({personalBankAccount, plaidData}: AddPersona shouldShowOfflineIndicator={false} testID={AddPersonalBankAccountPage.displayName} > - {isUserValidated && ( - - + + {shouldShowSuccess ? ( + exitFlow(true)} /> - {shouldShowSuccess ? ( - exitFlow(true)} + ) : ( + 0} + submitButtonText={translate('common.saveAndContinue')} + scrollContextEnabled + onSubmit={submitBankAccountForm} + validate={BankAccounts.validatePlaidSelection} + style={[styles.mh5, styles.flex1]} + > + Navigation.goBack()} + receivedRedirectURI={getPlaidOAuthReceivedRedirectURI()} + selectedPlaidAccountID={selectedPlaidAccountId} /> - ) : ( - 0} - submitButtonText={translate('common.saveAndContinue')} - scrollContextEnabled - onSubmit={submitBankAccountForm} - validate={BankAccounts.validatePlaidSelection} - style={[styles.mh5, styles.flex1]} - > - Navigation.goBack()} - receivedRedirectURI={getPlaidOAuthReceivedRedirectURI()} - selectedPlaidAccountID={selectedPlaidAccountId} - /> - - )} - - )} - { - setIsValidateCodeActionModalVisible(false); - exitFlow(); - }} - handleSubmitForm={handleSubmitForm} - clearError={() => {}} - /> + + )} + ); } diff --git a/src/pages/EnablePayments/AddBankAccount/SetupMethod.tsx b/src/pages/EnablePayments/AddBankAccount/SetupMethod.tsx index ed06d1aa1ed6..1f477998f4f4 100644 --- a/src/pages/EnablePayments/AddBankAccount/SetupMethod.tsx +++ b/src/pages/EnablePayments/AddBankAccount/SetupMethod.tsx @@ -15,12 +15,8 @@ import * as BankAccounts from '@userActions/BankAccounts'; import * as Link from '@userActions/Link'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {User} from '@src/types/onyx'; type SetupMethodOnyxProps = { - /** The user's data */ - user: OnyxEntry; - /** Whether Plaid is disabled */ isPlaidDisabled: OnyxEntry; }; @@ -29,7 +25,7 @@ type SetupMethodProps = SetupMethodOnyxProps; const plaidDesktopMessage = getPlaidDesktopMessage(); -function SetupMethod({isPlaidDisabled, user}: SetupMethodProps) { +function SetupMethod({isPlaidDisabled}: SetupMethodProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -52,7 +48,7 @@ function SetupMethod({isPlaidDisabled, user}: SetupMethodProps) { icon={Expensicons.Bank} text={translate('bankAccount.addBankAccount')} onPress={() => BankAccounts.openPersonalBankAccountSetupWithPlaid()} - isDisabled={!!isPlaidDisabled || !user?.validated} + isDisabled={!!isPlaidDisabled} style={[styles.mt4, styles.mb2]} iconStyles={styles.buttonCTAIcon} shouldShowRightIcon @@ -70,7 +66,4 @@ export default withOnyx({ isPlaidDisabled: { key: ONYXKEYS.IS_PLAID_DISABLED, }, - user: { - key: ONYXKEYS.USER, - }, })(SetupMethod); diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index 790157f5c3eb..56b8abf4c062 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -4,7 +4,7 @@ import React, {useCallback, useMemo} from 'react'; import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; import {FlatList, View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx, withOnyx} from 'react-native-onyx'; import type {SvgProps} from 'react-native-svg/lib/typescript/ReactNativeSVG'; import type {ValueOf} from 'type-fest'; import type {RenderSuggestionMenuItemProps} from '@components/AutoCompleteSuggestions/types'; @@ -199,6 +199,8 @@ function PaymentMethodList({ const {translate} = useLocalize(); const {isOffline} = useNetwork(); + const [isUserValidated] = useOnyx(ONYXKEYS.USER, {selector: (user) => !!user?.validated}); + const getDescriptionForPolicyDomainCard = (domainName: string): string => { // A domain name containing a policyID indicates that this is a workspace feed const policyID = domainName.match(CONST.REGEX.EXPENSIFY_POLICY_DOMAIN_NAME)?.[1]; @@ -322,17 +324,25 @@ function PaymentMethodList({ */ const renderListEmptyComponent = () => {translate('paymentMethodList.addFirstPaymentMethod')}; + const onPressItem = useCallback(() => { + if (!isUserValidated) { + Navigation.navigate(ROUTES.SETTINGS_WALLET_VERIFY_ACCOUNT.getRoute(ROUTES.SETTINGS_ADD_BANK_ACCOUNT)); + return; + } + onPress(); + }, [isUserValidated, onPress]); + const renderListFooterComponent = useCallback( () => ( ), - [onPress, translate, styles.paymentMethod, listItemStyle, buttonRef], + [translate, styles.paymentMethod, listItemStyle, buttonRef, onPressItem], ); /** diff --git a/src/pages/settings/Wallet/VerifyAccountPage.tsx b/src/pages/settings/Wallet/VerifyAccountPage.tsx new file mode 100644 index 000000000000..03ac87af8bc0 --- /dev/null +++ b/src/pages/settings/Wallet/VerifyAccountPage.tsx @@ -0,0 +1,73 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import React, {useCallback, useEffect, useRef} from 'react'; +import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import type {AnimatedTextInputRef} from '@components/RNTextInput'; +import ScreenWrapper from '@components/ScreenWrapper'; +import Text from '@components/Text'; +import ValidateCodeForm from '@components/ValidateCodeActionModal/ValidateCodeForm'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import Navigation from '@libs/Navigation/Navigation'; +import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import * as User from '@userActions/User'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; + +type VerifyAccountPageProps = StackScreenProps; + +function VerifyAccountPage({route}: VerifyAccountPageProps) { + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST); + const [pendingContactAction] = useOnyx(ONYXKEYS.PENDING_CONTACT_ACTION); + const contactMethod = account?.primaryLogin ?? ''; + const themeStyles = useThemeStyles(); + const {translate} = useLocalize(); + const loginInputRef = useRef(null); + const loginData = loginList?.[pendingContactAction?.contactMethod ?? contactMethod]; + const validateLoginError = ErrorUtils.getEarliestErrorField(loginData, 'validateLogin'); + + const [validateCodeAction] = useOnyx(ONYXKEYS.VALIDATE_ACTION_CODE); + + const navigateBackTo = route?.params?.backTo ?? ROUTES.SETTINGS_WALLET; + + useEffect(() => () => User.clearUnvalidatedNewContactMethodAction(), []); + + const handleSubmitForm = useCallback( + (submitCode: string) => { + User.validateSecondaryLogin(loginList, contactMethod ?? '', submitCode); + Navigation.navigate(navigateBackTo); + }, + [loginList, contactMethod, navigateBackTo], + ); + + return ( + loginInputRef.current?.focus()} + includeSafeAreaPaddingBottom={false} + shouldEnableMaxHeight + testID={VerifyAccountPage.displayName} + > + Navigation.goBack(ROUTES.SETTINGS_ADD_BANK_ACCOUNT)} + /> + + {translate('contacts.featureRequiresValidate')} + {}} + /> + + + ); +} + +VerifyAccountPage.displayName = 'VerifyAccountPage'; + +export default VerifyAccountPage;