Skip to content

Commit 8390f03

Browse files
authored
Merge pull request #88193 from callstack-internal/refactor/79048-restore-reverted-usd-flow
feat: 79048 restore reverted usd flow
2 parents 4ce9da3 + 0d25bc5 commit 8390f03

58 files changed

Lines changed: 839 additions & 500 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/CONST/index.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,65 @@ const CONST = {
627627
VALIDATION: 'ValidationStep',
628628
ENABLE: 'EnableStep',
629629
},
630+
PAGE_NAMES: {
631+
COUNTRY: 'currency-and-country',
632+
BANK_ACCOUNT: 'bank-info',
633+
REQUESTOR: 'personal-info',
634+
VERIFY_IDENTITY: 'verify-identity',
635+
COMPANY: 'company',
636+
BENEFICIAL_OWNERS: 'business-owner',
637+
ACH_CONTRACT: 'ach-contract',
638+
VALIDATION: 'validation',
639+
ENABLE: 'enable',
640+
},
630641
STEP_NAMES: ['1', '2', '3', '4', '5', '6'],
642+
BANK_INFO_STEP: {
643+
SUB_PAGE_NAMES: {
644+
MANUAL: 'manual',
645+
PLAID: 'plaid',
646+
},
647+
},
648+
PERSONAL_INFO_STEP: {
649+
SUB_PAGE_NAMES: {
650+
FULL_NAME: 'full-name',
651+
DATE_OF_BIRTH: 'date-of-birth',
652+
SSN: 'ssn',
653+
ADDRESS: 'address',
654+
CONFIRMATION: 'confirmation',
655+
},
656+
},
657+
BUSINESS_INFO_STEP: {
658+
SUB_PAGE_NAMES: {
659+
NAME: 'name',
660+
TAX_ID: 'tax-id',
661+
WEBSITE: 'website',
662+
PHONE: 'phone',
663+
ADDRESS: 'address',
664+
TYPE: 'type',
665+
INCORPORATION_DATE: 'start-date',
666+
INCORPORATION_STATE: 'state',
667+
INCORPORATION_CODE: 'code',
668+
CONFIRMATION: 'confirmation',
669+
},
670+
},
671+
BENEFICIAL_OWNERS_STEP: {
672+
SUB_PAGE_NAMES: {
673+
IS_USER_UBO: 'is-user-ubo',
674+
IS_ANYONE_ELSE_UBO: 'is-anyone-else-ubo',
675+
ARE_THERE_MORE_UBOS: 'are-there-more-ubos',
676+
UBOS_LIST: 'ubos-list',
677+
LEGAL_NAME: 'legal-name',
678+
DATE_OF_BIRTH: 'date-of-birth',
679+
SSN: 'ssn',
680+
ADDRESS: 'address',
681+
CONFIRMATION: 'confirmation',
682+
},
683+
},
684+
COMPLETE_VERIFICATION_STEP: {
685+
SUB_PAGE_NAMES: {
686+
CONFIRM_AGREEMENTS: 'confirm-agreements',
687+
},
688+
},
631689
SUBSTEP: {
632690
MANUAL: 'manual',
633691
PLAID: 'plaid',

src/ROUTES.ts

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import type {ReplacementReason} from './libs/actions/Card';
1414
import type {IOURequestType} from './libs/actions/IOU';
1515
import Log from './libs/Log';
1616
import type {RootNavigatorParamList} from './libs/Navigation/types';
17-
import type {ReimbursementAccountStepToOpen} from './libs/ReimbursementAccountUtils';
1817
import StringUtils from './libs/StringUtils';
1918
import {getUrlWithParams} from './libs/Url';
2019
import SCREENS from './SCREENS';
@@ -622,36 +621,24 @@ const ROUTES = {
622621
// eslint-disable-next-line no-restricted-syntax -- Legacy route generation
623622
getRoute: (policyID?: string, backTo?: string) => getUrlWithBackToParam(`bank-account/${VERIFY_ACCOUNT}?policyID=${policyID}`, backTo),
624623
},
625-
BANK_ACCOUNT_NEW: 'bank-account/new',
626624
BANK_ACCOUNT_PERSONAL: 'bank-account/personal',
625+
// TODO: rename the route as no longer accepts step
627626
BANK_ACCOUNT_WITH_STEP_TO_OPEN: {
628-
route: 'bank-account/:stepToOpen?',
629-
getRoute: ({
630-
policyID,
631-
stepToOpen = '',
632-
bankAccountID,
633-
backTo,
634-
subStepToOpen,
635-
}: {
636-
policyID: string | undefined;
637-
stepToOpen?: ReimbursementAccountStepToOpen;
638-
bankAccountID?: number;
639-
backTo?: string;
640-
subStepToOpen?: typeof CONST.BANK_ACCOUNT.STEP.COUNTRY;
641-
}) => {
627+
route: 'bank-account/new',
628+
getRoute: ({policyID, bankAccountID, backTo}: {policyID: string | undefined; bankAccountID?: number; backTo?: string}) => {
642629
if (!policyID && !bankAccountID) {
643630
// eslint-disable-next-line no-restricted-syntax -- Legacy route generation
644-
return getUrlWithBackToParam(`bank-account/${stepToOpen}`, backTo);
631+
return getUrlWithBackToParam(`bank-account/new`, backTo);
645632
}
646633

647634
if (bankAccountID) {
648635
// eslint-disable-next-line no-restricted-syntax -- Legacy route generation
649-
return getUrlWithBackToParam(`bank-account/${stepToOpen}?bankAccountID=${bankAccountID}`, backTo);
636+
return getUrlWithBackToParam(`bank-account/new?bankAccountID=${bankAccountID}`, backTo);
650637
}
651638
// TODO this backTo comes from drilling it through bank account form screens
652639
// should be removed once https://github.com/Expensify/App/pull/72219 is resolved
653640
// eslint-disable-next-line no-restricted-syntax -- Legacy route generation
654-
return getUrlWithBackToParam(`bank-account/${stepToOpen}?policyID=${policyID}${subStepToOpen ? `&subStep=${subStepToOpen}` : ''}`, backTo);
641+
return getUrlWithBackToParam(`bank-account/new?policyID=${policyID}`, backTo);
655642
},
656643
},
657644
BANK_ACCOUNT_ENTER_SIGNER_INFO: {
@@ -683,6 +670,18 @@ const ROUTES = {
683670
return getUrlWithBackToParam(`${base}${pagePart}${subPagePart}${actionPart}${queryString}`, backTo);
684671
},
685672
},
673+
BANK_ACCOUNT_USD_SETUP: {
674+
route: 'bank-account/new/us/:page?/:subPage?/:action?',
675+
getRoute: ({policyID, page, subPage, action, backTo}: {policyID?: string; page?: string; subPage?: string; action?: 'edit'; backTo?: string}) => {
676+
const base = 'bank-account/new/us';
677+
const pagePart = page ? `/${page}` : '';
678+
const subPagePart = subPage ? `/${subPage}` : '';
679+
const actionPart = action ? `/${action}` : '';
680+
const queryString = policyID ? `?policyID=${policyID}` : '';
681+
// eslint-disable-next-line no-restricted-syntax -- Legacy route generation
682+
return getUrlWithBackToParam(`${base}${pagePart}${subPagePart}${actionPart}${queryString}`, backTo);
683+
},
684+
},
686685
SETTINGS: 'settings',
687686
SETTINGS_PROFILE: {
688687
route: 'settings/profile',

src/SCREENS.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,7 @@ const SCREENS = {
959959
},
960960
DYNAMIC_FLAG_COMMENT: 'Dynamic_Flag_Comment',
961961
REIMBURSEMENT_ACCOUNT: 'ReimbursementAccount',
962+
REIMBURSEMENT_ACCOUNT_USD: 'Reimbursement_Account_USD',
962963
REIMBURSEMENT_ACCOUNT_NON_USD: 'Reimbursement_Account_Non_USD',
963964
REIMBURSEMENT_ACCOUNT_ENTER_SIGNER_INFO: 'Reimbursement_Account_Signer_Info',
964965
REFERRAL_DETAILS: 'Referral_Details',

src/components/Navigation/DebugTabView.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import useStyleUtils from '@hooks/useStyleUtils';
1515
import useTheme from '@hooks/useTheme';
1616
import useThemeStyles from '@hooks/useThemeStyles';
1717
import Navigation from '@libs/Navigation/Navigation';
18-
import {getRouteForCurrentStep as getReimbursementAccountRouteForCurrentStep} from '@libs/ReimbursementAccountUtils';
1918
import type {BrickRoad} from '@libs/WorkspacesSettingsUtils';
2019
import {getChatTabBrickRoadReportID} from '@libs/WorkspacesSettingsUtils';
2120
import CONST from '@src/CONST';
@@ -82,10 +81,7 @@ function getSettingsRoute(status: IndicatorStatus | undefined, reimbursementAcco
8281
case CONST.INDICATOR_STATUS.HAS_POLICY_ERRORS:
8382
return ROUTES.WORKSPACE_INITIAL.getRoute(policyIDWithErrors);
8483
case CONST.INDICATOR_STATUS.HAS_REIMBURSEMENT_ACCOUNT_ERRORS:
85-
return ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute({
86-
policyID: reimbursementAccount?.achData?.policyID,
87-
stepToOpen: getReimbursementAccountRouteForCurrentStep(reimbursementAccount?.achData?.currentStep ?? CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT),
88-
});
84+
return ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute({policyID: reimbursementAccount?.achData?.policyID});
8985
case CONST.INDICATOR_STATUS.HAS_SUBSCRIPTION_ERRORS:
9086
return ROUTES.SETTINGS_SUBSCRIPTION.route;
9187
case CONST.INDICATOR_STATUS.HAS_SUBSCRIPTION_INFO:
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {useCallback, useEffect, useRef} from 'react';
2+
import ONYXKEYS from '@src/ONYXKEYS';
3+
import useOnyx from './useOnyx';
4+
5+
/**
6+
* Defers navigation (onSubmit) until the reimbursement account API call completes.
7+
* Instead of navigating to the next step immediately after firing the API call,
8+
* this hook waits for `isLoading` to go back to `false` and checks for errors.
9+
*
10+
* @param onSubmit - callback that navigates to the next step
11+
* @returns markSubmitting - call this right after firing the API action
12+
*/
13+
export default function useReimbursementAccountSubmitCallback(onSubmit?: () => void) {
14+
const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT);
15+
const isSubmittingRef = useRef(false);
16+
17+
useEffect(() => {
18+
if (!isSubmittingRef.current || reimbursementAccount?.isLoading || reimbursementAccount?.errors) {
19+
return;
20+
}
21+
isSubmittingRef.current = false;
22+
onSubmit?.();
23+
}, [reimbursementAccount?.isLoading, reimbursementAccount?.errors, onSubmit]);
24+
25+
return useCallback(() => {
26+
isSubmittingRef.current = true;
27+
}, []);
28+
}

src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React, {useCallback} from 'react';
33
import {View} from 'react-native';
44
import useResponsiveLayout from '@hooks/useResponsiveLayout';
55
import useThemeStyles from '@hooks/useThemeStyles';
6+
import {isMobileChrome} from '@libs/Browser';
67
import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
78
import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation';
89
import type {PlatformStackNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
@@ -61,6 +62,17 @@ const loadAttachmentModalScreen = () => require<ReactComponentModule>('../../../
6162

6263
type Screens = Partial<Record<Screen, () => React.ComponentType>>;
6364

65+
// Reimbursement Account flow animations glitch on low-end Android devices in Chrome mWeb https://github.com/Expensify/App/issues/87658 so we intentionally disable them
66+
const IS_MOBILE_CHROME = isMobileChrome();
67+
68+
const REIMBURSEMENT_ACCOUNT_FLOW_SCREENS: Screen[] = [
69+
SCREENS.REIMBURSEMENT_ACCOUNT,
70+
SCREENS.REIMBURSEMENT_ACCOUNT_USD,
71+
SCREENS.REIMBURSEMENT_ACCOUNT_NON_USD,
72+
SCREENS.REIMBURSEMENT_ACCOUNT_VERIFY_ACCOUNT,
73+
SCREENS.REIMBURSEMENT_ACCOUNT_ENTER_SIGNER_INFO,
74+
];
75+
6476
const OPTIONS_PER_SCREEN: Partial<Record<Screen, PlatformStackNavigationOptions>> = {
6577
[SCREENS.SETTINGS.MERGE_ACCOUNTS.MERGE_RESULT]: {
6678
animationTypeForReplace: 'push',
@@ -113,6 +125,7 @@ const OPTIONS_PER_SCREEN: Partial<Record<Screen, PlatformStackNavigationOptions>
113125
[SCREENS.WORKSPACE.DYNAMIC_CATEGORIES_IMPORTED]: {
114126
animationTypeForReplace: 'push',
115127
},
128+
...(IS_MOBILE_CHROME ? Object.fromEntries(REIMBURSEMENT_ACCOUNT_FLOW_SCREENS.map((screen) => [screen, {animation: Animations.NONE}])) : {}),
116129
};
117130

118131
/**
@@ -662,6 +675,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
662675
[SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_ITEMS]: () => require<ReactComponentModule>('../../../../pages/workspace/accounting/qbd/import/QuickbooksDesktopItemsPage').default,
663676
[SCREENS.CONNECT_EXISTING_BUSINESS_BANK_ACCOUNT_ROOT]: () => require<ReactComponentModule>('@pages/workspace/ConnectExistingBusinessBankAccountPage').default,
664677
[SCREENS.REIMBURSEMENT_ACCOUNT]: () => require<ReactComponentModule>('../../../../pages/ReimbursementAccount/ReimbursementAccountPage').default,
678+
[SCREENS.REIMBURSEMENT_ACCOUNT_USD]: () => require<ReactComponentModule>('../../../../pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage').default,
665679
[SCREENS.REIMBURSEMENT_ACCOUNT_NON_USD]: () => require<ReactComponentModule>('../../../../pages/ReimbursementAccount/NonUSD/NonUSDVerifiedBankAccountFlowPage').default,
666680
[SCREENS.REIMBURSEMENT_ACCOUNT_VERIFY_ACCOUNT]: () => require<ReactComponentModule>('../../../../pages/ReimbursementAccount/ReimbursementAccountVerifyAccountPage').default,
667681
[SCREENS.REIMBURSEMENT_ACCOUNT_ENTER_SIGNER_INFO]: () => require<ReactComponentModule>('../../../../pages/ReimbursementAccount/EnterSignerInfo').default,

src/libs/Navigation/linkingConfig/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,6 +1173,10 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
11731173
path: ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.route,
11741174
exact: true,
11751175
},
1176+
[SCREENS.REIMBURSEMENT_ACCOUNT_USD]: {
1177+
path: ROUTES.BANK_ACCOUNT_USD_SETUP.route,
1178+
exact: true,
1179+
},
11761180
[SCREENS.REIMBURSEMENT_ACCOUNT_NON_USD]: {
11771181
path: ROUTES.BANK_ACCOUNT_NON_USD_SETUP.route,
11781182
exact: true,

src/libs/Navigation/types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,6 +2307,14 @@ type ReimbursementAccountNavigatorParamList = {
23072307
bankAccountID?: string;
23082308
subStep?: typeof CONST.BANK_ACCOUNT.STEP.COUNTRY;
23092309
};
2310+
[SCREENS.REIMBURSEMENT_ACCOUNT_USD]: {
2311+
page?: string;
2312+
subPage?: string;
2313+
action?: 'edit';
2314+
policyID?: string;
2315+
// eslint-disable-next-line no-restricted-syntax -- backTo is a temporary param will be removed after https://github.com/Expensify/App/issues/73825 is done
2316+
backTo?: Routes;
2317+
};
23102318
[SCREENS.REIMBURSEMENT_ACCOUNT_NON_USD]: {
23112319
page?: string;
23122320
subPage?: string;

src/libs/ReimbursementAccountUtils.ts

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type {ValueOf} from 'type-fest';
22
import CONST from '@src/CONST';
3-
import type {ACHDataReimbursementAccount, ReimbursementAccountStep} from '@src/types/onyx/ReimbursementAccount';
3+
import type {ACHDataReimbursementAccount} from '@src/types/onyx/ReimbursementAccount';
44

55
type ReimbursementAccountStepToOpen = ValueOf<typeof REIMBURSEMENT_ACCOUNT_ROUTE_NAMES> | '';
66

@@ -14,27 +14,6 @@ const REIMBURSEMENT_ACCOUNT_ROUTE_NAMES = {
1414
NEW: 'new',
1515
} as const;
1616

17-
function getRouteForCurrentStep(currentStep: ReimbursementAccountStep): ReimbursementAccountStepToOpen {
18-
switch (currentStep) {
19-
case CONST.BANK_ACCOUNT.STEP.COMPANY:
20-
return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.COMPANY;
21-
case CONST.BANK_ACCOUNT.STEP.REQUESTOR:
22-
return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.PERSONAL_INFORMATION;
23-
case CONST.BANK_ACCOUNT.STEP.BENEFICIAL_OWNERS:
24-
return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.BENEFICIAL_OWNERS;
25-
case CONST.BANK_ACCOUNT.STEP.ACH_CONTRACT:
26-
return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.CONTRACT;
27-
case CONST.BANK_ACCOUNT.STEP.VALIDATION:
28-
return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.VALIDATE;
29-
case CONST.BANK_ACCOUNT.STEP.ENABLE:
30-
return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.ENABLE;
31-
case CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT:
32-
case CONST.BANK_ACCOUNT.STEP.COUNTRY:
33-
default:
34-
return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.NEW;
35-
}
36-
}
37-
3817
/**
3918
* Returns true if a VBBA exists in any state other than OPEN or LOCKED
4019
*/
@@ -67,5 +46,5 @@ const hasInProgressVBBA = (achData?: ACHDataReimbursementAccount, isNonUSDWorksp
6746
return hasInProgressUSDVBBA(achData);
6847
};
6948

70-
export {getBankAccountIDAsNumber, getRouteForCurrentStep, hasInProgressUSDVBBA, hasInProgressVBBA, REIMBURSEMENT_ACCOUNT_ROUTE_NAMES};
49+
export {getBankAccountIDAsNumber, hasInProgressUSDVBBA, hasInProgressVBBA, REIMBURSEMENT_ACCOUNT_ROUTE_NAMES};
7150
export type {ReimbursementAccountStepToOpen};

src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ type ConnectedVerifiedBankAccountProps = {
2727
onBackButtonPress: () => void;
2828

2929
/** Method to set the state of shouldShowConnectedVerifiedBankAccount */
30-
setShouldShowConnectedVerifiedBankAccount: (shouldShowConnectedVerifiedBankAccount: boolean) => void;
30+
setShouldShowConnectedVerifiedBankAccount?: (shouldShowConnectedVerifiedBankAccount: boolean) => void;
3131

3232
/** Method to set the state of USD bank account step */
33-
setUSDBankAccountStep: (step: string | null) => void;
33+
setUSDBankAccountStep?: (step: string | null) => void;
3434

3535
/** Whether the workspace currency is set to non USD currency */
3636
isNonUSDWorkspace: boolean;

0 commit comments

Comments
 (0)