From dc0c88f86d05f653cd6b67b58e53cf0dc486e5b1 Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Wed, 20 Nov 2024 12:28:16 +0100 Subject: [PATCH 01/21] feat: Update corpay fields logic, integrate API --- src/CONST.ts | 1 + src/ONYXKEYS.ts | 4 + .../GetCorpayBankAccountFieldsParams.ts | 8 + src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 + src/libs/actions/BankAccounts.ts | 148 +----------------- .../NonUSD/BankInfo/BankInfo.tsx | 47 ++---- .../substeps/AccountHolderDetails.tsx | 134 ++++++++++++++++ .../BankInfo/substeps/BankAccountDetails.tsx | 12 +- .../NonUSD/BankInfo/substeps/Confirmation.tsx | 8 +- .../NonUSD/BankInfo/types.ts | 15 +- src/types/onyx/CorpayFields.ts | 42 +++++ src/types/onyx/index.ts | 2 + 13 files changed, 219 insertions(+), 205 deletions(-) create mode 100644 src/libs/API/parameters/GetCorpayBankAccountFieldsParams.ts create mode 100644 src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/AccountHolderDetails.tsx create mode 100644 src/types/onyx/CorpayFields.ts diff --git a/src/CONST.ts b/src/CONST.ts index c32248e6dcf3..276fefd81c98 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -629,6 +629,7 @@ const CONST = { HANG_TIGHT: 4, }, }, + BANK_INFO_STEP_ACCOUNT_HOLDER_KEY_PREFIX: 'accountHolder', }, INCORPORATION_TYPES: { LLC: 'LLC', diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index b4510a2faeed..1bf9a5244625 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -458,6 +458,9 @@ const ONYXKEYS = { /** The user's Concierge reportID */ CONCIERGE_REPORT_ID: 'conciergeReportID', + /* Corpay fieds to be used in the bank account creation setup */ + CORPAY_FIELDS: 'corpayFields', + /** Collection Keys */ COLLECTION: { DOWNLOAD: 'download_', @@ -1029,6 +1032,7 @@ type OnyxValuesMapping = { [ONYXKEYS.SHOULD_SHOW_SAVED_SEARCH_RENAME_TOOLTIP]: boolean; [ONYXKEYS.NVP_EXPENSIFY_COMPANY_CARDS_CUSTOM_NAMES]: Record; [ONYXKEYS.CONCIERGE_REPORT_ID]: string; + [ONYXKEYS.CORPAY_FIELDS]: OnyxTypes.CorpayFields; }; type OnyxValues = OnyxValuesMapping & OnyxCollectionValuesMapping & OnyxFormValuesMapping & OnyxFormDraftValuesMapping; diff --git a/src/libs/API/parameters/GetCorpayBankAccountFieldsParams.ts b/src/libs/API/parameters/GetCorpayBankAccountFieldsParams.ts new file mode 100644 index 000000000000..3e02b57f9e12 --- /dev/null +++ b/src/libs/API/parameters/GetCorpayBankAccountFieldsParams.ts @@ -0,0 +1,8 @@ +type GetCorpayBankAccountFieldsParams = { + countryISO: string; + currency: string; + isWithdrawal: boolean; + isBusinessBankAccount: boolean; +}; + +export default GetCorpayBankAccountFieldsParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 681114fd3b08..feb73af644bc 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -29,6 +29,7 @@ export type {default as ExpandURLPreviewParams} from './ExpandURLPreviewParams'; export type {default as GetMissingOnyxMessagesParams} from './GetMissingOnyxMessagesParams'; export type {default as GetNewerActionsParams} from './GetNewerActionsParams'; export type {default as GetOlderActionsParams} from './GetOlderActionsParams'; +export type {default as GetCorpayBankAccountFieldsParams} from './GetCorpayBankAccountFieldsParams'; export type {default as GetPolicyCategoriesParams} from './GetPolicyCategories'; export type {default as GetReportPrivateNoteParams} from './GetReportPrivateNoteParams'; export type {default as GetRouteParams} from './GetRouteParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index bd8a58555617..55da017ff5e2 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -888,6 +888,7 @@ type WriteCommandParameters = { }; const READ_COMMANDS = { + GET_CORPAY_BANK_ACCOUNT_FIELDS: 'GetCorpayBankAccountFields', CONNECT_POLICY_TO_QUICKBOOKS_ONLINE: 'ConnectPolicyToQuickbooksOnline', CONNECT_POLICY_TO_XERO: 'ConnectPolicyToXero', SYNC_POLICY_TO_QUICKBOOKS_ONLINE: 'SyncPolicyToQuickbooksOnline', @@ -967,6 +968,7 @@ type ReadCommandParameters = { [READ_COMMANDS.OPEN_PLAID_BANK_ACCOUNT_SELECTOR]: Parameters.OpenPlaidBankAccountSelectorParams; [READ_COMMANDS.GET_OLDER_ACTIONS]: Parameters.GetOlderActionsParams; [READ_COMMANDS.GET_NEWER_ACTIONS]: Parameters.GetNewerActionsParams; + [READ_COMMANDS.GET_CORPAY_BANK_ACCOUNT_FIELDS]: Parameters.GetCorpayBankAccountFieldsParams; [READ_COMMANDS.EXPAND_URL_PREVIEW]: Parameters.ExpandURLPreviewParams; [READ_COMMANDS.GET_REPORT_PRIVATE_NOTE]: Parameters.GetReportPrivateNoteParams; [READ_COMMANDS.OPEN_ROOM_MEMBERS_PAGE]: Parameters.OpenRoomMembersPageParams; diff --git a/src/libs/actions/BankAccounts.ts b/src/libs/actions/BankAccounts.ts index bac1dba9ec71..4f149a026ddf 100644 --- a/src/libs/actions/BankAccounts.ts +++ b/src/libs/actions/BankAccounts.ts @@ -344,8 +344,6 @@ function validateBankAccount(bankAccountID: number, validateCode: string, policy } function getCorpayBankAccountFields(country: string, currency: string) { - // TODO - Use parameters when API is ready - // eslint-disable-next-line @typescript-eslint/no-unused-vars const parameters = { countryISO: country, currency, @@ -353,151 +351,7 @@ function getCorpayBankAccountFields(country: string, currency: string) { isBusinessBankAccount: true, }; - // return API.read(READ_COMMANDS.GET_CORPAY_BANK_ACCOUNT_FIELDS, parameters); - return { - bankCountry: 'AU', - bankCurrency: 'AUD', - classification: 'Business', - destinationCountry: 'AU', - formFields: [ - { - errorMessage: 'Swift must be less than 12 characters', - id: 'swiftBicCode', - isRequired: false, - isRequiredInValueSet: true, - label: 'Swift Code', - regEx: '^.{0,12}$', - validationRules: [ - { - errorMessage: 'Swift must be less than 12 characters', - regEx: '^.{0,12}$', - }, - { - errorMessage: 'The following characters are not allowed: <,>, "', - regEx: '^[^<>\\x22]*$', - }, - ], - }, - { - errorMessage: 'Beneficiary Bank Name must be less than 250 characters', - id: 'bankName', - isRequired: true, - isRequiredInValueSet: true, - label: 'Bank Name', - regEx: '^.{0,250}$', - validationRules: [ - { - errorMessage: 'Beneficiary Bank Name must be less than 250 characters', - regEx: '^.{0,250}$', - }, - { - errorMessage: 'The following characters are not allowed: <,>, "', - regEx: '^[^<>\\x22]*$', - }, - ], - }, - { - errorMessage: 'City must be less than 100 characters', - id: 'bankCity', - isRequired: true, - isRequiredInValueSet: true, - label: 'Bank City', - regEx: '^.{0,100}$', - validationRules: [ - { - errorMessage: 'City must be less than 100 characters', - regEx: '^.{0,100}$', - }, - { - errorMessage: 'The following characters are not allowed: <,>, "', - regEx: '^[^<>\\x22]*$', - }, - ], - }, - { - errorMessage: 'Bank Address Line 1 must be less than 1000 characters', - id: 'bankAddressLine1', - isRequired: true, - isRequiredInValueSet: true, - label: 'Bank Address', - regEx: '^.{0,1000}$', - validationRules: [ - { - errorMessage: 'Bank Address Line 1 must be less than 1000 characters', - regEx: '^.{0,1000}$', - }, - { - errorMessage: 'The following characters are not allowed: <,>, "', - regEx: '^[^<>\\x22]*$', - }, - ], - }, - { - detailedRule: [ - { - isRequired: true, - value: [ - { - errorMessage: 'Beneficiary Account Number is invalid. Value should be 1 to 50 characters long.', - regEx: '^.{1,50}$', - ruleDescription: '1 to 50 characters', - }, - ], - }, - ], - errorMessage: 'Beneficiary Account Number is invalid. Value should be 1 to 50 characters long.', - id: 'accountNumber', - isRequired: true, - isRequiredInValueSet: true, - label: 'Account Number (iACH)', - regEx: '^.{1,50}$', - validationRules: [ - { - errorMessage: 'Beneficiary Account Number is invalid. Value should be 1 to 50 characters long.', - regEx: '^.{1,50}$', - ruleDescription: '1 to 50 characters', - }, - { - errorMessage: 'The following characters are not allowed: <,>, "', - regEx: '^[^<>\\x22]*$', - }, - ], - }, - { - detailedRule: [ - { - isRequired: true, - value: [ - { - errorMessage: 'BSB Number is invalid. Value should be exactly 6 digits long.', - regEx: '^[0-9]{6}$', - ruleDescription: 'Exactly 6 digits', - }, - ], - }, - ], - errorMessage: 'BSB Number is invalid. Value should be exactly 6 digits long.', - id: 'routingCode', - isRequired: true, - isRequiredInValueSet: true, - label: 'BSB Number', - regEx: '^[0-9]{6}$', - validationRules: [ - { - errorMessage: 'BSB Number is invalid. Value should be exactly 6 digits long.', - regEx: '^[0-9]{6}$', - ruleDescription: 'Exactly 6 digits', - }, - { - errorMessage: 'The following characters are not allowed: <,>, "', - regEx: '^[^<>\\x22]*$', - }, - ], - }, - ], - paymentMethods: ['E'], - preferredMethod: 'E', - }; + return API.read(READ_COMMANDS.GET_CORPAY_BANK_ACCOUNT_FIELDS, parameters); } function clearReimbursementAccount() { diff --git a/src/pages/ReimbursementAccount/NonUSD/BankInfo/BankInfo.tsx b/src/pages/ReimbursementAccount/NonUSD/BankInfo/BankInfo.tsx index 7c5d853428c5..66cd84593a71 100644 --- a/src/pages/ReimbursementAccount/NonUSD/BankInfo/BankInfo.tsx +++ b/src/pages/ReimbursementAccount/NonUSD/BankInfo/BankInfo.tsx @@ -1,17 +1,16 @@ import type {ComponentType} from 'react'; -import React, {useCallback, useEffect, useState} from 'react'; +import React from 'react'; import {useOnyx} from 'react-native-onyx'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import useLocalize from '@hooks/useLocalize'; import useSubStep from '@hooks/useSubStep'; -import * as BankAccounts from '@userActions/BankAccounts'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; +import AccountHolderDetails from './substeps/AccountHolderDetails'; import BankAccountDetails from './substeps/BankAccountDetails'; import Confirmation from './substeps/Confirmation'; import UploadStatement from './substeps/UploadStatement'; -import type {BankInfoSubStepProps, CorpayFormField} from './types'; +import type {BankInfoSubStepProps} from './types'; type BankInfoProps = { /** Handles back button press */ @@ -21,17 +20,11 @@ type BankInfoProps = { onSubmit: () => void; }; -const {COUNTRY} = INPUT_IDS.ADDITIONAL_DATA; - -const bodyContent: Array> = [BankAccountDetails, UploadStatement, Confirmation]; - function BankInfo({onBackButtonPress, onSubmit}: BankInfoProps) { const {translate} = useLocalize(); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); - const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); - const [corpayFields, setCorpayFields] = useState([]); - const country = reimbursementAccountDraft?.[COUNTRY] ?? ''; + const [corpayFields] = useOnyx(ONYXKEYS.CORPAY_FIELDS); const policyID = reimbursementAccount?.achData?.policyID ?? '-1'; const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); const currency = policy?.outputCurrency ?? ''; @@ -40,6 +33,9 @@ function BankInfo({onBackButtonPress, onSubmit}: BankInfoProps) { onSubmit(); }; + const bodyContent: Array> = + currency !== CONST.CURRENCY.AUD ? [BankAccountDetails, AccountHolderDetails, Confirmation] : [BankAccountDetails, AccountHolderDetails, UploadStatement, Confirmation]; + const { componentToRender: SubStep, isEditing, @@ -48,15 +44,8 @@ function BankInfo({onBackButtonPress, onSubmit}: BankInfoProps) { prevScreen, moveTo, goToTheLastStep, - resetScreenIndex, } = useSubStep({bodyContent, startFrom: 0, onFinished: submit}); - // Temporary solution to get the fields for the corpay bank account fields - useEffect(() => { - const response = BankAccounts.getCorpayBankAccountFields(country, currency); - setCorpayFields((response?.formFields as CorpayFormField[]) ?? []); - }, [country, currency]); - const handleBackButtonPress = () => { if (isEditing) { goToTheLastStep(); @@ -65,27 +54,11 @@ function BankInfo({onBackButtonPress, onSubmit}: BankInfoProps) { if (screenIndex === 0) { onBackButtonPress(); - } else if (currency === CONST.CURRENCY.AUD) { - prevScreen(); } else { - resetScreenIndex(); + prevScreen(); } }; - const handleNextScreen = useCallback(() => { - if (screenIndex === 2) { - nextScreen(); - return; - } - - if (currency !== CONST.CURRENCY.AUD) { - goToTheLastStep(); - return; - } - - nextScreen(); - }, [currency, goToTheLastStep, nextScreen, screenIndex]); - return ( ); diff --git a/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/AccountHolderDetails.tsx b/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/AccountHolderDetails.tsx new file mode 100644 index 000000000000..c0187b9ce7c7 --- /dev/null +++ b/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/AccountHolderDetails.tsx @@ -0,0 +1,134 @@ +import React, {useCallback, useMemo} from 'react'; +import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; +import FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; +import type {FormInputErrors, FormOnyxKeys, FormOnyxValues} from '@components/Form/types'; +import PushRowWithModal from '@components/PushRowWithModal'; +import Text from '@components/Text'; +import TextInput from '@components/TextInput'; +import useLocalize from '@hooks/useLocalize'; +import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; +import useThemeStyles from '@hooks/useThemeStyles'; +import type {BankInfoSubStepProps} from '@pages/ReimbursementAccount/NonUSD/BankInfo/types'; +import getSubstepValues from '@pages/ReimbursementAccount/utils/getSubstepValues'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {ReimbursementAccountForm} from '@src/types/form/ReimbursementAccountForm'; +import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; + +const {ACCOUNT_HOLDER_COUNTRY} = INPUT_IDS.ADDITIONAL_DATA; + +function AccountHolderDetails({onNext, isEditing, corpayFields}: BankInfoSubStepProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + + const accountHolderDetailsFields = useMemo(() => { + return corpayFields?.filter((field) => field.id.includes(CONST.NON_USD_BANK_ACCOUNT.BANK_INFO_STEP_ACCOUNT_HOLDER_KEY_PREFIX)); + }, [corpayFields]); + const fieldIds = accountHolderDetailsFields?.map((field) => field.id); + + const subStepKeys = accountHolderDetailsFields?.reduce((acc, field) => { + acc[field.id as keyof ReimbursementAccountForm] = field.id as keyof ReimbursementAccountForm; + return acc; + }, {} as Record); + + const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); + const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); + const defaultValues = useMemo(() => getSubstepValues(subStepKeys ?? {}, reimbursementAccountDraft, reimbursementAccount), [subStepKeys, reimbursementAccount, reimbursementAccountDraft]); + + const handleSubmit = useReimbursementAccountStepFormSubmit({ + fieldIds: fieldIds as Array>, + onNext, + shouldSaveDraft: isEditing, + }); + + const validate = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const errors: FormInputErrors = {}; + + accountHolderDetailsFields?.forEach((field) => { + const fieldID = field.id as keyof FormOnyxValues; + + if (field.isRequired && !values[fieldID]) { + errors[fieldID] = translate('common.error.fieldRequired'); + } + + field.validationRules.forEach((rule) => { + if (!rule.regEx) { + return; + } + + if (new RegExp(rule.regEx).test(values[fieldID] ? String(values[fieldID]) : '')) { + return; + } + + errors[fieldID] = rule.errorMessage; + }); + }); + + return errors; + }, + [accountHolderDetailsFields, translate], + ); + + const inputs = useMemo(() => { + return accountHolderDetailsFields?.map((field) => { + if (field.id === ACCOUNT_HOLDER_COUNTRY) { + return ( + + + + ); + } + + return ( + + + + ); + }); + }, [accountHolderDetailsFields, styles.flex2, styles.mb6, styles.mhn5, defaultValues, isEditing, translate]); + + return ( + + + {translate('bankInfoStep.whatAreYour')} + {inputs} + + + ); +} + +AccountHolderDetails.displayName = 'AccountHolderDetails'; + +export default AccountHolderDetails; diff --git a/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/BankAccountDetails.tsx b/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/BankAccountDetails.tsx index b3482a516c1f..d9bb9fe19671 100644 --- a/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/BankAccountDetails.tsx +++ b/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/BankAccountDetails.tsx @@ -16,13 +16,17 @@ function BankAccountDetails({onNext, isEditing, corpayFields}: BankInfoSubStepPr const {translate} = useLocalize(); const styles = useThemeStyles(); - const fieldIds = corpayFields.map((field) => field.id); + const bankAccountDetailsFields = useMemo(() => { + return corpayFields?.filter((field) => !field.id.includes(CONST.NON_USD_BANK_ACCOUNT.BANK_INFO_STEP_ACCOUNT_HOLDER_KEY_PREFIX)); + }, [corpayFields]); + + const fieldIds = bankAccountDetailsFields?.map((field) => field.id); const validate = useCallback( (values: FormOnyxValues): FormInputErrors => { const errors: FormInputErrors = {}; - corpayFields.forEach((field) => { + corpayFields?.forEach((field) => { const fieldID = field.id as keyof FormOnyxValues; if (field.isRequired && !values[fieldID]) { @@ -54,7 +58,7 @@ function BankAccountDetails({onNext, isEditing, corpayFields}: BankInfoSubStepPr }); const inputs = useMemo(() => { - return corpayFields.map((field) => { + return bankAccountDetailsFields?.map((field) => { return ( ); }); - }, [corpayFields, styles.flex2, styles.mb6, isEditing]); + }, [bankAccountDetailsFields, styles.flex2, styles.mb6, isEditing]); return ( { const keys: Record = {}; - corpayFields.forEach((field) => { - keys[field.id] = field.id; + corpayFields?.forEach((field) => { + keys[field.id] = field.id as keyof ReimbursementAccountForm; }); return keys; }, [corpayFields]); @@ -32,11 +32,11 @@ function Confirmation({onNext, onMove, corpayFields}: BankInfoSubStepProps) { const items = useMemo( () => ( <> - {corpayFields.map((field) => { + {corpayFields?.map((field) => { return ( { onMove(0); diff --git a/src/pages/ReimbursementAccount/NonUSD/BankInfo/types.ts b/src/pages/ReimbursementAccount/NonUSD/BankInfo/types.ts index 17943b29e3d3..4946b95ee496 100644 --- a/src/pages/ReimbursementAccount/NonUSD/BankInfo/types.ts +++ b/src/pages/ReimbursementAccount/NonUSD/BankInfo/types.ts @@ -1,17 +1,6 @@ import type {SubStepProps} from '@hooks/useSubStep/types'; -import type {ReimbursementAccountForm} from '@src/types/form'; +import type {CorpayFormField} from '@src/types/onyx/CorpayFields'; -type CorpayFormField = { - id: keyof ReimbursementAccountForm; - isRequired: boolean; - errorMessage: string; - label: string; - regEx?: string; - validationRules: Array<{errorMessage: string; regEx: string}>; - defaultValue?: string; - detailedRule?: Array<{isRequired: boolean; value: Array<{errorMessage: string; regEx: string; ruleDescription: string}>}>; -}; - -type BankInfoSubStepProps = SubStepProps & {corpayFields: CorpayFormField[]}; +type BankInfoSubStepProps = SubStepProps & {corpayFields?: CorpayFormField[]}; export type {BankInfoSubStepProps, CorpayFormField}; diff --git a/src/types/onyx/CorpayFields.ts b/src/types/onyx/CorpayFields.ts new file mode 100644 index 000000000000..da4c93b66834 --- /dev/null +++ b/src/types/onyx/CorpayFields.ts @@ -0,0 +1,42 @@ +/** + * Represents a form field with validation rules. + */ +type CorpayFormField = { + /** Error message for the form field */ + errorMessage: string; + /** Unique identifier for the form field */ + id: string; + /** Indicates if the field is required */ + isRequired: boolean; + /** Indicates if the field is required in the value set */ + isRequiredInValueSet: boolean; + /** Label for the form field */ + label: string; + /** Regular expression for the form field */ + regEx: string; + /** Validation rules for the form field */ + validationRules: Array<{ + /** Error message for the validation rule */ + errorMessage: string; + /** Regular expression for the validation rule */ + regEx: string; + }>; +}; + +/** CorpayFormFields */ +type CorpayFormFields = { + /** Country of the bank */ + bankCountry: string; + /** Currency of the bank */ + bankCurrency: string; + /** Classification of the bank */ + classification: string; + /** Destination country of the bank */ + destinationCountry: string; + /** Form fields for the Corpay form */ + formFields: CorpayFormField[]; +}; + +export default CorpayFormFields; + +export type {CorpayFormField}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index cec5243990a6..21fed723a07e 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -16,6 +16,7 @@ import type CardFeeds from './CardFeeds'; import type {AddNewCompanyCardFeed, CompanyCardFeed} from './CardFeeds'; import type CardOnWaitlist from './CardOnWaitlist'; import type {CapturedLogs, Log} from './Console'; +import type CorpayFields from './CorpayFields'; import type Credentials from './Credentials'; import type Currency from './Currency'; import type {CurrencyList} from './Currency'; @@ -124,6 +125,7 @@ export type { CardList, CardOnWaitlist, Credentials, + CorpayFields, Currency, CurrencyList, CustomStatusDraft, From d4b216546a4fa66cf5b8056412dadadcc14ab179 Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Wed, 20 Nov 2024 15:08:20 +0100 Subject: [PATCH 02/21] fix: variable value --- .../NonUSD/BankInfo/substeps/AccountHolderDetails.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/AccountHolderDetails.tsx b/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/AccountHolderDetails.tsx index c0187b9ce7c7..acb69d3312bb 100644 --- a/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/AccountHolderDetails.tsx +++ b/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/AccountHolderDetails.tsx @@ -17,7 +17,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {ReimbursementAccountForm} from '@src/types/form/ReimbursementAccountForm'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; -const {ACCOUNT_HOLDER_COUNTRY} = INPUT_IDS.ADDITIONAL_DATA; +const {ACCOUNT_HOLDER_COUNTRY} = INPUT_IDS.ADDITIONAL_DATA.CORPAY; function AccountHolderDetails({onNext, isEditing, corpayFields}: BankInfoSubStepProps) { const {translate} = useLocalize(); From 54e779f6d6722d1f7579bf1a8161280c6480fde2 Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Tue, 26 Nov 2024 10:12:22 +0100 Subject: [PATCH 03/21] feat: Add Corpay bank account creation parameters and update related components --- .../BankAccountCreateCorpayParams.ts | 8 ++++++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 ++ src/libs/actions/BankAccounts.ts | 14 +++++++++- .../NonUSD/BankInfo/BankInfo.tsx | 13 ++++++++- .../BankInfo/substeps/BankAccountDetails.tsx | 2 +- .../NonUSD/BankInfo/substeps/Confirmation.tsx | 10 +++++-- .../NonUSD/BankInfo/types.ts | 2 +- .../NonUSD/BusinessInfo/substeps/Address.tsx | 2 +- .../NonUSD/Country/substeps/Confirmation.tsx | 27 ++++++++++--------- src/types/form/ReimbursementAccountForm.ts | 12 +++++++-- src/types/onyx/CorpayFields.ts | 2 ++ src/types/onyx/ReimbursementAccount.ts | 4 ++- 13 files changed, 77 insertions(+), 22 deletions(-) create mode 100644 src/libs/API/parameters/BankAccountCreateCorpayParams.ts diff --git a/src/libs/API/parameters/BankAccountCreateCorpayParams.ts b/src/libs/API/parameters/BankAccountCreateCorpayParams.ts new file mode 100644 index 000000000000..3c617d326009 --- /dev/null +++ b/src/libs/API/parameters/BankAccountCreateCorpayParams.ts @@ -0,0 +1,8 @@ +type BankAccountCreateCorpayParams = { + type: number; + isSavings: boolean; + isWithdrawal: boolean; + inputs: string; +}; + +export default BankAccountCreateCorpayParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index feb73af644bc..1f3a3500a229 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -8,6 +8,7 @@ export type {default as RestartBankAccountSetupParams} from './RestartBankAccoun export type {default as AddSchoolPrincipalParams} from './AddSchoolPrincipalParams'; export type {default as AuthenticatePusherParams} from './AuthenticatePusherParams'; export type {default as BankAccountHandlePlaidErrorParams} from './BankAccountHandlePlaidErrorParams'; +export type {default as BankAccountCreateCorpayParams} from './BankAccountCreateCorpayParams'; export type {default as BeginAppleSignInParams} from './BeginAppleSignInParams'; export type {default as BeginGoogleSignInParams} from './BeginGoogleSignInParams'; export type {default as BeginSignInParams} from './BeginSignInParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 55da017ff5e2..3b4af17b492f 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -437,6 +437,7 @@ const WRITE_COMMANDS = { SELF_TOUR_VIEWED: 'SelfTourViewed', UPDATE_INVOICE_COMPANY_NAME: 'UpdateInvoiceCompanyName', UPDATE_INVOICE_COMPANY_WEBSITE: 'UpdateInvoiceCompanyWebsite', + BANK_ACCOUNT_CREATE_CORPAY: 'BankAccount_CreateCorpay', } as const; type WriteCommand = ValueOf; @@ -765,6 +766,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.APPROVE_MONEY_REQUEST_ON_SEARCH]: Parameters.ApproveMoneyRequestOnSearchParams; [WRITE_COMMANDS.PAY_MONEY_REQUEST_ON_SEARCH]: Parameters.PayMoneyRequestOnSearchParams; [WRITE_COMMANDS.UNHOLD_MONEY_REQUEST_ON_SEARCH]: Parameters.UnholdMoneyRequestOnSearchParams; + [WRITE_COMMANDS.BANK_ACCOUNT_CREATE_CORPAY]: Parameters.BankAccountCreateCorpayParams; [WRITE_COMMANDS.REQUEST_REFUND]: null; [WRITE_COMMANDS.CONNECT_POLICY_TO_SAGE_INTACCT]: Parameters.ConnectPolicyToSageIntacctParams; diff --git a/src/libs/actions/BankAccounts.ts b/src/libs/actions/BankAccounts.ts index 4f149a026ddf..067511e03fc2 100644 --- a/src/libs/actions/BankAccounts.ts +++ b/src/libs/actions/BankAccounts.ts @@ -20,7 +20,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {Route} from '@src/ROUTES'; import type {PersonalBankAccountForm} from '@src/types/form'; -import type {ACHContractStepProps, BeneficialOwnersStepProps, CompanyStepProps, RequestorStepProps} from '@src/types/form/ReimbursementAccountForm'; +import type {ACHContractStepProps, BeneficialOwnersStepProps, CompanyStepProps, ReimbursementAccountForm, RequestorStepProps} from '@src/types/form/ReimbursementAccountForm'; import type PlaidBankAccount from '@src/types/onyx/PlaidBankAccount'; import type {BankAccountStep, ReimbursementAccountStep, ReimbursementAccountSubStep} from '@src/types/onyx/ReimbursementAccount'; import type {OnyxData} from '@src/types/onyx/Request'; @@ -354,6 +354,17 @@ function getCorpayBankAccountFields(country: string, currency: string) { return API.read(READ_COMMANDS.GET_CORPAY_BANK_ACCOUNT_FIELDS, parameters); } +function createCorpayBankAccount(fields: ReimbursementAccountForm) { + const parameters = { + type: 1, + isSavings: false, + isWithdrawal: true, + inputs: JSON.stringify(fields), + }; + + return API.write(WRITE_COMMANDS.BANK_ACCOUNT_CREATE_CORPAY, parameters); +} + function clearReimbursementAccount() { Onyx.set(ONYXKEYS.REIMBURSEMENT_ACCOUNT, null); } @@ -566,6 +577,7 @@ export { openPlaidView, connectBankAccountManually, connectBankAccountWithPlaid, + createCorpayBankAccount, deletePaymentBankAccount, handlePlaidError, setPersonalBankAccountContinueKYCOnSuccess, diff --git a/src/pages/ReimbursementAccount/NonUSD/BankInfo/BankInfo.tsx b/src/pages/ReimbursementAccount/NonUSD/BankInfo/BankInfo.tsx index 66cd84593a71..cf83a2365669 100644 --- a/src/pages/ReimbursementAccount/NonUSD/BankInfo/BankInfo.tsx +++ b/src/pages/ReimbursementAccount/NonUSD/BankInfo/BankInfo.tsx @@ -1,17 +1,21 @@ import type {ComponentType} from 'react'; -import React from 'react'; +import React, {useEffect} from 'react'; import {useOnyx} from 'react-native-onyx'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import useLocalize from '@hooks/useLocalize'; import useSubStep from '@hooks/useSubStep'; +import * as BankAccounts from '@userActions/BankAccounts'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; import AccountHolderDetails from './substeps/AccountHolderDetails'; import BankAccountDetails from './substeps/BankAccountDetails'; import Confirmation from './substeps/Confirmation'; import UploadStatement from './substeps/UploadStatement'; import type {BankInfoSubStepProps} from './types'; +const {DESTINATION_COUNTRY} = INPUT_IDS.ADDITIONAL_DATA; + type BankInfoProps = { /** Handles back button press */ onBackButtonPress: () => void; @@ -24,15 +28,21 @@ function BankInfo({onBackButtonPress, onSubmit}: BankInfoProps) { const {translate} = useLocalize(); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); + const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); const [corpayFields] = useOnyx(ONYXKEYS.CORPAY_FIELDS); const policyID = reimbursementAccount?.achData?.policyID ?? '-1'; const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); const currency = policy?.outputCurrency ?? ''; + const country = reimbursementAccountDraft?.[DESTINATION_COUNTRY] ?? ''; const submit = () => { onSubmit(); }; + useEffect(() => { + BankAccounts.getCorpayBankAccountFields(country, currency); + }, [country, currency]); + const bodyContent: Array> = currency !== CONST.CURRENCY.AUD ? [BankAccountDetails, AccountHolderDetails, Confirmation] : [BankAccountDetails, AccountHolderDetails, UploadStatement, Confirmation]; @@ -72,6 +82,7 @@ function BankInfo({onBackButtonPress, onSubmit}: BankInfoProps) { onNext={nextScreen} onMove={moveTo} corpayFields={corpayFields?.formFields} + preferredMethod={corpayFields?.preferredMethod} /> ); diff --git a/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/BankAccountDetails.tsx b/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/BankAccountDetails.tsx index d9bb9fe19671..5e1356430440 100644 --- a/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/BankAccountDetails.tsx +++ b/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/BankAccountDetails.tsx @@ -34,7 +34,7 @@ function BankAccountDetails({onNext, isEditing, corpayFields}: BankInfoSubStepPr } field.validationRules.forEach((rule) => { - if (rule.regEx) { + if (!rule.regEx) { return; } diff --git a/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/Confirmation.tsx b/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/Confirmation.tsx index c10c98b77418..2d22b52d28b6 100644 --- a/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/Confirmation.tsx +++ b/src/pages/ReimbursementAccount/NonUSD/BankInfo/substeps/Confirmation.tsx @@ -10,11 +10,12 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import type {BankInfoSubStepProps} from '@pages/ReimbursementAccount/NonUSD/BankInfo/types'; import getSubstepValues from '@pages/ReimbursementAccount/utils/getSubstepValues'; +import * as BankAccounts from '@userActions/BankAccounts'; import ONYXKEYS from '@src/ONYXKEYS'; import type {ReimbursementAccountForm} from '@src/types/form/ReimbursementAccountForm'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; -function Confirmation({onNext, onMove, corpayFields}: BankInfoSubStepProps) { +function Confirmation({onNext, onMove, corpayFields, preferredMethod}: BankInfoSubStepProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -58,6 +59,11 @@ function Confirmation({onNext, onMove, corpayFields}: BankInfoSubStepProps) { [corpayFields, onMove, reimbursementAccountDraft, translate, values], ); + const handleNext = () => { + BankAccounts.createCorpayBankAccount({...reimbursementAccountDraft, preferredMethod} as ReimbursementAccountForm); + onNext(); + }; + return ( {({safeAreaPaddingBottomStyle}) => ( @@ -72,7 +78,7 @@ function Confirmation({onNext, onMove, corpayFields}: BankInfoSubStepProps) {