From 973dd49d924aa6b3fa75a4bd442d2385861f3e71 Mon Sep 17 00:00:00 2001 From: Marcin Swornowski Date: Wed, 20 Dec 2023 13:53:10 +0100 Subject: [PATCH 01/35] fix: better narrowing for getSubstepValues return --- src/pages/ReimbursementAccount/utils/getSubstepValues.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/ReimbursementAccount/utils/getSubstepValues.ts b/src/pages/ReimbursementAccount/utils/getSubstepValues.ts index 90e6596e7f39..857547038b43 100644 --- a/src/pages/ReimbursementAccount/utils/getSubstepValues.ts +++ b/src/pages/ReimbursementAccount/utils/getSubstepValues.ts @@ -5,13 +5,13 @@ function getSubstepValues( inputKeys: Record, reimbursementAccountDraft: ReimbursementAccountDraft, reimbursementAccount: ReimbursementAccount, -): Record { +): {[K in T]: ReimbursementAccountDraft[K]} { return Object.entries(inputKeys).reduce( (acc, [, value]) => ({ ...acc, [value]: reimbursementAccountDraft[value] ?? getDefaultValueForReimbursementAccountField(reimbursementAccount, value, ''), }), - {} as Record, + {} as {[K in T]: ReimbursementAccountDraft[K]}, ); } From 104ee2b259e66192e17f1b83b626821b93552432 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Thu, 21 Dec 2023 10:23:31 +0100 Subject: [PATCH 02/35] fix: fixed datepicker --- src/components/DatePicker/index.js | 34 ++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/components/DatePicker/index.js b/src/components/DatePicker/index.js index bbc4ebc451d3..0037c2a5b938 100644 --- a/src/components/DatePicker/index.js +++ b/src/components/DatePicker/index.js @@ -1,8 +1,9 @@ import {setYear} from 'date-fns'; import _ from 'lodash'; import PropTypes from 'prop-types'; -import React, {forwardRef, useState} from 'react'; +import React, {forwardRef, useEffect, useState} from 'react'; import {View} from 'react-native'; +import InputWrapper from '@components/Form/InputWrapper'; import * as Expensicons from '@components/Icon/Expensicons'; import refPropTypes from '@components/refPropTypes'; import TextInput from '@components/TextInput'; @@ -37,6 +38,12 @@ const propTypes = { /** A maximum date of calendar to select */ maxDate: PropTypes.objectOf(Date), + /** A function that is passed by FormWrapper */ + onInputChange: PropTypes.func.isRequired, + + /** A function that is passed by FormWrapper */ + onTouched: PropTypes.func.isRequired, + /** Saves a draft of the input value when used in a form */ shouldSaveDraft: PropTypes.bool, @@ -56,6 +63,7 @@ const datePickerDefaultProps = { }; function DatePicker({ + forwardedRef, containerStyles, defaultValue, disabled, @@ -68,7 +76,6 @@ function DatePicker({ onInputChange, onTouched, placeholder, - translate, value, shouldSaveDraft, formID, @@ -77,6 +84,16 @@ function DatePicker({ const {translate} = useLocalize(); const [selectedDate, setSelectedDate] = useState(value || defaultValue || undefined); + const onSelected = (newValue) => { + if (_.isFunction(onTouched)) { + onTouched(); + } + if (_.isFunction(onInputChange)) { + onInputChange(newValue); + } + setSelectedDate(newValue); + }; + useEffect(() => { // Value is provided to input via props and onChange never fires. We have to save draft manually. if (shouldSaveDraft && formID !== '') { @@ -90,21 +107,12 @@ function DatePicker({ setSelectedDate(value); }, [formID, inputID, selectedDate, shouldSaveDraft, value]); - useEffect(() => { - if (_.isFunction(onTouched)) { - onTouched(); - } - if (_.isFunction(onInputChange)) { - onInputChange(newValue); - } - setSelectedDate(newValue); - }; - return ( - Date: Thu, 21 Dec 2023 11:15:06 +0100 Subject: [PATCH 03/35] fix: fixed component in datepicker --- src/components/DatePicker/index.js | 4 +--- .../BeneficialOwnerDetailsFormSubsteps/DateOfBirthUBO.js | 4 +++- .../BusinessInfo/substeps/IncorporationDateBusiness.js | 4 +++- .../ReimbursementAccount/PersonalInfo/substeps/DateOfBirth.js | 4 +++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/DatePicker/index.js b/src/components/DatePicker/index.js index 0037c2a5b938..759908a4647f 100644 --- a/src/components/DatePicker/index.js +++ b/src/components/DatePicker/index.js @@ -3,7 +3,6 @@ import _ from 'lodash'; import PropTypes from 'prop-types'; import React, {forwardRef, useEffect, useState} from 'react'; import {View} from 'react-native'; -import InputWrapper from '@components/Form/InputWrapper'; import * as Expensicons from '@components/Icon/Expensicons'; import refPropTypes from '@components/refPropTypes'; import TextInput from '@components/TextInput'; @@ -110,9 +109,8 @@ function DatePicker({ return ( - {translate('beneficialOwnerInfoStep.enterTheDateOfBirthOfTheOwner')} - {translate('businessInfoStep.selectYourCompanysIncorporationDate')} - {translate('personalInfoStep.enterYourDateOfBirth')} - Date: Fri, 1 Dec 2023 16:09:20 +0100 Subject: [PATCH 04/35] feat: add new verification step page --- .../substeps/ConfirmAgreements.js | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js index 5f0f23821c6d..682d26e2c595 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js +++ b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js @@ -1,4 +1,7 @@ import React from 'react'; +import {View} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; import CheckboxWithLabel from '@components/CheckboxWithLabel'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; @@ -6,10 +9,29 @@ import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; +import reimbursementAccountDraftPropTypes from '@pages/ReimbursementAccount/ReimbursementAccountDraftPropTypes'; +import {reimbursementAccountPropTypes} from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; +import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; +import subStepPropTypes from '@pages/ReimbursementAccount/subStepPropTypes'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ValidationUtils from '@libs/ValidationUtils'; import ONYXKEYS from '@src/ONYXKEYS'; +const propTypes = { + /** Reimbursement account from ONYX */ + reimbursementAccount: reimbursementAccountPropTypes, + + /** The draft values of the bank account being setup */ + reimbursementAccountDraft: reimbursementAccountDraftPropTypes, + + ...subStepPropTypes, +}; + +const defaultProps = { + reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps, + reimbursementAccountDraft: {}, +}; + const validate = (values) => { const errors = {}; @@ -84,5 +106,14 @@ function ConfirmAgreements() { } ConfirmAgreements.displayName = 'ConfirmAgreements'; +ConfirmAgreements.propTypes = propTypes; +ConfirmAgreements.defaultProps = defaultProps; -export default ConfirmAgreements; +export default withOnyx({ + reimbursementAccount: { + key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, + }, + reimbursementAccountDraft: { + key: ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT, + }, +})(ConfirmAgreements); From 3180e923efcae251636b3bee8260983785f16505 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Tue, 5 Dec 2023 10:44:17 +0100 Subject: [PATCH 05/35] feat: added submit of stpe, added default valuies and validation for checkboxes --- src/CONST.ts | 8 +++ src/languages/en.ts | 4 +- src/languages/es.ts | 11 ++-- .../CompleteVerification.js | 12 +++- .../substeps/ConfirmAgreements.js | 57 +++++++++++-------- 5 files changed, 60 insertions(+), 32 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index beac027599f9..1e273eff6baa 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -260,6 +260,14 @@ const CONST = { EXIT: 'EXIT', }, }, + COMPLETE_VERIFICATION: { + INPUT_KEY: { + BANK_ACCOUNT_ID: 'bankAccountID', + IS_AUTHORIZED_TO_USE_BANK_ACCOUNT: 'isAuthorizedToUseBankAccount', + CERTIFY_TRUE_INFORMATION: 'certifyTrueInformation', + ACCEPT_TERMS_AND_CONDITIONS: 'acceptTermsAndConditions', + }, + }, ERROR: { MISSING_ROUTING_NUMBER: '402 Missing routingNumber', MAX_ROUTING_NUMBER: '402 Maximum Size Exceeded routingNumber', diff --git a/src/languages/en.ts b/src/languages/en.ts index 087afb186340..4feaba057887 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1535,8 +1535,8 @@ export default { confirmAgreements: 'Please confirm the agreements below.', certifyTrueAndAccurate: 'I certify that the information provided is true and accurate', certifyTrueAndAccurateError: 'Must certify information is true and accurate', - isControllingOfficer: 'I am authorized to use my company bank account for business spend', - isControllingOfficerError: 'You must be a controlling officer with authorization to operate the business bank account.', + isAuthorizedToUseBankAccount: 'I am authorized to use my company bank account for business spend', + isAuthorizedToUseBankAccountError: 'You must be a controlling officer with authorization to operate the business bank account.', termsAndConditions: 'terms and conditions', }, reimbursementAccountLoadingAnimation: { diff --git a/src/languages/es.ts b/src/languages/es.ts index 01bccc0f8fa3..026ba11d32d4 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1554,13 +1554,14 @@ export default { }, }, completeVerificationStep: { + // TODO -bart- check translations completeVerification: 'Complete verification', confirmAgreements: 'Please confirm the agreements below.', - certifyTrueAndAccurate: 'I certify that the information provided is true and accurate', - certifyTrueAndAccurateError: 'Must certify information is true and accurate', - isControllingOfficer: 'I am authorized to use my company bank account for business spend', - isControllingOfficerError: 'You must be a controlling officer with authorization to operate the business bank account.', - termsAndConditions: 'terms and conditions', + certifyTrueAndAccurate: 'Certifico que la información dada es correcta', + certifyTrueAndAccurateError: 'Debe certificar que la información es verdadera y precisa', + isAuthorizedToUseBankAccount: 'Estoy autorizado a utilizar la cuenta bancaria de mi compañía para gastos de empresa', + isAuthorizedToUseBankAccountError: 'Debe ser un oficial controlador con autorización para operar la cuenta bancaria de la compañía', + termsAndConditions: 'Términos y condiciones', }, reimbursementAccountLoadingAnimation: { oneMoment: 'Un momento', diff --git a/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js b/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js index d4eedba74f84..13979fa763fe 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js +++ b/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js @@ -50,7 +50,17 @@ const CompleteVerification = forwardRef(({reimbursementAccount, reimbursementAcc ...values, }; - BankAccounts.updatePersonalInformationForBankAccount(payload); + // TODO mocked fieldsFrom UBO step should be replaced by real one + const tempValues = { + ownsMoreThan25Percent: false, + hasOtherBeneficialOwners: false, + beneficialOwners: '[]', + }; + + BankAccounts.updateBeneficialOwnersForBankAccount({ + ...tempValues, + ...payload, + }); }, [reimbursementAccount, values]); const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo} = useSubStep({bodyContent: BODY_CONTENT, startFrom: 0, onFinished: submit}); diff --git a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js index 682d26e2c595..868ef9fc90b0 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js +++ b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js @@ -1,7 +1,5 @@ -import React from 'react'; -import {View} from 'react-native'; +import React, {useMemo} from 'react'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import CheckboxWithLabel from '@components/CheckboxWithLabel'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; @@ -9,27 +7,23 @@ import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; -import reimbursementAccountDraftPropTypes from '@pages/ReimbursementAccount/ReimbursementAccountDraftPropTypes'; import {reimbursementAccountPropTypes} from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import subStepPropTypes from '@pages/ReimbursementAccount/subStepPropTypes'; +import getDefaultValueForReimbursementAccountField from '@pages/ReimbursementAccount/utils/getDefaultValueForReimbursementAccountField'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ValidationUtils from '@libs/ValidationUtils'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; const propTypes = { /** Reimbursement account from ONYX */ reimbursementAccount: reimbursementAccountPropTypes, - - /** The draft values of the bank account being setup */ - reimbursementAccountDraft: reimbursementAccountDraftPropTypes, - ...subStepPropTypes, }; const defaultProps = { reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps, - reimbursementAccountDraft: {}, }; const validate = (values) => { @@ -43,16 +37,34 @@ const validate = (values) => { errors.certifyTrueInformation = 'completeVerificationStep.certifyTrueAndAccurateError'; } - if (!ValidationUtils.isRequiredFulfilled(values.isControllingOfficer)) { - errors.isControllingOfficer = 'completeVerificationStep.isControllingOfficerError'; + if (!ValidationUtils.isRequiredFulfilled(values.isAuthorizedToUseBankAccount)) { + errors.isAuthorizedToUseBankAccount = 'completeVerificationStep.isAuthorizedToUseBankAccountError'; } return errors; }; -function ConfirmAgreements() { +const completeVerificationKeys = CONST.BANK_ACCOUNT.COMPLETE_VERIFICATION.INPUT_KEY; + +function ConfirmAgreements({onNext, reimbursementAccount}) { const {translate} = useLocalize(); const styles = useThemeStyles(); + const defaultValues = useMemo( + () => ({ + [completeVerificationKeys.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT]: getDefaultValueForReimbursementAccountField( + reimbursementAccount, + completeVerificationKeys.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT, + false, + ), + [completeVerificationKeys.CERTIFY_TRUE_INFORMATION]: getDefaultValueForReimbursementAccountField(reimbursementAccount, completeVerificationKeys.CERTIFY_TRUE_INFORMATION, false), + [completeVerificationKeys.ACCEPT_TERMS_AND_CONDITIONS]: getDefaultValueForReimbursementAccountField( + reimbursementAccount, + completeVerificationKeys.ACCEPT_TERMS_AND_CONDITIONS, + false, + ), + }), + [reimbursementAccount], + ); return ( {}} + onSubmit={onNext} submitButtonText={translate('common.saveAndContinue')} style={[styles.mh5, styles.flexGrow1]} > {translate('completeVerificationStep.isControllingOfficer')}} - defaultValue={false} + LabelComponent={() => {translate('completeVerificationStep.isAuthorizedToUseBankAccount')}} + defaultValue={defaultValues[completeVerificationKeys.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT]} shouldSaveDraft /> {translate('completeVerificationStep.certifyTrueAndAccurate')}} - defaultValue={false} + defaultValue={defaultValues[completeVerificationKeys.CERTIFY_TRUE_INFORMATION]} shouldSaveDraft /> ( @@ -97,7 +109,7 @@ function ConfirmAgreements() { {`${translate('completeVerificationStep.termsAndConditions')}`} )} - defaultValue={false} + defaultValue={defaultValues[completeVerificationKeys.ACCEPT_TERMS_AND_CONDITIONS]} shouldSaveDraft /> @@ -113,7 +125,4 @@ export default withOnyx({ reimbursementAccount: { key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, }, - reimbursementAccountDraft: { - key: ONYXKEYS.REIMBURSEMENT_ACCOUNT_DRAFT, - }, })(ConfirmAgreements); From b40dbc7b713cacde09f0b0d73f64619ad67d3ddc Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Thu, 7 Dec 2023 08:41:01 +0100 Subject: [PATCH 06/35] feat: added ConnectBankAccount component --- src/languages/en.ts | 19 +++ src/languages/es.ts | 19 +++ .../ConnectBankAccount/ConnectBankAccount.js | 99 +++++++++++++ .../components/BankAccountValidationForm.js | 135 ++++++++++++++++++ .../components/Enable2FACard.js | 47 ++++++ .../components/FinishChatCard.js | 64 +++++++++ src/pages/ReimbursementAccount/EnableStep.js | 2 +- 7 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js create mode 100644 src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.js create mode 100644 src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js create mode 100644 src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.js diff --git a/src/languages/en.ts b/src/languages/en.ts index 4feaba057887..708e41bf618e 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1539,6 +1539,25 @@ export default { isAuthorizedToUseBankAccountError: 'You must be a controlling officer with authorization to operate the business bank account.', termsAndConditions: 'terms and conditions', }, + connectBankAccountStep: { + connectBankAccount: 'Connect bank account', + finishButtonText: 'Finish setup', + validateYourBankAccount: 'Validate your bank account', + validateButtonText: 'Validate', + maxAttemptsReached: 'Validation for this bank account has been disabled due to too many incorrect attempts.', + validationInputLabel: 'Transaction', + description: 'A day or two after you add your account to Expensify we send three (3) transactions to your account. They have a merchant line like "Expensify, Inc. Validation".', + descriptionCTA: 'Please enter each transaction amount in the fields below. Example: 1.51.', + reviewingInfo: "Thanks! We're reviewing your information, and will be in touch shortly. Please check your chat with Concierge ", + forNextSteps: ' for next steps to finish setting up your bank account.', + letsChatCTA: "Yes, let's chat", + letsChatText: 'Thanks for doing that. We need your help verifying a few pieces of information, but we can work this out quickly over chat. Ready?', + letsChatTitle: "Let's chat!", + enable2FATitle: 'Prevent fraud, enable two-factor authentication!', + enable2FAText: + 'We take your security seriously, so please set up two-factor authentication for your account now. That will allow us to dispute Expensify Card digital transactions, and will reduce your risk for fraud.', + secureYourAccount: 'Secure your account', + }, reimbursementAccountLoadingAnimation: { oneMoment: 'One moment', explanationLine: 'We’re taking a look at your information. You will be able to continue with next steps shortly.', diff --git a/src/languages/es.ts b/src/languages/es.ts index 026ba11d32d4..d30ed13e43d2 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1563,6 +1563,25 @@ export default { isAuthorizedToUseBankAccountError: 'Debe ser un oficial controlador con autorización para operar la cuenta bancaria de la compañía', termsAndConditions: 'Términos y condiciones', }, + connectBankAccountStep: { + connectBankAccount: 'Connect bank account', + finishButtonText: 'Finish setup', + validateYourBankAccount: 'Validate your bank account', + validateButtonText: 'Validate', + maxAttemptsReached: 'Se ha inhabilitado la validación de esta cuenta bancaria debido a demasiados intentos incorrectos.', + description: + 'Uno o dos días después de añadir tu cuenta a Expensify, te enviaremos tres (3) transacciones a tu cuenta. Tienen un nombre de comerciante similar a "Expensify, Inc. Validation".', + descriptionCTA: 'Introduce el importe de cada transacción en los campos siguientes. Ejemplo: 1.51.', + reviewingInfo: '¡Gracias! Estamos revisando tu información y nos comunicaremos contigo en breve. Consulta el chat con Concierge ', + forNextSteps: ' para conocer los próximos pasos para terminar de configurar tu cuenta bancaria.', + letsChatCTA: 'Sí, vamos a chatear', + letsChatText: 'Gracias. Necesitamos tu ayuda para verificar la información, pero podemos hacerlo rápidamente a través del chat. ¿Estás listo?', + letsChatTitle: '¡Vamos a chatear!', + enable2FATitle: 'Evita fraudes, activa la autenticación de dos factores!', + enable2FAText: + 'Tu seguridad es importante para nosotros. Por favor, configura ahora la autenticación de dos factores. Eso nos permitirá disputar las transacciones de la Tarjeta Expensify y reducirá tu riesgo de fraude.', + secureYourAccount: 'Asegura tu cuenta', + }, reimbursementAccountLoadingAnimation: { oneMoment: 'Un momento', explanationLine: 'Estamos verificando tu información y podrás continuar con los siguientes pasos en unos momentos.', diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js new file mode 100644 index 000000000000..bd56f6aee772 --- /dev/null +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js @@ -0,0 +1,99 @@ +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import React from 'react'; +import {View} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import Text from '@components/Text'; +import TextLink from '@components/TextLink'; +import useLocalize from '@hooks/useLocalize'; +import BankAccount from '@libs/models/BankAccount'; +import EnableStep from '@pages/ReimbursementAccount/EnableStep'; +import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; +import useThemeStyles from '@styles/useThemeStyles'; +import * as Report from '@userActions/Report'; +import ONYXKEYS from '@src/ONYXKEYS'; +import BankAccountValidationForm from './components/BankAccountValidationForm'; +import FinishChatCard from './components/FinishChatCard'; + +const propTypes = { + /** Bank account currently in setup */ + reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes.isRequired, + + onBackButtonPress: PropTypes.func.isRequired, + + /** User's account who is setting up bank account */ + account: PropTypes.shape({ + /** If user has two-factor authentication enabled */ + requiresTwoFactorAuth: PropTypes.bool, + }), +}; + +const defaultProps = { + account: { + requiresTwoFactorAuth: false, + }, +}; + +function ConnectBankAccount({reimbursementAccount, onBackButtonPress, account}) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const bankAccountState = lodashGet(reimbursementAccount, 'achData.state'); + + // If a user tries to navigate directly to the validate page we'll show them the EnableStep + if (bankAccountState === BankAccount.STATE.OPEN) { + return ; + } + + const maxAttemptsReached = lodashGet(reimbursementAccount, 'maxAttemptsReached'); + const isBankAccountVerifying = !maxAttemptsReached && bankAccountState === BankAccount.STATE.VERIFYING; + const isBankAccountPending = bankAccountState === BankAccount.STATE.PENDING; + const requiresTwoFactorAuth = lodashGet(account, 'requiresTwoFactorAuth'); + + return ( + + + {maxAttemptsReached && ( + + + {translate('connectBankAccountStep.maxAttemptsReached')} {translate('common.please')}{' '} + {translate('common.contactUs')}. + + + )} + {!maxAttemptsReached && isBankAccountPending && ( + + )} + {isBankAccountVerifying && ( + + )} + + ); +} + +ConnectBankAccount.propTypes = propTypes; +ConnectBankAccount.defaultProps = defaultProps; +ConnectBankAccount.displayName = 'ConectBankAccount'; + +export default withOnyx({ + account: { + key: ONYXKEYS.ACCOUNT, + }, +})(ConnectBankAccount); diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.js b/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.js new file mode 100644 index 000000000000..48a065de0d59 --- /dev/null +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.js @@ -0,0 +1,135 @@ +import Str from 'expensify-common/lib/str'; +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import React, {useCallback} from 'react'; +import {View} from 'react-native'; +import _ from 'underscore'; +import FormProvider from '@components/Form/FormProvider'; +import Text from '@components/Text'; +import TextInput from '@components/TextInput'; +import useLocalize from '@hooks/useLocalize'; +import * as ValidationUtils from '@libs/ValidationUtils'; +import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; +import useThemeStyles from '@styles/useThemeStyles'; +import * as BankAccounts from '@userActions/BankAccounts'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import Enable2FACard from './Enable2FACard'; + +const propTypes = { + reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes.isRequired, + requiresTwoFactorAuth: PropTypes.bool.isRequired, +}; + +/** + * Filter input for validation amount + * Anything that isn't a number is returned as an empty string + * Any dollar amount (e.g. 1.12) will be returned as 112 + * + * @param {String} amount field input + * @returns {String} + */ +const filterInput = (amount) => { + let value = amount ? amount.toString().trim() : ''; + if (value === '' || _.isNaN(Number(value)) || !Math.abs(Str.fromUSDToNumber(value))) { + return ''; + } + + // If the user enters the values in dollars, convert it to the respective cents amount + if (_.contains(value, '.')) { + value = Str.fromUSDToNumber(value); + } + + return value; +}; + +/** + * @param {Object} values - form input values passed by the Form component + * @returns {Object} + */ + +const validate = (values) => { + const errors = {}; + + _.each(values, (value, key) => { + const filteredValue = typeof value === 'string' ? filterInput(value) : value; + if (ValidationUtils.isRequiredFulfilled(filteredValue)) { + return; + } + errors[key] = 'common.error.invalidAmount'; + }); + + return errors; +}; + +function BankAccountValidationForm({requiresTwoFactorAuth, reimbursementAccount}) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + + /** + * @param {Object} values - form input values passed by the Form component + */ + const submit = useCallback( + (values) => { + const amount1 = filterInput(values.amount1); + const amount2 = filterInput(values.amount2); + const amount3 = filterInput(values.amount3); + + const validateCode = [amount1, amount2, amount3].join(','); + + // Send valid amounts to BankAccountAPI::validateBankAccount in Web-Expensify + const bankAccountID = lodashGet(reimbursementAccount, 'achData.bankAccountID'); + BankAccounts.validateBankAccount(bankAccountID, validateCode); + }, + [reimbursementAccount], + ); + return ( + + {translate('connectBankAccountStep.description')} + {translate('connectBankAccountStep.descriptionCTA')} + + + + + + + {!requiresTwoFactorAuth && ( + + + + )} + + ); +} + +BankAccountValidationForm.propTypes = propTypes; +BankAccountValidationForm.displayName = 'BankAccountValidationForm'; + +export default BankAccountValidationForm; diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js b/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js new file mode 100644 index 000000000000..ca603ad0d15f --- /dev/null +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js @@ -0,0 +1,47 @@ +import React from 'react'; +import {View} from 'react-native'; +import * as Expensicons from '@components/Icon/Expensicons'; +import * as Illustrations from '@components/Icon/Illustrations'; +import Section from '@components/Section'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@styles/useThemeStyles'; +import * as Link from '@userActions/Link'; +import ROUTES from '@src/ROUTES'; + +function Enable2FACard() { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const secureYourAccountUrl = encodeURI( + `settings?param={"section":"account","action":"enableTwoFactorAuth","exitTo":"${ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute()}","isFromNewDot":"true"}`, + ); + + return ( +
{ + Link.openOldDotLink(secureYourAccountUrl); + }, + icon: Expensicons.Shield, + shouldShowRightIcon: true, + iconRight: Expensicons.NewWindow, + wrapperStyle: [styles.cardMenuItem], + link: () => Link.buildOldDotURL(secureYourAccountUrl), + }, + ]} + > + + {translate('validationStep.enable2FAText')} + +
+ ); +} + +Enable2FACard.displayName = 'Enable2FAPrompt'; + +export default Enable2FACard; diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.js b/src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.js new file mode 100644 index 000000000000..612aa353fb75 --- /dev/null +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.js @@ -0,0 +1,64 @@ +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import React from 'react'; +import {ScrollView} from 'react-native'; +import Button from '@components/Button'; +import * as Expensicons from '@components/Icon/Expensicons'; +import * as Illustrations from '@components/Icon/Illustrations'; +import MenuItem from '@components/MenuItem'; +import Section from '@components/Section'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; +import WorkspaceResetBankAccountModal from '@pages/workspace/WorkspaceResetBankAccountModal'; +import useThemeStyles from '@styles/useThemeStyles'; +import * as BankAccounts from '@userActions/BankAccounts'; +import * as Report from '@userActions/Report'; +import Enable2FACard from './Enable2FACard'; + +const propTypes = { + requiresTwoFactorAuth: PropTypes.bool.isRequired, + reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes.isRequired, +}; + +function FinishChatCard({requiresTwoFactorAuth, reimbursementAccount}) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const shouldShowResetModal = lodashGet(reimbursementAccount, 'shouldShowResetModal', false); + + return ( + +
+ {translate('connectBankAccountStep.letsChatText')} +
+ {!requiresTwoFactorAuth && } + {shouldShowResetModal && } +
+ ); +} + +FinishChatCard.propTypes = propTypes; +FinishChatCard.displayName = 'FinishChatCard'; + +export default FinishChatCard; diff --git a/src/pages/ReimbursementAccount/EnableStep.js b/src/pages/ReimbursementAccount/EnableStep.js index d8d76d6cfb2f..014f918d5776 100644 --- a/src/pages/ReimbursementAccount/EnableStep.js +++ b/src/pages/ReimbursementAccount/EnableStep.js @@ -17,13 +17,13 @@ import Text from '@components/Text'; import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; +import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import userPropTypes from '@pages/settings/userPropTypes'; import WorkspaceResetBankAccountModal from '@pages/workspace/WorkspaceResetBankAccountModal'; import * as Link from '@userActions/Link'; import * as BankAccounts from '@userActions/ReimbursementAccount'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import * as ReimbursementAccountProps from './reimbursementAccountPropTypes'; const propTypes = { /** Bank account currently in setup */ From 9dd74d32935e89fe35246abf139996a05da74635 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Thu, 7 Dec 2023 15:00:49 +0100 Subject: [PATCH 07/35] feat: added EnableBankAccount step --- .../EnableBankAccount/EnableBankAccount.js | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 src/pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount.js diff --git a/src/pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount.js b/src/pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount.js new file mode 100644 index 000000000000..6b1ba9d6100e --- /dev/null +++ b/src/pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount.js @@ -0,0 +1,129 @@ +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import React from 'react'; +import {ScrollView} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; +import Button from '@components/Button'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import getBankIcon from '@components/Icon/BankIcons'; +import * as Expensicons from '@components/Icon/Expensicons'; +import * as Illustrations from '@components/Icon/Illustrations'; +import MenuItem from '@components/MenuItem'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; +import ScreenWrapper from '@components/ScreenWrapper'; +import Section from '@components/Section'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; +import userPropTypes from '@pages/settings/userPropTypes'; +import WorkspaceResetBankAccountModal from '@pages/workspace/WorkspaceResetBankAccountModal'; +import useThemeStyles from '@styles/useThemeStyles'; +import * as Link from '@userActions/Link'; +import * as BankAccounts from '@userActions/ReimbursementAccount'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; + +const propTypes = { + /** Bank account currently in setup */ + reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes.isRequired, + + /* Onyx Props */ + user: userPropTypes, + + /** Method to trigger when pressing back button of the header */ + onBackButtonPress: PropTypes.func.isRequired, +}; + +const defaultProps = { + user: {}, +}; + +function EnableBankAccount({reimbursementAccount, user, onBackButtonPress}) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const achData = lodashGet(reimbursementAccount, 'achData') || {}; + const {icon, iconSize} = getBankIcon(achData.bankName); + const isUsingExpensifyCard = user.isUsingExpensifyCard; + const formattedBankAccountNumber = achData.accountNumber ? `${translate('paymentMethodList.accountLastFour')} ${achData.accountNumber.slice(-4)}` : ''; + const bankName = achData.addressName; + const errors = lodashGet(reimbursementAccount, 'errors', {}); + const pendingAction = lodashGet(reimbursementAccount, 'pendingAction', null); + const shouldShowResetModal = lodashGet(reimbursementAccount, 'shouldShowResetModal'); + + return ( + + + +
+ + + + {!isUsingExpensifyCard ? translate('workspace.bankAccount.accountDescriptionNoCards') : translate('workspace.bankAccount.accountDescriptionWithCards')} + + {!isUsingExpensifyCard && ( +
+ {Boolean(user.isCheckingDomain) && {translate('workspace.card.checkingDomain')}} +
+ {shouldShowResetModal && } +
+ ); +} + +EnableBankAccount.displayName = 'EnableStep'; +EnableBankAccount.propTypes = propTypes; +EnableBankAccount.defaultProps = defaultProps; + +export default withOnyx({ + user: { + key: ONYXKEYS.USER, + }, +})(EnableBankAccount); From 50fa8226fbfa3971fd42be90a493656cd83ec41d Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Thu, 7 Dec 2023 15:06:18 +0100 Subject: [PATCH 08/35] fix: rollback import --- src/pages/ReimbursementAccount/EnableStep.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/EnableStep.js b/src/pages/ReimbursementAccount/EnableStep.js index 014f918d5776..d8d76d6cfb2f 100644 --- a/src/pages/ReimbursementAccount/EnableStep.js +++ b/src/pages/ReimbursementAccount/EnableStep.js @@ -17,13 +17,13 @@ import Text from '@components/Text'; import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; -import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import userPropTypes from '@pages/settings/userPropTypes'; import WorkspaceResetBankAccountModal from '@pages/workspace/WorkspaceResetBankAccountModal'; import * as Link from '@userActions/Link'; import * as BankAccounts from '@userActions/ReimbursementAccount'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import * as ReimbursementAccountProps from './reimbursementAccountPropTypes'; const propTypes = { /** Bank account currently in setup */ From c4b58d700098278616105da996ff556678a3e071 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Thu, 7 Dec 2023 15:21:29 +0100 Subject: [PATCH 09/35] fix: fixed translation --- src/languages/en.ts | 2 +- src/languages/es.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 708e41bf618e..3813cd2d7c6e 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1544,8 +1544,8 @@ export default { finishButtonText: 'Finish setup', validateYourBankAccount: 'Validate your bank account', validateButtonText: 'Validate', - maxAttemptsReached: 'Validation for this bank account has been disabled due to too many incorrect attempts.', validationInputLabel: 'Transaction', + maxAttemptsReached: 'Validation for this bank account has been disabled due to too many incorrect attempts.', description: 'A day or two after you add your account to Expensify we send three (3) transactions to your account. They have a merchant line like "Expensify, Inc. Validation".', descriptionCTA: 'Please enter each transaction amount in the fields below. Example: 1.51.', reviewingInfo: "Thanks! We're reviewing your information, and will be in touch shortly. Please check your chat with Concierge ", diff --git a/src/languages/es.ts b/src/languages/es.ts index d30ed13e43d2..3a33934581ea 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1568,6 +1568,7 @@ export default { finishButtonText: 'Finish setup', validateYourBankAccount: 'Validate your bank account', validateButtonText: 'Validate', + validationInputLabel: 'Transaction', maxAttemptsReached: 'Se ha inhabilitado la validación de esta cuenta bancaria debido a demasiados intentos incorrectos.', description: 'Uno o dos días después de añadir tu cuenta a Expensify, te enviaremos tres (3) transacciones a tu cuenta. Tienen un nombre de comerciante similar a "Expensify, Inc. Validation".', From 48d7a8ea85f04c1ab3cdf5fcad1bb458acdab789 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Fri, 15 Dec 2023 13:31:56 +0100 Subject: [PATCH 10/35] feat: handled sending proper data after the last step --- .../ReimbursementAccount/ACHContractStep.js | 7 +++-- .../CompleteVerification.js | 27 ++++++++----------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/pages/ReimbursementAccount/ACHContractStep.js b/src/pages/ReimbursementAccount/ACHContractStep.js index 307fe3cceb32..ce10f2a40300 100644 --- a/src/pages/ReimbursementAccount/ACHContractStep.js +++ b/src/pages/ReimbursementAccount/ACHContractStep.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import React, {useState} from 'react'; +import React, {useCallback, useState} from 'react'; import BeneficialOwnerInfo from './BeneficialOwnerInfo/BeneficialOwnerInfo'; import CompleteVerification from './CompleteVerification/CompleteVerification'; @@ -13,9 +13,12 @@ const propTypes = { function ACHContractStep({onBackButtonPress, onCloseButtonPress}) { const [isBeneficialOwnerInfoSet, setIsBeneficialOwnerInfoSet] = useState(false); + const handleCompleteVerificationBackButtonPress = useCallback(() => { + setIsBeneficialOwnerInfoSet(false); + }, []); if (isBeneficialOwnerInfoSet) { - return ; + return ; } return ( diff --git a/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js b/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js index 13979fa763fe..fb65217b59fd 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js +++ b/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js @@ -25,8 +25,8 @@ const propTypes = { /** The draft values of the bank account being setup */ reimbursementAccountDraft: reimbursementAccountDraftPropTypes, - /** Changes variable responsible for displaying step 4 or 5 */ - setIsBeneficialOwnerInfoSet: PropTypes.func.isRequired, + /** Handle back button press */ + onBackButtonPress: PropTypes.func.isRequired, }; const defaultProps = { @@ -35,39 +35,34 @@ const defaultProps = { }; const BODY_CONTENT = [ConfirmAgreements]; -const PERSONAL_INFO_STEP_KEYS = CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.INPUT_KEY; +const COMPLETE_VERIFICATION_KEYS = CONST.BANK_ACCOUNT.COMPLETE_VERIFICATION.INPUT_KEY; +const BENEFICIAL_OWNER_INFO_STEP_KEYS = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.INPUT_KEY; // This is a mocked step to showcase full transition between steps - will be removed with next PR -const CompleteVerification = forwardRef(({reimbursementAccount, reimbursementAccountDraft, setIsBeneficialOwnerInfoSet}, ref) => { +const CompleteVerification = forwardRef(({reimbursementAccount, reimbursementAccountDraft, onBackButtonPress}, ref) => { const {translate} = useLocalize(); const styles = useThemeStyles(); - const values = useMemo(() => getSubstepValues(PERSONAL_INFO_STEP_KEYS, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]); + const values = useMemo(() => getSubstepValues(COMPLETE_VERIFICATION_KEYS, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]); const submit = useCallback(() => { const payload = { - bankAccountID: getDefaultValueForReimbursementAccountField(reimbursementAccount, PERSONAL_INFO_STEP_KEYS.BANK_ACCOUNT_ID, 0), + bankAccountID: getDefaultValueForReimbursementAccountField(reimbursementAccount, COMPLETE_VERIFICATION_KEYS.BANK_ACCOUNT_ID, 0), ...values, }; - - // TODO mocked fieldsFrom UBO step should be replaced by real one - const tempValues = { - ownsMoreThan25Percent: false, - hasOtherBeneficialOwners: false, - beneficialOwners: '[]', - }; + const uboStepValues = getSubstepValues(BENEFICIAL_OWNER_INFO_STEP_KEYS, reimbursementAccountDraft, reimbursementAccount); BankAccounts.updateBeneficialOwnersForBankAccount({ - ...tempValues, + ...uboStepValues, ...payload, }); - }, [reimbursementAccount, values]); + }, [reimbursementAccount, reimbursementAccountDraft, values]); const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo} = useSubStep({bodyContent: BODY_CONTENT, startFrom: 0, onFinished: submit}); const handleBackButtonPress = () => { if (screenIndex === 0) { - setIsBeneficialOwnerInfoSet(false); + onBackButtonPress(); } else { prevScreen(); } From 2c6e183d4d01f0061e23100a4baf6403807ae399 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Fri, 15 Dec 2023 13:33:21 +0100 Subject: [PATCH 11/35] feat: handled sending proper data after the last step --- .../CompleteVerification/CompleteVerification.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js b/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js index fb65217b59fd..75afaa0ca895 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js +++ b/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js @@ -38,7 +38,6 @@ const BODY_CONTENT = [ConfirmAgreements]; const COMPLETE_VERIFICATION_KEYS = CONST.BANK_ACCOUNT.COMPLETE_VERIFICATION.INPUT_KEY; const BENEFICIAL_OWNER_INFO_STEP_KEYS = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.INPUT_KEY; -// This is a mocked step to showcase full transition between steps - will be removed with next PR const CompleteVerification = forwardRef(({reimbursementAccount, reimbursementAccountDraft, onBackButtonPress}, ref) => { const {translate} = useLocalize(); const styles = useThemeStyles(); From 714cb1a47910fa572d5584fad30105683971402e Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Fri, 15 Dec 2023 13:53:20 +0100 Subject: [PATCH 12/35] feat: added new compnents for verification and enable steps --- .../ConnectBankAccount/ConnectBankAccount.js | 2 +- .../EnableBankAccount/EnableBankAccount.js | 2 +- .../ReimbursementAccount/ReimbursementAccountPage.js | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js index bd56f6aee772..e0d4b19e31d9 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js @@ -8,10 +8,10 @@ import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; import BankAccount from '@libs/models/BankAccount'; import EnableStep from '@pages/ReimbursementAccount/EnableStep'; import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; -import useThemeStyles from '@styles/useThemeStyles'; import * as Report from '@userActions/Report'; import ONYXKEYS from '@src/ONYXKEYS'; import BankAccountValidationForm from './components/BankAccountValidationForm'; diff --git a/src/pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount.js b/src/pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount.js index 6b1ba9d6100e..948db2fdc1d2 100644 --- a/src/pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount.js +++ b/src/pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount.js @@ -15,10 +15,10 @@ import ScreenWrapper from '@components/ScreenWrapper'; import Section from '@components/Section'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import userPropTypes from '@pages/settings/userPropTypes'; import WorkspaceResetBankAccountModal from '@pages/workspace/WorkspaceResetBankAccountModal'; -import useThemeStyles from '@styles/useThemeStyles'; import * as Link from '@userActions/Link'; import * as BankAccounts from '@userActions/ReimbursementAccount'; import CONST from '@src/CONST'; diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index a2bbeb660f9a..02f807c7f8d2 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -28,12 +28,13 @@ import ROUTES from '@src/ROUTES'; import ACHContractStep from './ACHContractStep'; import BankAccountStep from './BankAccountStep'; import CompanyStep from './CompanyStep'; +import ConnectBankAccount from './ConnectBankAccount/ConnectBankAccount'; import ContinueBankAccountSetup from './ContinueBankAccountSetup'; +import EnableBankAccount from './EnableBankAccount/EnableBankAccount'; import EnableStep from './EnableStep'; import reimbursementAccountDraftPropTypes from './ReimbursementAccountDraftPropTypes'; import * as ReimbursementAccountProps from './reimbursementAccountPropTypes'; import RequestorStep from './RequestorStep'; -import ValidationStep from './ValidationStep'; const propTypes = { /** Plaid SDK token to use to initialize the widget */ @@ -521,19 +522,18 @@ function ReimbursementAccountPage({reimbursementAccount, route, onfidoToken, pol if (currentStep === CONST.BANK_ACCOUNT.STEP.VALIDATION) { return ( - ); } if (currentStep === CONST.BANK_ACCOUNT.STEP.ENABLE) { return ( - ); From 89a9e81eb6a2ba5c414b1ae6cb11037b1cf4a63c Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Fri, 15 Dec 2023 14:21:35 +0100 Subject: [PATCH 13/35] fix: fixed imports --- .../ConnectBankAccount/ConnectBankAccount.js | 2 +- .../ConnectBankAccount/components/BankAccountValidationForm.js | 2 +- .../ConnectBankAccount/components/Enable2FACard.js | 2 +- .../ConnectBankAccount/components/FinishChatCard.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js index e0d4b19e31d9..d4850c8a820c 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js @@ -90,7 +90,7 @@ function ConnectBankAccount({reimbursementAccount, onBackButtonPress, account}) ConnectBankAccount.propTypes = propTypes; ConnectBankAccount.defaultProps = defaultProps; -ConnectBankAccount.displayName = 'ConectBankAccount'; +ConnectBankAccount.displayName = 'ConnectBankAccount'; export default withOnyx({ account: { diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.js b/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.js index 48a065de0d59..fa06f70ac480 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.js +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/components/BankAccountValidationForm.js @@ -8,9 +8,9 @@ import FormProvider from '@components/Form/FormProvider'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; import * as ValidationUtils from '@libs/ValidationUtils'; import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; -import useThemeStyles from '@styles/useThemeStyles'; import * as BankAccounts from '@userActions/BankAccounts'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js b/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js index ca603ad0d15f..8e2e5d926f44 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js @@ -5,7 +5,7 @@ import * as Illustrations from '@components/Icon/Illustrations'; import Section from '@components/Section'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@styles/useThemeStyles'; +import useThemeStyles from '@hooks/useThemeStyles'; import * as Link from '@userActions/Link'; import ROUTES from '@src/ROUTES'; diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.js b/src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.js index 612aa353fb75..e13a64963f36 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.js +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/components/FinishChatCard.js @@ -9,9 +9,9 @@ import MenuItem from '@components/MenuItem'; import Section from '@components/Section'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import WorkspaceResetBankAccountModal from '@pages/workspace/WorkspaceResetBankAccountModal'; -import useThemeStyles from '@styles/useThemeStyles'; import * as BankAccounts from '@userActions/BankAccounts'; import * as Report from '@userActions/Report'; import Enable2FACard from './Enable2FACard'; From 4609424c7932c5ffc6c567c6b728aa186f41d77e Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Fri, 15 Dec 2023 15:42:46 +0100 Subject: [PATCH 14/35] fix: fixed helepr funciton --- .../ReimbursementAccount/EnableBankAccount/EnableBankAccount.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount.js b/src/pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount.js index 948db2fdc1d2..678a5b517627 100644 --- a/src/pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount.js +++ b/src/pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount.js @@ -44,7 +44,7 @@ function EnableBankAccount({reimbursementAccount, user, onBackButtonPress}) { const {translate} = useLocalize(); const achData = lodashGet(reimbursementAccount, 'achData') || {}; - const {icon, iconSize} = getBankIcon(achData.bankName); + const {icon, iconSize} = getBankIcon({bankName: achData.bankName, styles}); const isUsingExpensifyCard = user.isUsingExpensifyCard; const formattedBankAccountNumber = achData.accountNumber ? `${translate('paymentMethodList.accountLastFour')} ${achData.accountNumber.slice(-4)}` : ''; const bankName = achData.addressName; From d6fcd71e76a7122f5e02d57be5530b567c858ec7 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Fri, 15 Dec 2023 15:59:46 +0100 Subject: [PATCH 15/35] refactor: remove unused components --- .../ConnectBankAccount/ConnectBankAccount.js | 4 +- .../ReimbursementAccount/Enable2FAPrompt.js | 50 ---- src/pages/ReimbursementAccount/EnableStep.js | 138 ---------- .../ReimbursementAccountPage.js | 1 - .../ReimbursementAccount/ValidationStep.js | 239 ------------------ 5 files changed, 2 insertions(+), 430 deletions(-) delete mode 100644 src/pages/ReimbursementAccount/Enable2FAPrompt.js delete mode 100644 src/pages/ReimbursementAccount/EnableStep.js delete mode 100644 src/pages/ReimbursementAccount/ValidationStep.js diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js index d4850c8a820c..22269cb89990 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js @@ -10,10 +10,10 @@ import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import BankAccount from '@libs/models/BankAccount'; -import EnableStep from '@pages/ReimbursementAccount/EnableStep'; import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import * as Report from '@userActions/Report'; import ONYXKEYS from '@src/ONYXKEYS'; +import EnableBankAccount from "@pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount"; import BankAccountValidationForm from './components/BankAccountValidationForm'; import FinishChatCard from './components/FinishChatCard'; @@ -44,7 +44,7 @@ function ConnectBankAccount({reimbursementAccount, onBackButtonPress, account}) // If a user tries to navigate directly to the validate page we'll show them the EnableStep if (bankAccountState === BankAccount.STATE.OPEN) { - return ; + return ; } const maxAttemptsReached = lodashGet(reimbursementAccount, 'maxAttemptsReached'); diff --git a/src/pages/ReimbursementAccount/Enable2FAPrompt.js b/src/pages/ReimbursementAccount/Enable2FAPrompt.js deleted file mode 100644 index 90752a57c50b..000000000000 --- a/src/pages/ReimbursementAccount/Enable2FAPrompt.js +++ /dev/null @@ -1,50 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import {View} from 'react-native'; -import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; -import Section from '@components/Section'; -import Text from '@components/Text'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation from '@navigation/Navigation'; -import ROUTES from '@src/ROUTES'; - -const propTypes = { - ...withLocalizePropTypes, - - /** policyID of the workspace where user is setting up bank account */ - policyID: PropTypes.string.isRequired, -}; - -function Enable2FAPrompt({translate, policyID}) { - const styles = useThemeStyles(); - - return ( -
{ - Navigation.navigate(ROUTES.SETTINGS_2FA.getRoute(ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute('', policyID))); - }, - icon: Expensicons.Shield, - shouldShowRightIcon: true, - iconRight: Expensicons.NewWindow, - wrapperStyle: [styles.cardMenuItem], - }, - ]} - > - - {translate('validationStep.enable2FAText')} - -
- ); -} - -Enable2FAPrompt.propTypes = propTypes; -Enable2FAPrompt.displayName = 'Enable2FAPrompt'; - -export default withLocalize(Enable2FAPrompt); diff --git a/src/pages/ReimbursementAccount/EnableStep.js b/src/pages/ReimbursementAccount/EnableStep.js deleted file mode 100644 index d8d76d6cfb2f..000000000000 --- a/src/pages/ReimbursementAccount/EnableStep.js +++ /dev/null @@ -1,138 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React from 'react'; -import {ScrollView} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import Button from '@components/Button'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import getBankIcon from '@components/Icon/BankIcons'; -import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; -import MenuItem from '@components/MenuItem'; -import OfflineWithFeedback from '@components/OfflineWithFeedback'; -import ScreenWrapper from '@components/ScreenWrapper'; -import Section from '@components/Section'; -import Text from '@components/Text'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; -import userPropTypes from '@pages/settings/userPropTypes'; -import WorkspaceResetBankAccountModal from '@pages/workspace/WorkspaceResetBankAccountModal'; -import * as Link from '@userActions/Link'; -import * as BankAccounts from '@userActions/ReimbursementAccount'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import * as ReimbursementAccountProps from './reimbursementAccountPropTypes'; - -const propTypes = { - /** Bank account currently in setup */ - reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes.isRequired, - - /* Onyx Props */ - user: userPropTypes, - - /* The workspace name */ - policyName: PropTypes.string, - - /** Method to trigger when pressing back button of the header */ - onBackButtonPress: PropTypes.func.isRequired, - - ...withLocalizePropTypes, -}; - -const defaultProps = { - user: {}, - policyName: '', -}; - -function EnableStep(props) { - const styles = useThemeStyles(); - const isUsingExpensifyCard = props.user.isUsingExpensifyCard; - const achData = lodashGet(props.reimbursementAccount, 'achData') || {}; - const {icon, iconSize} = getBankIcon({bankName: achData.bankName, styles}); - const formattedBankAccountNumber = achData.accountNumber ? `${props.translate('paymentMethodList.accountLastFour')} ${achData.accountNumber.slice(-4)}` : ''; - const bankName = achData.addressName; - - const errors = lodashGet(props.reimbursementAccount, 'errors', {}); - const pendingAction = lodashGet(props.reimbursementAccount, 'pendingAction', null); - return ( - - - -
- - - - {!isUsingExpensifyCard - ? props.translate('workspace.bankAccount.accountDescriptionNoCards') - : props.translate('workspace.bankAccount.accountDescriptionWithCards')} - - {!isUsingExpensifyCard && ( -
- {Boolean(props.user.isCheckingDomain) && {props.translate('workspace.card.checkingDomain')}} -
- {props.reimbursementAccount.shouldShowResetModal && } -
- ); -} - -EnableStep.displayName = 'EnableStep'; -EnableStep.propTypes = propTypes; -EnableStep.defaultProps = defaultProps; - -export default compose( - withLocalize, - withOnyx({ - user: { - key: ONYXKEYS.USER, - }, - }), -)(EnableStep); diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index 02f807c7f8d2..3c5bf46c3a93 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -31,7 +31,6 @@ import CompanyStep from './CompanyStep'; import ConnectBankAccount from './ConnectBankAccount/ConnectBankAccount'; import ContinueBankAccountSetup from './ContinueBankAccountSetup'; import EnableBankAccount from './EnableBankAccount/EnableBankAccount'; -import EnableStep from './EnableStep'; import reimbursementAccountDraftPropTypes from './ReimbursementAccountDraftPropTypes'; import * as ReimbursementAccountProps from './reimbursementAccountPropTypes'; import RequestorStep from './RequestorStep'; diff --git a/src/pages/ReimbursementAccount/ValidationStep.js b/src/pages/ReimbursementAccount/ValidationStep.js deleted file mode 100644 index f1dfc944a24c..000000000000 --- a/src/pages/ReimbursementAccount/ValidationStep.js +++ /dev/null @@ -1,239 +0,0 @@ -import Str from 'expensify-common/lib/str'; -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React from 'react'; -import {ScrollView, View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import Button from '@components/Button'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapper from '@components/Form/InputWrapper'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; -import MenuItem from '@components/MenuItem'; -import ScreenWrapper from '@components/ScreenWrapper'; -import Section from '@components/Section'; -import Text from '@components/Text'; -import TextInput from '@components/TextInput'; -import TextLink from '@components/TextLink'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; -import BankAccount from '@libs/models/BankAccount'; -import * as ValidationUtils from '@libs/ValidationUtils'; -import WorkspaceResetBankAccountModal from '@pages/workspace/WorkspaceResetBankAccountModal'; -import * as BankAccounts from '@userActions/BankAccounts'; -import * as Report from '@userActions/Report'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import Enable2FAPrompt from './Enable2FAPrompt'; -import EnableStep from './EnableStep'; -import * as ReimbursementAccountProps from './reimbursementAccountPropTypes'; - -const propTypes = { - ...withLocalizePropTypes, - - /** Bank account currently in setup */ - reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes.isRequired, - - onBackButtonPress: PropTypes.func.isRequired, - - /** User's account who is setting up bank account */ - account: PropTypes.shape({ - /** If user has two-factor authentication enabled */ - requiresTwoFactorAuth: PropTypes.bool, - }), - - /** policyID of the workspace where user is setting up bank account */ - policyID: PropTypes.string.isRequired, -}; - -const defaultProps = { - account: { - requiresTwoFactorAuth: false, - }, -}; - -/** - * Filter input for validation amount - * Anything that isn't a number is returned as an empty string - * Any dollar amount (e.g. 1.12) will be returned as 112 - * - * @param {String} amount field input - * @returns {String} - */ -const filterInput = (amount) => { - let value = amount ? amount.toString().trim() : ''; - if (value === '' || _.isNaN(Number(value)) || !Math.abs(Str.fromUSDToNumber(value))) { - return ''; - } - - // If the user enters the values in dollars, convert it to the respective cents amount - if (_.contains(value, '.')) { - value = Str.fromUSDToNumber(value); - } - - return value; -}; - -function ValidationStep({reimbursementAccount, translate, onBackButtonPress, account, policyID}) { - const styles = useThemeStyles(); - /** - * @param {Object} values - form input values passed by the Form component - * @returns {Object} - */ - const validate = (values) => { - const errors = {}; - - _.each(values, (value, key) => { - const filteredValue = typeof value === 'string' ? filterInput(value) : value; - if (ValidationUtils.isRequiredFulfilled(filteredValue)) { - return; - } - errors[key] = 'common.error.invalidAmount'; - }); - - return errors; - }; - - /** - * @param {Object} values - form input values passed by the Form component - */ - const submit = (values) => { - const amount1 = filterInput(values.amount1); - const amount2 = filterInput(values.amount2); - const amount3 = filterInput(values.amount3); - - const validateCode = [amount1, amount2, amount3].join(','); - - // Send valid amounts to BankAccountAPI::validateBankAccount in Web-Expensify - const bankaccountID = lodashGet(reimbursementAccount, 'achData.bankAccountID'); - BankAccounts.validateBankAccount(bankaccountID, validateCode); - }; - - const state = lodashGet(reimbursementAccount, 'achData.state'); - - // If a user tries to navigate directly to the validate page we'll show them the EnableStep - if (state === BankAccount.STATE.OPEN) { - return ; - } - - const maxAttemptsReached = lodashGet(reimbursementAccount, 'maxAttemptsReached'); - const isVerifying = !maxAttemptsReached && state === BankAccount.STATE.VERIFYING; - const requiresTwoFactorAuth = lodashGet(account, 'requiresTwoFactorAuth'); - - return ( - - - {maxAttemptsReached && ( - - - {translate('validationStep.maxAttemptsReached')} {translate('common.please')}{' '} - {translate('common.contactUs')}. - - - )} - {!maxAttemptsReached && state === BankAccount.STATE.PENDING && ( - - - {translate('validationStep.description')} - {translate('validationStep.descriptionCTA')} - - - - - - - {!requiresTwoFactorAuth && ( - - - - )} - - )} - {isVerifying && ( - -
- {translate('validationStep.letsChatText')} -
- {reimbursementAccount.shouldShowResetModal && } - {!requiresTwoFactorAuth && } -
- )} -
- ); -} - -ValidationStep.propTypes = propTypes; -ValidationStep.defaultProps = defaultProps; -ValidationStep.displayName = 'ValidationStep'; - -export default compose( - withLocalize, - withOnyx({ - account: { - key: ONYXKEYS.ACCOUNT, - }, - }), -)(ValidationStep); From 4d0ca8bc765e6dd5e8ad0b6d790758f6c96b6777 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Fri, 15 Dec 2023 16:09:12 +0100 Subject: [PATCH 16/35] refactor: fixed prettier --- .../CompleteVerification/substeps/ConfirmAgreements.js | 4 ++-- .../ConnectBankAccount/ConnectBankAccount.js | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js index 868ef9fc90b0..f3647ae123bb 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js +++ b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js @@ -7,12 +7,12 @@ import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as ValidationUtils from '@libs/ValidationUtils'; import {reimbursementAccountPropTypes} from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import subStepPropTypes from '@pages/ReimbursementAccount/subStepPropTypes'; import getDefaultValueForReimbursementAccountField from '@pages/ReimbursementAccount/utils/getDefaultValueForReimbursementAccountField'; -import useThemeStyles from '@hooks/useThemeStyles'; -import * as ValidationUtils from '@libs/ValidationUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js index 22269cb89990..64ca0cc9d117 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js @@ -10,10 +10,10 @@ import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import BankAccount from '@libs/models/BankAccount'; +import EnableBankAccount from '@pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount'; import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import * as Report from '@userActions/Report'; import ONYXKEYS from '@src/ONYXKEYS'; -import EnableBankAccount from "@pages/ReimbursementAccount/EnableBankAccount/EnableBankAccount"; import BankAccountValidationForm from './components/BankAccountValidationForm'; import FinishChatCard from './components/FinishChatCard'; @@ -44,7 +44,12 @@ function ConnectBankAccount({reimbursementAccount, onBackButtonPress, account}) // If a user tries to navigate directly to the validate page we'll show them the EnableStep if (bankAccountState === BankAccount.STATE.OPEN) { - return ; + return ( + + ); } const maxAttemptsReached = lodashGet(reimbursementAccount, 'maxAttemptsReached'); From 0df650b04aa6f9745392e31d8eff1a8e013b4440 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Sun, 17 Dec 2023 20:45:14 +0100 Subject: [PATCH 17/35] fix: fixed stepper colors --- src/styles/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/styles/index.ts b/src/styles/index.ts index e9921a4bf16a..85a721de9e67 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -4134,7 +4134,7 @@ const styles = (theme: ThemeColors) => }, interactiveStepHeaderLockedStepButton: { - borderColor: colors.darkBorders, + borderColor: colors.productDark400, }, interactiveStepHeaderStepText: { @@ -4154,7 +4154,7 @@ const styles = (theme: ThemeColors) => }, interactiveStepHeaderLockedStepLine: { - backgroundColor: colors.darkBorders, + backgroundColor: colors.productDark400, }, confirmBankInfoCard: { backgroundColor: colors.green800, From 06d8f09ed96624339b1020476962b7cfe8d104c9 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Mon, 18 Dec 2023 09:02:05 +0100 Subject: [PATCH 18/35] fix: follow const variable uppercased names, change ubo step value name, move build url out form component --- .../CompleteVerification.js | 4 +-- .../substeps/ConfirmAgreements.js | 28 +++++++++++-------- .../components/Enable2FACard.js | 7 +++-- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js b/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js index 75afaa0ca895..952ed8bfda06 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js +++ b/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js @@ -49,10 +49,10 @@ const CompleteVerification = forwardRef(({reimbursementAccount, reimbursementAcc bankAccountID: getDefaultValueForReimbursementAccountField(reimbursementAccount, COMPLETE_VERIFICATION_KEYS.BANK_ACCOUNT_ID, 0), ...values, }; - const uboStepValues = getSubstepValues(BENEFICIAL_OWNER_INFO_STEP_KEYS, reimbursementAccountDraft, reimbursementAccount); + const beneficialOwnersStepValues = getSubstepValues(BENEFICIAL_OWNER_INFO_STEP_KEYS, reimbursementAccountDraft, reimbursementAccount); BankAccounts.updateBeneficialOwnersForBankAccount({ - ...uboStepValues, + ...beneficialOwnersStepValues, ...payload, }); }, [reimbursementAccount, reimbursementAccountDraft, values]); diff --git a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js index f3647ae123bb..e0217bbfd5ec 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js +++ b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js @@ -44,22 +44,26 @@ const validate = (values) => { return errors; }; -const completeVerificationKeys = CONST.BANK_ACCOUNT.COMPLETE_VERIFICATION.INPUT_KEY; +const COMPLETE_VERIFICATION_KEYS = CONST.BANK_ACCOUNT.COMPLETE_VERIFICATION.INPUT_KEY; function ConfirmAgreements({onNext, reimbursementAccount}) { const {translate} = useLocalize(); const styles = useThemeStyles(); const defaultValues = useMemo( () => ({ - [completeVerificationKeys.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT]: getDefaultValueForReimbursementAccountField( + [COMPLETE_VERIFICATION_KEYS.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT]: getDefaultValueForReimbursementAccountField( reimbursementAccount, - completeVerificationKeys.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT, + COMPLETE_VERIFICATION_KEYS.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT, false, ), - [completeVerificationKeys.CERTIFY_TRUE_INFORMATION]: getDefaultValueForReimbursementAccountField(reimbursementAccount, completeVerificationKeys.CERTIFY_TRUE_INFORMATION, false), - [completeVerificationKeys.ACCEPT_TERMS_AND_CONDITIONS]: getDefaultValueForReimbursementAccountField( + [COMPLETE_VERIFICATION_KEYS.CERTIFY_TRUE_INFORMATION]: getDefaultValueForReimbursementAccountField( reimbursementAccount, - completeVerificationKeys.ACCEPT_TERMS_AND_CONDITIONS, + COMPLETE_VERIFICATION_KEYS.CERTIFY_TRUE_INFORMATION, + false, + ), + [COMPLETE_VERIFICATION_KEYS.ACCEPT_TERMS_AND_CONDITIONS]: getDefaultValueForReimbursementAccountField( + reimbursementAccount, + COMPLETE_VERIFICATION_KEYS.ACCEPT_TERMS_AND_CONDITIONS, false, ), }), @@ -83,25 +87,25 @@ function ConfirmAgreements({onNext, reimbursementAccount}) { {translate('completeVerificationStep.isAuthorizedToUseBankAccount')}} - defaultValue={defaultValues[completeVerificationKeys.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT]} + defaultValue={defaultValues[COMPLETE_VERIFICATION_KEYS.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT]} shouldSaveDraft /> {translate('completeVerificationStep.certifyTrueAndAccurate')}} - defaultValue={defaultValues[completeVerificationKeys.CERTIFY_TRUE_INFORMATION]} + defaultValue={defaultValues[COMPLETE_VERIFICATION_KEYS.CERTIFY_TRUE_INFORMATION]} shouldSaveDraft /> ( @@ -109,7 +113,7 @@ function ConfirmAgreements({onNext, reimbursementAccount}) { {`${translate('completeVerificationStep.termsAndConditions')}`} )} - defaultValue={defaultValues[completeVerificationKeys.ACCEPT_TERMS_AND_CONDITIONS]} + defaultValue={defaultValues[COMPLETE_VERIFICATION_KEYS.ACCEPT_TERMS_AND_CONDITIONS]} shouldSaveDraft /> diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js b/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js index 8e2e5d926f44..32b1fc7d3282 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/components/Enable2FACard.js @@ -9,12 +9,13 @@ import useThemeStyles from '@hooks/useThemeStyles'; import * as Link from '@userActions/Link'; import ROUTES from '@src/ROUTES'; +const secureYourAccountUrl = encodeURI( + `settings?param={"section":"account","action":"enableTwoFactorAuth","exitTo":"${ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute()}","isFromNewDot":"true"}`, +); + function Enable2FACard() { const styles = useThemeStyles(); const {translate} = useLocalize(); - const secureYourAccountUrl = encodeURI( - `settings?param={"section":"account","action":"enableTwoFactorAuth","exitTo":"${ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute()}","isFromNewDot":"true"}`, - ); return (
Date: Mon, 18 Dec 2023 10:36:20 +0100 Subject: [PATCH 19/35] feat: updated translation --- src/languages/es.ts | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index 3a33934581ea..8211e232076d 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1554,31 +1554,30 @@ export default { }, }, completeVerificationStep: { - // TODO -bart- check translations - completeVerification: 'Complete verification', - confirmAgreements: 'Please confirm the agreements below.', - certifyTrueAndAccurate: 'Certifico que la información dada es correcta', + completeVerification: 'Completar la verificación', + confirmAgreements: 'Por favor, confirma los Acuerdos a continuación.', + certifyTrueAndAccurate: 'Certifico que la información dada es verdadera y precisa', certifyTrueAndAccurateError: 'Debe certificar que la información es verdadera y precisa', - isAuthorizedToUseBankAccount: 'Estoy autorizado a utilizar la cuenta bancaria de mi compañía para gastos de empresa', - isAuthorizedToUseBankAccountError: 'Debe ser un oficial controlador con autorización para operar la cuenta bancaria de la compañía', - termsAndConditions: 'Términos y condiciones', + isAuthorizedToUseBankAccount: 'Estoy autorizado para usar la cuenta bancaria de mi empresa para gastos comerciales', + isAuthorizedToUseBankAccountError: 'Debes ser un oficial controlador con autorización para operar la cuenta bancaria de la empresa.', + termsAndConditions: 'Términos y Condiciones', }, connectBankAccountStep: { - connectBankAccount: 'Connect bank account', - finishButtonText: 'Finish setup', - validateYourBankAccount: 'Validate your bank account', - validateButtonText: 'Validate', - validationInputLabel: 'Transaction', - maxAttemptsReached: 'Se ha inhabilitado la validación de esta cuenta bancaria debido a demasiados intentos incorrectos.', + connectBankAccount: 'Conectar cuenta bancaria', + finishButtonText: 'Finalizar configuración', + validateYourBankAccount: 'Valida tu cuenta bancaria', + validateButtonText: 'Validar', + validationInputLabel: 'Transacción', + maxAttemptsReached: 'La validación para esta cuenta bancaria se ha desactivado debido a demasiados intentos incorrectos.', description: - 'Uno o dos días después de añadir tu cuenta a Expensify, te enviaremos tres (3) transacciones a tu cuenta. Tienen un nombre de comerciante similar a "Expensify, Inc. Validation".', - descriptionCTA: 'Introduce el importe de cada transacción en los campos siguientes. Ejemplo: 1.51.', + 'Un día o dos después de agregar tu cuenta a Expensify, enviamos tres (3) transacciones a tu cuenta. Tienen un nombre de comerciante similar a "Expensify, Inc. Validation".', + descriptionCTA: 'Ingresa el importe de cada transacción en los campos a continuación. Ejemplo: 1.51.', reviewingInfo: '¡Gracias! Estamos revisando tu información y nos comunicaremos contigo en breve. Consulta el chat con Concierge ', forNextSteps: ' para conocer los próximos pasos para terminar de configurar tu cuenta bancaria.', letsChatCTA: 'Sí, vamos a chatear', - letsChatText: 'Gracias. Necesitamos tu ayuda para verificar la información, pero podemos hacerlo rápidamente a través del chat. ¿Estás listo?', + letsChatText: 'Gracias. Necesitamos tu ayuda para verificar la información, pero podemos resolver esto rápidamente a través del chat. ¿Estás Listo?', letsChatTitle: '¡Vamos a chatear!', - enable2FATitle: 'Evita fraudes, activa la autenticación de dos factores!', + enable2FATitle: '¡Evita fraudes, habilita la autenticación de dos factores!', enable2FAText: 'Tu seguridad es importante para nosotros. Por favor, configura ahora la autenticación de dos factores. Eso nos permitirá disputar las transacciones de la Tarjeta Expensify y reducirá tu riesgo de fraude.', secureYourAccount: 'Asegura tu cuenta', From eaeffedebe418e0780c455d8fbdcfe56ea8e3347 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Mon, 18 Dec 2023 11:14:57 +0100 Subject: [PATCH 20/35] fix: added default values, added close button to the CompleteVerification component --- .../ReimbursementAccount/ACHContractStep.js | 7 +++- .../CompleteVerification.js | 7 +++- .../substeps/ConfirmAgreements.js | 33 ++++++++----------- .../EnableBankAccount/EnableBankAccount.js | 4 +-- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/pages/ReimbursementAccount/ACHContractStep.js b/src/pages/ReimbursementAccount/ACHContractStep.js index ce10f2a40300..8a5fc5d4613d 100644 --- a/src/pages/ReimbursementAccount/ACHContractStep.js +++ b/src/pages/ReimbursementAccount/ACHContractStep.js @@ -18,7 +18,12 @@ function ACHContractStep({onBackButtonPress, onCloseButtonPress}) { }, []); if (isBeneficialOwnerInfoSet) { - return ; + return ( + + ); } return ( diff --git a/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js b/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js index 952ed8bfda06..cd54f5b25a0b 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js +++ b/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js @@ -27,6 +27,9 @@ const propTypes = { /** Handle back button press */ onBackButtonPress: PropTypes.func.isRequired, + + /** Exits flow and goes back to the workspace initial page */ + onCloseButtonPress: PropTypes.func.isRequired, }; const defaultProps = { @@ -38,7 +41,7 @@ const BODY_CONTENT = [ConfirmAgreements]; const COMPLETE_VERIFICATION_KEYS = CONST.BANK_ACCOUNT.COMPLETE_VERIFICATION.INPUT_KEY; const BENEFICIAL_OWNER_INFO_STEP_KEYS = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.INPUT_KEY; -const CompleteVerification = forwardRef(({reimbursementAccount, reimbursementAccountDraft, onBackButtonPress}, ref) => { +const CompleteVerification = forwardRef(({reimbursementAccount, reimbursementAccountDraft, onBackButtonPress, onCloseButtonPress}, ref) => { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -78,6 +81,8 @@ const CompleteVerification = forwardRef(({reimbursementAccount, reimbursementAcc ({ - [COMPLETE_VERIFICATION_KEYS.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT]: getDefaultValueForReimbursementAccountField( - reimbursementAccount, - COMPLETE_VERIFICATION_KEYS.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT, - false, - ), - [COMPLETE_VERIFICATION_KEYS.CERTIFY_TRUE_INFORMATION]: getDefaultValueForReimbursementAccountField( - reimbursementAccount, - COMPLETE_VERIFICATION_KEYS.CERTIFY_TRUE_INFORMATION, - false, - ), - [COMPLETE_VERIFICATION_KEYS.ACCEPT_TERMS_AND_CONDITIONS]: getDefaultValueForReimbursementAccountField( - reimbursementAccount, - COMPLETE_VERIFICATION_KEYS.ACCEPT_TERMS_AND_CONDITIONS, - false, - ), - }), - [reimbursementAccount], - ); + const defaultValues = { + [COMPLETE_VERIFICATION_KEYS.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT]: getDefaultValueForReimbursementAccountField( + reimbursementAccount, + COMPLETE_VERIFICATION_KEYS.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT, + false, + ), + [COMPLETE_VERIFICATION_KEYS.CERTIFY_TRUE_INFORMATION]: getDefaultValueForReimbursementAccountField(reimbursementAccount, COMPLETE_VERIFICATION_KEYS.CERTIFY_TRUE_INFORMATION, false), + [COMPLETE_VERIFICATION_KEYS.ACCEPT_TERMS_AND_CONDITIONS]: getDefaultValueForReimbursementAccountField( + reimbursementAccount, + COMPLETE_VERIFICATION_KEYS.ACCEPT_TERMS_AND_CONDITIONS, + false, + ), + }; return ( Date: Mon, 18 Dec 2023 11:37:50 +0100 Subject: [PATCH 21/35] fix: added default values and missed comments --- src/pages/ReimbursementAccount/ACHContractStep.js | 6 ++---- .../CompleteVerification/CompleteVerification.js | 2 +- .../ConnectBankAccount/ConnectBankAccount.js | 7 ++++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/pages/ReimbursementAccount/ACHContractStep.js b/src/pages/ReimbursementAccount/ACHContractStep.js index 8a5fc5d4613d..07f0828fe67f 100644 --- a/src/pages/ReimbursementAccount/ACHContractStep.js +++ b/src/pages/ReimbursementAccount/ACHContractStep.js @@ -1,5 +1,5 @@ import PropTypes from 'prop-types'; -import React, {useCallback, useState} from 'react'; +import React, {useState} from 'react'; import BeneficialOwnerInfo from './BeneficialOwnerInfo/BeneficialOwnerInfo'; import CompleteVerification from './CompleteVerification/CompleteVerification'; @@ -13,9 +13,7 @@ const propTypes = { function ACHContractStep({onBackButtonPress, onCloseButtonPress}) { const [isBeneficialOwnerInfoSet, setIsBeneficialOwnerInfoSet] = useState(false); - const handleCompleteVerificationBackButtonPress = useCallback(() => { - setIsBeneficialOwnerInfoSet(false); - }, []); + const handleCompleteVerificationBackButtonPress = () => setIsBeneficialOwnerInfoSet(false); if (isBeneficialOwnerInfoSet) { return ( diff --git a/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js b/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js index cd54f5b25a0b..f43c042c6484 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js +++ b/src/pages/ReimbursementAccount/CompleteVerification/CompleteVerification.js @@ -25,7 +25,7 @@ const propTypes = { /** The draft values of the bank account being setup */ reimbursementAccountDraft: reimbursementAccountDraftPropTypes, - /** Handle back button press */ + /** Handles back button press */ onBackButtonPress: PropTypes.func.isRequired, /** Exits flow and goes back to the workspace initial page */ diff --git a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js index 64ca0cc9d117..aedff279f14d 100644 --- a/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js +++ b/src/pages/ReimbursementAccount/ConnectBankAccount/ConnectBankAccount.js @@ -21,6 +21,7 @@ const propTypes = { /** Bank account currently in setup */ reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes.isRequired, + /** Handles back button press */ onBackButtonPress: PropTypes.func.isRequired, /** User's account who is setting up bank account */ @@ -40,7 +41,7 @@ function ConnectBankAccount({reimbursementAccount, onBackButtonPress, account}) const styles = useThemeStyles(); const {translate} = useLocalize(); - const bankAccountState = lodashGet(reimbursementAccount, 'achData.state'); + const bankAccountState = lodashGet(reimbursementAccount, 'achData.state', ''); // If a user tries to navigate directly to the validate page we'll show them the EnableStep if (bankAccountState === BankAccount.STATE.OPEN) { @@ -52,10 +53,10 @@ function ConnectBankAccount({reimbursementAccount, onBackButtonPress, account}) ); } - const maxAttemptsReached = lodashGet(reimbursementAccount, 'maxAttemptsReached'); + const maxAttemptsReached = lodashGet(reimbursementAccount, 'maxAttemptsReached', false); const isBankAccountVerifying = !maxAttemptsReached && bankAccountState === BankAccount.STATE.VERIFYING; const isBankAccountPending = bankAccountState === BankAccount.STATE.PENDING; - const requiresTwoFactorAuth = lodashGet(account, 'requiresTwoFactorAuth'); + const requiresTwoFactorAuth = lodashGet(account, 'requiresTwoFactorAuth', false); return ( Date: Mon, 18 Dec 2023 11:46:30 +0100 Subject: [PATCH 22/35] fix: removed unused useMemo --- .../CompleteVerification/substeps/ConfirmAgreements.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js index 4be9dac5cf31..cb172ae75430 100644 --- a/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js +++ b/src/pages/ReimbursementAccount/CompleteVerification/substeps/ConfirmAgreements.js @@ -1,4 +1,4 @@ -import React, {useMemo} from 'react'; +import React from 'react'; import {withOnyx} from 'react-native-onyx'; import CheckboxWithLabel from '@components/CheckboxWithLabel'; import FormProvider from '@components/Form/FormProvider'; From 598740d45849dc70f3dfff4b39f8c940620df53e Mon Sep 17 00:00:00 2001 From: Michal Muzyk Date: Thu, 21 Dec 2023 12:24:11 +0100 Subject: [PATCH 23/35] feat: BankInfo migration to ts --- .../{useSubStep.ts => useSubStep/index.ts} | 11 +- src/hooks/useSubStep/types.ts | 17 ++ src/libs/actions/BankAccounts.ts | 2 +- .../actions/ReimbursementAccount/index.js | 2 +- .../BankAccountManualStep.js | 146 ---------------- .../BankAccountPlaidStep.js | 156 ------------------ .../ReimbursementAccount/BankAccountStep.js | 25 --- .../BankInfo/{BankInfo.js => BankInfo.tsx} | 53 +++--- .../{Confirmation.js => Confirmation.tsx} | 43 +++-- .../substeps/{Manual.js => Manual.tsx} | 39 +++-- .../BankInfo/substeps/{Plaid.js => Plaid.tsx} | 71 ++++---- .../utils/getSubstepValues.ts | 4 +- src/types/onyx/ReimbursementAccount.ts | 8 +- tests/unit/useSubStepTest.js | 2 +- 14 files changed, 124 insertions(+), 455 deletions(-) rename src/hooks/{useSubStep.ts => useSubStep/index.ts} (86%) create mode 100644 src/hooks/useSubStep/types.ts delete mode 100644 src/pages/ReimbursementAccount/BankAccountManualStep.js delete mode 100644 src/pages/ReimbursementAccount/BankAccountPlaidStep.js rename src/pages/ReimbursementAccount/BankInfo/{BankInfo.js => BankInfo.tsx} (71%) rename src/pages/ReimbursementAccount/BankInfo/substeps/{Confirmation.js => Confirmation.tsx} (79%) rename src/pages/ReimbursementAccount/BankInfo/substeps/{Manual.js => Manual.tsx} (74%) rename src/pages/ReimbursementAccount/BankInfo/substeps/{Plaid.js => Plaid.tsx} (60%) diff --git a/src/hooks/useSubStep.ts b/src/hooks/useSubStep/index.ts similarity index 86% rename from src/hooks/useSubStep.ts rename to src/hooks/useSubStep/index.ts index 18519ba5b343..08a9089148b9 100644 --- a/src/hooks/useSubStep.ts +++ b/src/hooks/useSubStep/index.ts @@ -1,12 +1,7 @@ -import {ReactNode, useCallback, useRef, useState} from 'react'; +import {useCallback, useRef, useState} from 'react'; +import {UseSubStep} from './types'; -type Props = { - bodyContent: ReactNode[]; - onFinished: () => void; - startFrom?: number; -}; - -export default function useSubStep({bodyContent, onFinished, startFrom = 0}: Props) { +export default function useSubStep({bodyContent, onFinished, startFrom = 0}: UseSubStep) { const [screenIndex, setScreenIndex] = useState(startFrom); const isEditing = useRef(false); diff --git a/src/hooks/useSubStep/types.ts b/src/hooks/useSubStep/types.ts new file mode 100644 index 000000000000..f8b7e968ee7d --- /dev/null +++ b/src/hooks/useSubStep/types.ts @@ -0,0 +1,17 @@ +import {ComponentType} from 'react'; + +type SubStepProps = { + isEditing: boolean; + onNext: () => void; + onMove: (step: number) => void; + screenIndex?: number; + prevScreen?: () => void; +}; + +type UseSubStep = { + bodyContent: Array>; + onFinished: () => void; + startFrom?: number; +}; + +export type {SubStepProps, UseSubStep}; diff --git a/src/libs/actions/BankAccounts.ts b/src/libs/actions/BankAccounts.ts index 2d0b7d4dfa8b..ad8f6268601b 100644 --- a/src/libs/actions/BankAccounts.ts +++ b/src/libs/actions/BankAccounts.ts @@ -142,7 +142,7 @@ function addPersonalAddressForDraft(personalAddress: {requestorAddressStreet?: s /** * Submit Bank Account step with Plaid data so php can perform some checks. */ -function connectBankAccountWithPlaid(bankAccountID: number, selectedPlaidBankAccount: PlaidBankAccount) { +function connectBankAccountWithPlaid(bankAccountID: number, selectedPlaidBankAccount: Omit) { const commandName = 'ConnectBankAccountWithPlaid'; type ConnectBankAccountWithPlaidParams = { diff --git a/src/libs/actions/ReimbursementAccount/index.js b/src/libs/actions/ReimbursementAccount/index.js index 0404115f086b..da55a73ae6e6 100644 --- a/src/libs/actions/ReimbursementAccount/index.js +++ b/src/libs/actions/ReimbursementAccount/index.js @@ -12,7 +12,7 @@ export {setBankAccountFormValidationErrors, setPersonalBankAccountFormValidation * - CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL to ask them to enter their accountNumber and routingNumber * - CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID to ask them to login to their bank via Plaid * - * @param {String} subStep + * @param {String | null} subStep */ function setBankAccountSubStep(subStep) { Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {achData: {subStep}}); diff --git a/src/pages/ReimbursementAccount/BankAccountManualStep.js b/src/pages/ReimbursementAccount/BankAccountManualStep.js deleted file mode 100644 index 8e79a492bfe3..000000000000 --- a/src/pages/ReimbursementAccount/BankAccountManualStep.js +++ /dev/null @@ -1,146 +0,0 @@ -import lodashGet from 'lodash/get'; -import React, {useCallback} from 'react'; -import _ from 'underscore'; -import CheckboxWithLabel from '@components/CheckboxWithLabel'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapper from '@components/Form/InputWrapper'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import Text from '@components/Text'; -import TextInput from '@components/TextInput'; -import TextLink from '@components/TextLink'; -import {withLocalizePropTypes} from '@components/withLocalize'; -import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import shouldDelayFocus from '@libs/shouldDelayFocus'; -import * as ValidationUtils from '@libs/ValidationUtils'; -import * as BankAccounts from '@userActions/BankAccounts'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import ExampleCheck from './ExampleCheck'; -import StepPropTypes from './StepPropTypes'; - -const propTypes = { - ..._.omit(StepPropTypes, _.keys(withLocalizePropTypes)), -}; - -function BankAccountManualStep(props) { - const styles = useThemeStyles(); - const {translate} = useLocalize(); - const {reimbursementAccount, reimbursementAccountDraft} = props; - - const shouldDisableInputs = Boolean(lodashGet(reimbursementAccount, 'achData.bankAccountID')); - - /** - * @param {Object} values - form input values passed by the Form component - * @returns {Object} - */ - const validate = useCallback( - (values) => { - const requiredFields = ['routingNumber', 'accountNumber']; - const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields); - const routingNumber = values.routingNumber && values.routingNumber.trim(); - - if ( - values.accountNumber && - !CONST.BANK_ACCOUNT.REGEX.US_ACCOUNT_NUMBER.test(values.accountNumber.trim()) && - !(shouldDisableInputs && CONST.BANK_ACCOUNT.REGEX.MASKED_US_ACCOUNT_NUMBER.test(values.accountNumber.trim())) - ) { - errors.accountNumber = 'bankAccount.error.accountNumber'; - } else if (values.accountNumber && values.accountNumber === routingNumber) { - errors.accountNumber = translate('bankAccount.error.routingAndAccountNumberCannotBeSame'); - } - if (routingNumber && (!CONST.BANK_ACCOUNT.REGEX.SWIFT_BIC.test(routingNumber) || !ValidationUtils.isValidRoutingNumber(routingNumber))) { - errors.routingNumber = 'bankAccount.error.routingNumber'; - } - if (!values.acceptTerms) { - errors.acceptTerms = 'common.error.acceptTerms'; - } - - return errors; - }, - [translate, shouldDisableInputs], - ); - - const submit = useCallback( - (values) => { - BankAccounts.connectBankAccountManually( - lodashGet(reimbursementAccount, 'achData.bankAccountID') || 0, - values.accountNumber, - values.routingNumber, - lodashGet(reimbursementAccountDraft, ['plaidMask']), - ); - }, - [reimbursementAccount, reimbursementAccountDraft], - ); - - return ( - - - - {translate('bankAccount.checkHelpLine')} - - - - ( - - {translate('common.iAcceptThe')} - {translate('common.expensifyTermsOfService')} - - )} - defaultValue={props.getDefaultStateForField('acceptTerms', false)} - shouldSaveDraft - /> - - - ); -} - -BankAccountManualStep.propTypes = propTypes; -BankAccountManualStep.displayName = 'BankAccountManualStep'; -export default BankAccountManualStep; diff --git a/src/pages/ReimbursementAccount/BankAccountPlaidStep.js b/src/pages/ReimbursementAccount/BankAccountPlaidStep.js deleted file mode 100644 index c235a31f626f..000000000000 --- a/src/pages/ReimbursementAccount/BankAccountPlaidStep.js +++ /dev/null @@ -1,156 +0,0 @@ -import {useIsFocused} from '@react-navigation/native'; -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React, {useCallback, useEffect} from 'react'; -import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; -import AddPlaidBankAccount from '@components/AddPlaidBankAccount'; -import CheckboxWithLabel from '@components/CheckboxWithLabel'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapper from '@components/Form/InputWrapper'; -import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ScreenWrapper from '@components/ScreenWrapper'; -import Text from '@components/Text'; -import TextLink from '@components/TextLink'; -import withLocalize from '@components/withLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; -import * as BankAccounts from '@userActions/BankAccounts'; -import * as ReimbursementAccount from '@userActions/ReimbursementAccount'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import * as PlaidDataProps from './plaidDataPropTypes'; -import StepPropTypes from './StepPropTypes'; - -const propTypes = { - ...StepPropTypes, - - /** Contains plaid data */ - plaidData: PlaidDataProps.plaidDataPropTypes, - - /** The OAuth URI + stateID needed to re-initialize the PlaidLink after the user logs into their bank */ - receivedRedirectURI: PropTypes.string, - - /** During the OAuth flow we need to use the plaidLink token that we initially connected with */ - plaidLinkOAuthToken: PropTypes.string, -}; - -const defaultProps = { - plaidData: PlaidDataProps.plaidDataDefaultProps, - receivedRedirectURI: null, - plaidLinkOAuthToken: '', -}; - -function BankAccountPlaidStep(props) { - const styles = useThemeStyles(); - const {plaidData, receivedRedirectURI, plaidLinkOAuthToken, reimbursementAccount, reimbursementAccountDraft, onBackButtonPress, getDefaultStateForField, translate} = props; - const isFocused = useIsFocused(); - - const validate = useCallback((values) => { - const errorFields = {}; - if (!values.acceptTerms) { - errorFields.acceptTerms = 'common.error.acceptTerms'; - } - - return errorFields; - }, []); - - useEffect(() => { - const plaidBankAccounts = lodashGet(plaidData, 'bankAccounts') || []; - if (isFocused || plaidBankAccounts.length) { - return; - } - BankAccounts.setBankAccountSubStep(null); - }, [isFocused, plaidData]); - - const submit = useCallback(() => { - const selectedPlaidBankAccount = _.findWhere(lodashGet(plaidData, 'bankAccounts', []), { - plaidAccountID: lodashGet(reimbursementAccountDraft, 'plaidAccountID', ''), - }); - - const bankAccountData = { - routingNumber: selectedPlaidBankAccount.routingNumber, - accountNumber: selectedPlaidBankAccount.accountNumber, - plaidMask: selectedPlaidBankAccount.mask, - isSavings: selectedPlaidBankAccount.isSavings, - bankName: lodashGet(plaidData, 'bankName') || '', - plaidAccountID: selectedPlaidBankAccount.plaidAccountID, - plaidAccessToken: lodashGet(plaidData, 'plaidAccessToken') || '', - }; - ReimbursementAccount.updateReimbursementAccountDraft(bankAccountData); - - const bankAccountID = lodashGet(reimbursementAccount, 'achData.bankAccountID') || 0; - BankAccounts.connectBankAccountWithPlaid(bankAccountID, bankAccountData); - }, [reimbursementAccount, reimbursementAccountDraft, plaidData]); - - const bankAccountID = lodashGet(reimbursementAccount, 'achData.bankAccountID') || 0; - const selectedPlaidAccountID = lodashGet(reimbursementAccountDraft, 'plaidAccountID', ''); - - return ( - - - - { - ReimbursementAccount.updateReimbursementAccountDraft({plaidAccountID}); - }} - plaidData={plaidData} - onExitPlaid={() => BankAccounts.setBankAccountSubStep(null)} - receivedRedirectURI={receivedRedirectURI} - plaidLinkOAuthToken={plaidLinkOAuthToken} - allowDebit - bankAccountID={bankAccountID} - selectedPlaidAccountID={selectedPlaidAccountID} - /> - {Boolean(selectedPlaidAccountID) && !_.isEmpty(lodashGet(plaidData, 'bankAccounts')) && ( - ( - - {translate('common.iAcceptThe')} - {translate('common.expensifyTermsOfService')} - - )} - defaultValue={getDefaultStateForField('acceptTerms', false)} - shouldSaveDraft - /> - )} - - - ); -} - -BankAccountPlaidStep.propTypes = propTypes; -BankAccountPlaidStep.defaultProps = defaultProps; -BankAccountPlaidStep.displayName = 'BankAccountPlaidStep'; -export default compose( - withLocalize, - withOnyx({ - plaidData: { - key: ONYXKEYS.PLAID_DATA, - }, - }), -)(BankAccountPlaidStep); diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index cab656e1268b..21b2ee991be1 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -28,8 +28,6 @@ import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import BankAccountManualStep from './BankAccountManualStep'; -import BankAccountPlaidStep from './BankAccountPlaidStep'; import BankInfo from './BankInfo/BankInfo'; import StepPropTypes from './StepPropTypes'; @@ -101,29 +99,6 @@ function BankAccountStep(props) { return ; } - if (subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL) { - return ( - - ); - } - - if (subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID) { - return ( - - ); - } - - // TODO Move initial screen where you select setup type to new ReimbursementAccount page as the begining of whole flow; also cleanup once this is done return ( ; /** Reimbursement account from ONYX */ - reimbursementAccount: reimbursementAccountPropTypes, + reimbursementAccount: OnyxEntry; /** The draft values of the bank account being setup */ - reimbursementAccountDraft: reimbursementAccountDraftPropTypes, + reimbursementAccountDraft: OnyxEntry; }; -const defaultProps = { - plaidLinkToken: '', - reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps, - reimbursementAccountDraft: {}, -}; +type BankInfoProps = BankInfoOnyxProps; const bankInfoStepKeys = CONST.BANK_ACCOUNT.BANK_INFO_STEP.INPUT_KEY; -const manualSubsteps = [Manual, Confirmation]; -const plaidSubsteps = [Plaid, Confirmation]; +const manualSubsteps: Array> = [Manual, Confirmation]; +const plaidSubsteps: Array> = [Plaid, Confirmation]; const receivedRedirectURI = getPlaidOAuthReceivedRedirectURI(); -function BankInfo({reimbursementAccount, reimbursementAccountDraft, plaidLinkToken}) { +function BankInfo({reimbursementAccount = ReimbursementAccountProps.reimbursementAccountDefaultProps, reimbursementAccountDraft = {}, plaidLinkToken = ''}: BankInfoProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const [redirectedFromPlaidToManual, setRedirectedFromPlaidToManual] = React.useState(false); - const values = useMemo(() => getSubstepValues(bankInfoStepKeys, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]); + const values = useMemo(() => getSubstepValues(bankInfoStepKeys, reimbursementAccountDraft ?? {}, reimbursementAccount ?? {}), [reimbursementAccount, reimbursementAccountDraft]); - let setupType = getDefaultValueForReimbursementAccountField(reimbursementAccount, 'subStep'); + let setupType = reimbursementAccount?.achData?.subStep ?? ''; const shouldReinitializePlaidLink = plaidLinkToken && receivedRedirectURI && setupType !== CONST.BANK_ACCOUNT.SUBSTEP.MANUAL; if (shouldReinitializePlaidLink) { @@ -60,20 +55,18 @@ function BankInfo({reimbursementAccount, reimbursementAccountDraft, plaidLinkTok const submit = useCallback(() => { if (setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL) { BankAccounts.connectBankAccountManually( - Number(getDefaultValueForReimbursementAccountField(reimbursementAccount, bankInfoStepKeys.BANK_ACCOUNT_ID, '0')), + Number(reimbursementAccount?.achData?.bankAccountID ?? '0'), values[bankInfoStepKeys.ACCOUNT_NUMBER], values[bankInfoStepKeys.ROUTING_NUMBER], values[bankInfoStepKeys.PLAID_MASK], ); } else if (setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID) { - BankAccounts.connectBankAccountWithPlaid(Number(getDefaultValueForReimbursementAccountField(reimbursementAccount, bankInfoStepKeys.BANK_ACCOUNT_ID, '0')), { - [bankInfoStepKeys.ROUTING_NUMBER]: values[bankInfoStepKeys.ROUTING_NUMBER], - [bankInfoStepKeys.ACCOUNT_NUMBER]: values[bankInfoStepKeys.ACCOUNT_NUMBER], - [bankInfoStepKeys.PLAID_MASK]: values[bankInfoStepKeys.PLAID_MASK], - [bankInfoStepKeys.IS_SAVINGS]: values[bankInfoStepKeys.IS_SAVINGS], - [bankInfoStepKeys.BANK_NAME]: values[bankInfoStepKeys.BANK_NAME], - [bankInfoStepKeys.PLAID_ACCOUNT_ID]: values[bankInfoStepKeys.PLAID_ACCOUNT_ID], - [bankInfoStepKeys.PLAID_ACCESS_TOKEN]: values[bankInfoStepKeys.PLAID_ACCESS_TOKEN], + BankAccounts.connectBankAccountWithPlaid(Number(reimbursementAccount?.achData?.bankAccountID ?? '0'), { + [bankInfoStepKeys.ROUTING_NUMBER]: values[bankInfoStepKeys.ROUTING_NUMBER] ?? '', + [bankInfoStepKeys.ACCOUNT_NUMBER]: values[bankInfoStepKeys.ACCOUNT_NUMBER] ?? '', + [bankInfoStepKeys.BANK_NAME]: values[bankInfoStepKeys.BANK_NAME] ?? '', + [bankInfoStepKeys.PLAID_ACCOUNT_ID]: values[bankInfoStepKeys.PLAID_ACCOUNT_ID] ?? '', + [bankInfoStepKeys.PLAID_ACCESS_TOKEN]: values[bankInfoStepKeys.PLAID_ACCESS_TOKEN] ?? '', }); } }, [reimbursementAccount, setupType, values]); @@ -97,7 +90,6 @@ function BankInfo({reimbursementAccount, reimbursementAccountDraft, plaidLinkTok const handleBackButtonPress = () => { if (screenIndex === 0) { - // TODO replace it with navigation to ReimbursementAccountPage once base is updated BankAccounts.setBankAccountSubStep(null); } else { prevScreen(); @@ -105,6 +97,7 @@ function BankInfo({reimbursementAccount, reimbursementAccountDraft, plaidLinkTok }; return ( + // @ts-expect-error TODO: remove once ScreenWrapper (https://github.com/Expensify/App/issues/25128) is migrated to TS ({ reimbursementAccount: { key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, }, diff --git a/src/pages/ReimbursementAccount/BankInfo/substeps/Confirmation.js b/src/pages/ReimbursementAccount/BankInfo/substeps/Confirmation.tsx similarity index 79% rename from src/pages/ReimbursementAccount/BankInfo/substeps/Confirmation.js rename to src/pages/ReimbursementAccount/BankInfo/substeps/Confirmation.tsx index 88392af7c9df..82f878959e91 100644 --- a/src/pages/ReimbursementAccount/BankInfo/substeps/Confirmation.js +++ b/src/pages/ReimbursementAccount/BankInfo/substeps/Confirmation.tsx @@ -1,7 +1,7 @@ -import lodashGet from 'lodash/get'; import React, {useMemo} from 'react'; import {ScrollView, Text, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import {OnyxEntry} from 'react-native-onyx/lib/types'; import Button from '@components/Button'; import DotIndicatorMessage from '@components/DotIndicatorMessage'; import Icon from '@components/Icon'; @@ -9,46 +9,39 @@ import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; +import {SubStepProps} from '@hooks/useSubStep/types'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; -import reimbursementAccountDraftPropTypes from '@pages/ReimbursementAccount/ReimbursementAccountDraftPropTypes'; -import {reimbursementAccountPropTypes} from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes'; -import subStepPropTypes from '@pages/ReimbursementAccount/subStepPropTypes'; -import getDefaultValueForReimbursementAccountField from '@pages/ReimbursementAccount/utils/getDefaultValueForReimbursementAccountField'; import getSubstepValues from '@pages/ReimbursementAccount/utils/getSubstepValues'; import * as BankAccounts from '@userActions/BankAccounts'; import * as ReimbursementAccount from '@userActions/ReimbursementAccount'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {ReimbursementAccountDraft, ReimbursementAccount as TReimbursementAccount} from '@src/types/onyx'; -const propTypes = { +type ConfirmationOnyxProps = { /** Reimbursement account from ONYX */ - reimbursementAccount: reimbursementAccountPropTypes, + reimbursementAccount: OnyxEntry; /** The draft values of the bank account being setup */ - reimbursementAccountDraft: reimbursementAccountDraftPropTypes, - - ...subStepPropTypes, + reimbursementAccountDraft: OnyxEntry; }; -const defaultProps = { - reimbursementAccount: ReimbursementAccountProps.reimbursementAccountDefaultProps, - reimbursementAccountDraft: {}, -}; +type ConfirmationProps = ConfirmationOnyxProps & SubStepProps; const bankInfoStepKeys = CONST.BANK_ACCOUNT.BANK_INFO_STEP.INPUT_KEY; -function Confirmation({reimbursementAccount, reimbursementAccountDraft, onNext}) { +function Confirmation({reimbursementAccount = ReimbursementAccountProps.reimbursementAccountDefaultProps, reimbursementAccountDraft = {}, onNext}: ConfirmationProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const theme = useTheme(); - const isLoading = lodashGet(reimbursementAccount, 'isLoading', false); - const setupType = getDefaultValueForReimbursementAccountField(reimbursementAccount, 'subStep'); - const values = useMemo(() => getSubstepValues(bankInfoStepKeys, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]); - const error = ErrorUtils.getLatestErrorMessage(reimbursementAccount); + const isLoading = reimbursementAccount?.isLoading ?? false; + const setupType = reimbursementAccount?.achData?.subStep ?? ''; + const values = useMemo(() => getSubstepValues(bankInfoStepKeys, reimbursementAccountDraft ?? {}, reimbursementAccount ?? {}), [reimbursementAccount, reimbursementAccountDraft]); + const error = ErrorUtils.getLatestErrorMessage(reimbursementAccount ?? {}); const handleConnectDifferentAccount = () => { const bankAccountData = { @@ -66,6 +59,7 @@ function Confirmation({reimbursementAccount, reimbursementAccountDraft, onNext}) }; return ( + // @ts-expect-error TODO: remove once ScreenWrapper (https://github.com/Expensify/App/issues/25128) is migrated to TS )} {translate('bankAccount.thisBankAccount')} + )}