Skip to content

Commit 884ba29

Browse files
authored
Merge pull request #60696 from callstack-internal/fix/60633-global-vbba-followup
fix: Global Reimbursements fixes and improvements
2 parents e0b8943 + 474a930 commit 884ba29

File tree

21 files changed

+232
-56
lines changed

21 files changed

+232
-56
lines changed

src/ONYXKEYS.ts

+9
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,13 @@ const ONYXKEYS = {
520520
/** Billing receipt details */
521521
BILLING_RECEIPT_DETAILS: 'billingReceiptDetails',
522522

523+
/** Set when user tries to connect VBBA but workspace currency is unsupported and is forced to change
524+
* This is later used to redirect user directly back to the VBBA flow */
525+
IS_FORCED_TO_CHANGE_CURRENCY: 'isForcedToChangeCurrency',
526+
527+
/** Set this gets redirected from global reimbursements flow */
528+
IS_COMING_FROM_GLOBAL_REIMBURSEMENTS_FLOW: 'isComingFromGlobalReimbursementsFlow',
529+
523530
/** Collection Keys */
524531
COLLECTION: {
525532
DOWNLOAD: 'download_',
@@ -1151,6 +1158,8 @@ type OnyxValuesMapping = {
11511158
[ONYXKEYS.BILLING_RECEIPT_DETAILS]: OnyxTypes.BillingReceiptDetails;
11521159
[ONYXKEYS.NVP_SIDE_PANEL]: OnyxTypes.SidePanel;
11531160
[ONYXKEYS.SCHEDULE_CALL_DRAFT]: OnyxTypes.ScheduleCallDraft;
1161+
[ONYXKEYS.IS_FORCED_TO_CHANGE_CURRENCY]: boolean | undefined;
1162+
[ONYXKEYS.IS_COMING_FROM_GLOBAL_REIMBURSEMENTS_FLOW]: boolean | undefined;
11541163
};
11551164

11561165
type OnyxDerivedValuesMapping = {

src/languages/en.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -2719,10 +2719,10 @@ const translations = {
27192719
letsDoubleCheck: 'Let’s double check that everything looks right.',
27202720
legalName: 'Legal name',
27212721
proofOf: 'Proof of personal address',
2722-
enterOneEmail: 'Enter the email of director or senior officer at',
2722+
enterOneEmail: ({companyName}: CompanyNameParams) => `Enter the email of director or senior officer at ${companyName}`,
27232723
regulationRequiresOneMoreDirector: 'Regulation requires at least more director or senior officer as a signer.',
27242724
hangTight: 'Hang tight...',
2725-
enterTwoEmails: 'Enter the emails of two directors or senior officers at',
2725+
enterTwoEmails: ({companyName}: CompanyNameParams) => `Enter the emails of two directors or senior officers at ${companyName}`,
27262726
sendReminder: 'Send a reminder',
27272727
chooseFile: 'Choose file',
27282728
weAreWaiting: "We're waiting for others to verify their identities as directors or senior officers of the business.",

src/languages/es.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -2745,10 +2745,10 @@ const translations = {
27452745
letsDoubleCheck: 'Vamos a verificar que todo esté correcto.',
27462746
legalName: 'Nombre legal',
27472747
proofOf: 'Comprobante de domicilio personal',
2748-
enterOneEmail: 'Introduce el correo electrónico del director o alto funcionario en',
2748+
enterOneEmail: ({companyName}: CompanyNameParams) => `Introduce el correo electrónico del director o alto funcionario en ${companyName}`,
27492749
regulationRequiresOneMoreDirector: 'El reglamento exige que haya otro director o funcionario superior como firmante.',
27502750
hangTight: 'Espera un momento...',
2751-
enterTwoEmails: 'Introduce los correos electrónicos de dos directores o altos funcionarios en',
2751+
enterTwoEmails: ({companyName}: CompanyNameParams) => `Introduce los correos electrónicos de dos directores o altos funcionarios en ${companyName}`,
27522752
sendReminder: 'Enviar un recordatorio',
27532753
chooseFile: 'Seleccionar archivo',
27542754
weAreWaiting: 'Estamos esperando que otros verifiquen sus identidades como directores o altos funcionarios de la empresa.',

src/libs/actions/Policy/Policy.ts

+10
Original file line numberDiff line numberDiff line change
@@ -5170,6 +5170,14 @@ function clearBillingReceiptDetailsErrors() {
51705170
Onyx.merge(ONYXKEYS.BILLING_RECEIPT_DETAILS, {errors: null});
51715171
}
51725172

5173+
function setIsForcedToChangeCurrency(value: boolean) {
5174+
Onyx.set(ONYXKEYS.IS_FORCED_TO_CHANGE_CURRENCY, value);
5175+
}
5176+
5177+
function setIsComingFromGlobalReimbursementsFlow(value: boolean) {
5178+
Onyx.set(ONYXKEYS.IS_COMING_FROM_GLOBAL_REIMBURSEMENTS_FLOW, value);
5179+
}
5180+
51735181
export {
51745182
leaveWorkspace,
51755183
addBillingCardAndRequestPolicyOwnerChange,
@@ -5276,4 +5284,6 @@ export {
52765284
clearBillingReceiptDetailsErrors,
52775285
clearQuickbooksOnlineAutoSyncErrorField,
52785286
updateLastAccessedWorkspaceSwitcher,
5287+
setIsForcedToChangeCurrency,
5288+
setIsComingFromGlobalReimbursementsFlow,
52795289
};

src/pages/ReimbursementAccount/NonUSD/Agreements/index.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import useSubStep from '@hooks/useSubStep';
77
import type {SubStepProps} from '@hooks/useSubStep/types';
88
import getSubStepValues from '@pages/ReimbursementAccount/utils/getSubStepValues';
99
import {clearReimbursementAccountFinishCorpayBankAccountOnboarding, finishCorpayBankAccountOnboarding} from '@userActions/BankAccounts';
10+
import {clearErrors} from '@userActions/FormActions';
1011
import CONST from '@src/CONST';
1112
import ONYXKEYS from '@src/ONYXKEYS';
1213
import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
@@ -67,6 +68,7 @@ function Agreements({onBackButtonPress, onSubmit}: AgreementsProps) {
6768
const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo, goToTheLastStep} = useSubStep({bodyContent, startFrom: 0, onFinished: submit});
6869

6970
const handleBackButtonPress = () => {
71+
clearErrors(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM);
7072
if (isEditing) {
7173
goToTheLastStep();
7274
return;

src/pages/ReimbursementAccount/NonUSD/BankInfo/BankInfo.tsx

+28-10
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import type {ComponentType} from 'react';
33
import {useOnyx} from 'react-native-onyx';
44
import InteractiveStepWrapper from '@components/InteractiveStepWrapper';
55
import useLocalize from '@hooks/useLocalize';
6+
import useNetwork from '@hooks/useNetwork';
67
import useSubStep from '@hooks/useSubStep';
78
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
89
import {getBankInfoStepValues} from '@pages/ReimbursementAccount/NonUSD/utils/getBankInfoStepValues';
910
import getInitialSubStepForBankInfoStep from '@pages/ReimbursementAccount/NonUSD/utils/getInitialSubStepForBankInfoStep';
1011
import getInputKeysForBankInfoStep from '@pages/ReimbursementAccount/NonUSD/utils/getInputKeysForBankInfoStep';
1112
import {clearReimbursementAccountBankCreation, createCorpayBankAccount, getCorpayBankAccountFields} from '@userActions/BankAccounts';
13+
import {clearErrors} from '@userActions/FormActions';
1214
import CONST from '@src/CONST';
1315
import ONYXKEYS from '@src/ONYXKEYS';
1416
import type {ReimbursementAccountForm} from '@src/types/form/ReimbursementAccountForm';
@@ -35,42 +37,57 @@ function BankInfo({onBackButtonPress, onSubmit, policyID}: BankInfoProps) {
3537
const {translate} = useLocalize();
3638

3739
const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {canBeMissing: false});
38-
const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT, {canBeMissing: false});
39-
const [corpayFields] = useOnyx(ONYXKEYS.CORPAY_FIELDS, {initWithStoredValues: false, canBeMissing: true});
40+
const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT, {canBeMissing: true});
41+
const [corpayFields] = useOnyx(ONYXKEYS.CORPAY_FIELDS, {canBeMissing: true});
4042
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {canBeMissing: false});
4143
const currency = policy?.outputCurrency ?? '';
42-
const country = reimbursementAccount?.achData?.[COUNTRY] ?? reimbursementAccountDraft?.[COUNTRY] ?? '';
44+
const country = reimbursementAccountDraft?.[COUNTRY] ?? reimbursementAccount?.achData?.[COUNTRY] ?? '';
4345
const inputKeys = getInputKeysForBankInfoStep(corpayFields);
4446
const values = useMemo(() => getBankInfoStepValues(inputKeys, reimbursementAccountDraft, reimbursementAccount), [inputKeys, reimbursementAccount, reimbursementAccountDraft]);
45-
const startFrom = getInitialSubStepForBankInfoStep(values, corpayFields);
47+
const startFrom = useMemo(() => getInitialSubStepForBankInfoStep(values, corpayFields), [corpayFields, values]);
4648

4749
const submit = () => {
4850
const {formFields, isLoading, isSuccess, ...corpayData} = corpayFields ?? {};
4951

5052
createCorpayBankAccount({...values, ...corpayData} as ReimbursementAccountForm, policyID);
5153
};
5254

55+
useNetwork({
56+
onReconnect: () => {
57+
getCorpayBankAccountFields(country, currency);
58+
},
59+
});
60+
5361
useEffect(() => {
5462
if (reimbursementAccount?.isLoading === true || !!reimbursementAccount?.errors) {
5563
return;
5664
}
5765

5866
if (reimbursementAccount?.isSuccess === true) {
5967
onSubmit();
68+
clearReimbursementAccountBankCreation();
6069
}
61-
}, [onSubmit, reimbursementAccount?.errors, reimbursementAccount?.isLoading, reimbursementAccount?.isSuccess]);
62-
63-
useEffect(() => {
64-
return () => clearReimbursementAccountBankCreation();
65-
}, []);
70+
}, [corpayFields?.bankCurrency, country, currency, onSubmit, reimbursementAccount?.errors, reimbursementAccount?.isLoading, reimbursementAccount?.isSuccess]);
6671

6772
useEffect(() => {
73+
// No fetching when there is no country
6874
if (country === '') {
6975
return;
7076
}
7177

78+
// When workspace currency is set to EUR we need to refetch if country from Step 1 doesn't match country inside fetched Corpay data
79+
if (currency === CONST.CURRENCY.EUR && country !== corpayFields?.bankCountry) {
80+
getCorpayBankAccountFields(country, currency);
81+
return;
82+
}
83+
84+
// No fetching when workspace currency matches the currency inside fetched Corpay
85+
if (currency === corpayFields?.bankCurrency) {
86+
return;
87+
}
88+
7289
getCorpayBankAccountFields(country, currency);
73-
}, [country, currency]);
90+
}, [corpayFields?.bankCurrency, corpayFields?.bankCountry, country, currency]);
7491

7592
const bodyContent: Array<ComponentType<BankInfoSubStepProps>> = [BankAccountDetails, AccountHolderDetails, Confirmation];
7693

@@ -85,6 +102,7 @@ function BankInfo({onBackButtonPress, onSubmit, policyID}: BankInfoProps) {
85102
} = useSubStep<BankInfoSubStepProps>({bodyContent, startFrom, onFinished: submit});
86103

87104
const handleBackButtonPress = () => {
105+
clearErrors(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM);
88106
if (isEditing) {
89107
goToTheLastStep();
90108
return;

src/pages/ReimbursementAccount/NonUSD/BeneficialOwnerInfo/BeneficialOwnerInfo.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import useSubStep from '@hooks/useSubStep';
1010
import type {SubStepProps} from '@hooks/useSubStep/types';
1111
import getOwnerDetailsAndOwnerFilesForBeneficialOwners from '@pages/ReimbursementAccount/NonUSD/utils/getOwnerDetailsAndOwnerFilesForBeneficialOwners';
1212
import {clearReimbursementAccountSaveCorpayOnboardingBeneficialOwners, saveCorpayOnboardingBeneficialOwners} from '@userActions/BankAccounts';
13-
import {setDraftValues} from '@userActions/FormActions';
13+
import {clearErrors, setDraftValues} from '@userActions/FormActions';
1414
import CONST from '@src/CONST';
1515
import ONYXKEYS from '@src/ONYXKEYS';
1616
import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
@@ -152,6 +152,7 @@ function BeneficialOwnerInfo({onBackButtonPress, onSubmit}: BeneficialOwnerInfoP
152152
const beneficialOwnerAddressCountryValue = reimbursementAccountDraft?.[beneficialOwnerAddressCountryInputID] ?? '';
153153

154154
const handleBackButtonPress = () => {
155+
clearErrors(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM);
155156
if (isEditing) {
156157
goToTheLastStep();
157158
return;

src/pages/ReimbursementAccount/NonUSD/BusinessInfo/BusinessInfo.tsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {SubStepProps} from '@hooks/useSubStep/types';
88
import getInitialSubStepForBusinessInfoStep from '@pages/ReimbursementAccount/NonUSD/utils/getInitialSubStepForBusinessInfoStep';
99
import getSubStepValues from '@pages/ReimbursementAccount/utils/getSubStepValues';
1010
import {clearReimbursementAccountSaveCorpayOnboardingCompanyDetails, getCorpayOnboardingFields, saveCorpayOnboardingCompanyDetails} from '@userActions/BankAccounts';
11+
import {clearErrors} from '@userActions/FormActions';
1112
import CONST from '@src/CONST';
1213
import ONYXKEYS from '@src/ONYXKEYS';
1314
import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
@@ -21,6 +22,7 @@ import Name from './subSteps/Name';
2122
import PaymentVolume from './subSteps/PaymentVolume';
2223
import RegistrationNumber from './subSteps/RegistrationNumber';
2324
import TaxIDEINNumber from './subSteps/TaxIDEINNumber';
25+
import Website from './subSteps/Website';
2426

2527
type BusinessInfoProps = {
2628
/** Handles back button press */
@@ -32,6 +34,7 @@ type BusinessInfoProps = {
3234

3335
const bodyContent: Array<ComponentType<SubStepProps>> = [
3436
Name,
37+
Website,
3538
Address,
3639
ContactInformation,
3740
RegistrationNumber,
@@ -45,6 +48,7 @@ const bodyContent: Array<ComponentType<SubStepProps>> = [
4548

4649
const INPUT_KEYS = {
4750
NAME: INPUT_IDS.ADDITIONAL_DATA.CORPAY.COMPANY_NAME,
51+
WEBSITE: INPUT_IDS.ADDITIONAL_DATA.CORPAY.COMPANY_WEBSITE,
4852
STREET: INPUT_IDS.ADDITIONAL_DATA.CORPAY.COMPANY_STREET,
4953
CITY: INPUT_IDS.ADDITIONAL_DATA.CORPAY.COMPANY_CITY,
5054
STATE: INPUT_IDS.ADDITIONAL_DATA.CORPAY.COMPANY_STATE,
@@ -65,10 +69,10 @@ const INPUT_KEYS = {
6569
function BusinessInfo({onBackButtonPress, onSubmit}: BusinessInfoProps) {
6670
const {translate} = useLocalize();
6771

68-
const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT);
69-
const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT);
72+
const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {canBeMissing: false});
73+
const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT, {canBeMissing: true});
7074
const policyID = reimbursementAccount?.achData?.policyID;
71-
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
75+
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {canBeMissing: false});
7276
const currency = policy?.outputCurrency ?? '';
7377
const businessInfoStepValues = useMemo(() => getSubStepValues(INPUT_KEYS, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]);
7478
const bankAccountID = reimbursementAccount?.achData?.bankAccountID ?? CONST.DEFAULT_NUMBER_ID;
@@ -113,6 +117,7 @@ function BusinessInfo({onBackButtonPress, onSubmit}: BusinessInfoProps) {
113117
const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo, goToTheLastStep} = useSubStep({bodyContent, startFrom, onFinished: submit});
114118

115119
const handleBackButtonPress = () => {
120+
clearErrors(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM);
116121
if (isEditing) {
117122
goToTheLastStep();
118123
return;

src/pages/ReimbursementAccount/NonUSD/BusinessInfo/subSteps/Confirmation.tsx

+22-13
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import INPUT_IDS from '@src/types/form/ReimbursementAccountForm';
1313
const BUSINESS_INFO_STEP_KEYS = INPUT_IDS.ADDITIONAL_DATA.CORPAY;
1414
const {
1515
COMPANY_NAME,
16+
COMPANY_WEBSITE,
1617
BUSINESS_REGISTRATION_INCORPORATION_NUMBER,
1718
TAX_ID_EIN_NUMBER,
1819
COMPANY_COUNTRY_CODE,
@@ -48,9 +49,9 @@ const displayIncorporationLocation = (country: string, state: string) => {
4849
function Confirmation({onNext, onMove, isEditing}: SubStepProps) {
4950
const {translate} = useLocalize();
5051

51-
const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT);
52-
const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT);
53-
const [corpayOnboardingFields] = useOnyx(ONYXKEYS.CORPAY_ONBOARDING_FIELDS);
52+
const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {canBeMissing: false});
53+
const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT, {canBeMissing: false});
54+
const [corpayOnboardingFields] = useOnyx(ONYXKEYS.CORPAY_ONBOARDING_FIELDS, {canBeMissing: false});
5455
const error = getLatestErrorMessage(reimbursementAccount);
5556

5657
const values = useMemo(() => getSubStepValues(BUSINESS_INFO_STEP_KEYS, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]);
@@ -82,84 +83,92 @@ function Confirmation({onNext, onMove, isEditing}: SubStepProps) {
8283
onMove(0);
8384
},
8485
},
86+
{
87+
title: values[COMPANY_WEBSITE],
88+
description: translate('businessInfoStep.companyWebsite'),
89+
shouldShowRightIcon: true,
90+
onPress: () => {
91+
onMove(1);
92+
},
93+
},
8594
{
8695
title: values[BUSINESS_REGISTRATION_INCORPORATION_NUMBER],
8796
description: translate('businessInfoStep.registrationNumber'),
8897
shouldShowRightIcon: true,
8998
onPress: () => {
90-
onMove(3);
99+
onMove(4);
91100
},
92101
},
93102
{
94103
title: values[TAX_ID_EIN_NUMBER],
95104
description: translate('businessInfoStep.taxIDEIN'),
96105
shouldShowRightIcon: true,
97106
onPress: () => {
98-
onMove(4);
107+
onMove(5);
99108
},
100109
},
101110
{
102111
title: displayAddress(values[COMPANY_STREET], values[COMPANY_CITY], values[COMPANY_STATE], values[COMPANY_POSTAL_CODE], values[COMPANY_COUNTRY_CODE]),
103112
description: translate('businessInfoStep.businessAddress'),
104113
shouldShowRightIcon: true,
105114
onPress: () => {
106-
onMove(1);
115+
onMove(2);
107116
},
108117
},
109118
{
110119
title: values[BUSINESS_CONTACT_NUMBER],
111120
description: translate('common.phoneNumber'),
112121
shouldShowRightIcon: true,
113122
onPress: () => {
114-
onMove(2);
123+
onMove(3);
115124
},
116125
},
117126
{
118127
title: values[BUSINESS_CONFIRMATION_EMAIL],
119128
description: translate('common.email'),
120129
shouldShowRightIcon: true,
121130
onPress: () => {
122-
onMove(2);
131+
onMove(3);
123132
},
124133
},
125134
{
126135
title: businessType,
127136
description: translate('businessInfoStep.businessType'),
128137
shouldShowRightIcon: true,
129138
onPress: () => {
130-
onMove(6);
139+
onMove(7);
131140
},
132141
},
133142
{
134143
title: displayIncorporationLocation(values[FORMATION_INCORPORATION_COUNTRY_CODE], values[FORMATION_INCORPORATION_STATE]),
135144
description: translate('businessInfoStep.incorporation'),
136145
shouldShowRightIcon: true,
137146
onPress: () => {
138-
onMove(5);
147+
onMove(6);
139148
},
140149
},
141150
{
142151
title: businessCategory,
143152
description: translate('businessInfoStep.businessCategory'),
144153
shouldShowRightIcon: true,
145154
onPress: () => {
146-
onMove(6);
155+
onMove(7);
147156
},
148157
},
149158
{
150159
title: paymentVolume,
151160
description: translate('businessInfoStep.annualPaymentVolume'),
152161
shouldShowRightIcon: true,
153162
onPress: () => {
154-
onMove(7);
163+
onMove(8);
155164
},
156165
},
157166
{
158167
title: tradeVolumeRange,
159168
description: translate('businessInfoStep.averageReimbursementAmount'),
160169
shouldShowRightIcon: true,
161170
onPress: () => {
162-
onMove(8);
171+
onMove(9);
163172
},
164173
},
165174
],

0 commit comments

Comments
 (0)