From 87ab0950e5ebe8420bc938fa0bc28e7d1a0b4c5d Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 24 Mar 2026 12:08:41 +0100 Subject: [PATCH 01/20] feat: create new route and add to config --- src/ROUTES.ts | 12 +++ src/SCREENS.ts | 1 + .../ModalStackNavigators/index.tsx | 4 + src/libs/Navigation/linkingConfig/config.ts | 4 + src/libs/Navigation/types.ts | 7 ++ .../USD/USDVerifiedBankAccountFlowPage.tsx | 99 +++++++++++++++++++ 6 files changed, 127 insertions(+) create mode 100644 src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 952a920d1f6e0..727cbdf24d893 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -312,6 +312,18 @@ const ROUTES = { route: 'bank-account/connect-existing-business-bank-account', getRoute: (policyID: string) => `bank-account/connect-existing-business-bank-account?policyID=${policyID}` as const, }, + BANK_ACCOUNT_USD_SETUP: { + route: 'bank-account/us/:step?/:subStep?', + // eslint-disable-next-line no-restricted-syntax -- Legacy route generation + getRoute: ({policyID, step, subStep, backTo}: {policyID?: string; step?: string; subStep?: string; backTo?: string}) => { + const base = 'bank-account/us'; + const stepPart = step ? `/${step}` : ''; + const subStepPart = subStep ? `/${subStep}` : ''; + const queryString = policyID ? `?policyID=${policyID}` : ''; + // eslint-disable-next-line no-restricted-syntax -- Legacy route generation + return getUrlWithBackToParam(`${base}${stepPart}${subStepPart}${queryString}`, backTo); + }, + }, SETTINGS: 'settings', SETTINGS_PROFILE: { route: 'settings/profile', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 51fffec8051df..2802247971a56 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -899,6 +899,7 @@ const SCREENS = { }, FLAG_COMMENT_ROOT: 'FlagComment_Root', REIMBURSEMENT_ACCOUNT: 'ReimbursementAccount', + REIMBURSEMENT_ACCOUNT_USD: 'Reimbursement_Account_USD', REIMBURSEMENT_ACCOUNT_ENTER_SIGNER_INFO: 'Reimbursement_Account_Signer_Info', REFERRAL_DETAILS: 'Referral_Details', REPORT_VERIFY_ACCOUNT: 'Report_Verify_Account', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 69427c1a1949d..bf008b3dc6cb0 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -109,6 +109,9 @@ const OPTIONS_PER_SCREEN: Partial [SCREENS.MULTIFACTOR_AUTHENTICATION.NOT_FOUND]: { animationTypeForReplace: 'push', }, + [SCREENS.REIMBURSEMENT_ACCOUNT_USD]: { + animationTypeForReplace: 'pop', + }, }; /** @@ -625,6 +628,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/accounting/qbd/import/QuickbooksDesktopItemsPage').default, [SCREENS.CONNECT_EXISTING_BUSINESS_BANK_ACCOUNT_ROOT]: () => require('@pages/workspace/ConnectExistingBusinessBankAccountPage').default, [SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../../pages/ReimbursementAccount/ReimbursementAccountPage').default, + [SCREENS.REIMBURSEMENT_ACCOUNT_USD]: () => require('../../../../pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage').default, [SCREENS.REIMBURSEMENT_ACCOUNT_VERIFY_ACCOUNT]: () => require('../../../../pages/ReimbursementAccount/ReimbursementAccountVerifyAccountPage').default, [SCREENS.REIMBURSEMENT_ACCOUNT_ENTER_SIGNER_INFO]: () => require('../../../../pages/ReimbursementAccount/EnterSignerInfo').default, [SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED]: () => require('../../../../pages/settings/Wallet/ReportCardLostPage').default, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 1e28d24ef4edd..c75b25eb109c0 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1155,6 +1155,10 @@ const config: LinkingOptions['config'] = { path: ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.route, exact: true, }, + [SCREENS.REIMBURSEMENT_ACCOUNT_USD]: { + path: ROUTES.BANK_ACCOUNT_USD_SETUP.route, + exact: true, + }, [SCREENS.REIMBURSEMENT_ACCOUNT_VERIFY_ACCOUNT]: { path: ROUTES.BANK_ACCOUNT_VERIFY_ACCOUNT.route, exact: true, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index d9447e03d14d9..cc651c9ed2f43 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -2243,6 +2243,13 @@ type ReimbursementAccountNavigatorParamList = { bankAccountID?: string; subStep?: typeof CONST.BANK_ACCOUNT.STEP.COUNTRY; }; + [SCREENS.REIMBURSEMENT_ACCOUNT_USD]: { + step?: string; + subStep?: string; + policyID?: string; + // 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 + backTo?: Routes; + }; [SCREENS.REIMBURSEMENT_ACCOUNT_VERIFY_ACCOUNT]: { // TODO this backTo comes from drilling it through bank account form screens // should be removed once https://github.com/Expensify/App/pull/72219 is resolved diff --git a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx new file mode 100644 index 0000000000000..c86356f1f4bde --- /dev/null +++ b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx @@ -0,0 +1,99 @@ +import React, {useCallback, useMemo, useRef} from 'react'; +import {View} from 'react-native'; +import useOnyx from '@hooks/useOnyx'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; +import type {ReimbursementAccountNavigatorParamList} from '@libs/Navigation/types'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; +import BankInfo from './BankInfo/BankInfo'; +import BeneficialOwnersStep from './BeneficialOwnerInfo/BeneficialOwnersStep'; +import BusinessInfo from './BusinessInfo/BusinessInfo'; +import CompleteVerification from './CompleteVerification/CompleteVerification'; +import ConnectBankAccount from './ConnectBankAccount/ConnectBankAccount'; +import Country from './Country'; +import RequestorStep from './Requestor/RequestorStep'; +import type USDPageProps from './types'; + +const STEP = CONST.BANK_ACCOUNT.STEP; + +type PageEntry = { + pageName: string; + component: React.ComponentType; +}; + +const pages: PageEntry[] = [ + {pageName: STEP.COUNTRY, component: Country as React.ComponentType}, + {pageName: STEP.BANK_ACCOUNT, component: BankInfo as React.ComponentType}, + {pageName: STEP.REQUESTOR, component: RequestorStep as React.ComponentType}, + {pageName: STEP.COMPANY, component: BusinessInfo as React.ComponentType}, + {pageName: STEP.BENEFICIAL_OWNERS, component: BeneficialOwnersStep as React.ComponentType}, + {pageName: STEP.ACH_CONTRACT, component: CompleteVerification as React.ComponentType}, + {pageName: STEP.VALIDATION, component: ConnectBankAccount as React.ComponentType}, +]; + +type USDVerifiedBankAccountFlowPageProps = PlatformStackScreenProps; + +function USDVerifiedBankAccountFlowPage({route}: USDVerifiedBankAccountFlowPageProps) { + const styles = useThemeStyles(); + const policyID = route.params?.policyID; + const currentStep = route.params?.step; + const currentSubPage = route.params?.subStep; + + const [onfidoToken = ''] = useOnyx(ONYXKEYS.ONFIDO_TOKEN); + const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); + + const requestorStepRef = useRef(null); + + const currentPageIndex = useMemo(() => { + const index = pages.findIndex((p) => p.pageName === currentStep); + return index >= 0 ? index : 0; + }, [currentStep]); + + const currentEntry = pages.at(currentPageIndex); + const CurrentPage = currentEntry?.component ?? (Country as React.ComponentType); + + const onSubmit = useCallback(() => { + const nextIndex = currentPageIndex + 1; + if (nextIndex >= pages.length) { + Navigation.goBack(); + return; + } + const nextPage = pages.at(nextIndex); + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: nextPage?.pageName})); + }, [currentPageIndex, policyID]); + + const onBackButtonPress = useCallback(() => { + const prevIndex = currentPageIndex - 1; + if (prevIndex < 0) { + Navigation.goBack(); + return; + } + const prevPage = pages.at(prevIndex); + Navigation.goBack(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: prevPage?.pageName})); + }, [currentPageIndex, policyID]); + + const shouldShowOnfido = !!(onfidoToken && !reimbursementAccount?.achData?.isOnfidoSetupComplete); + const isRequestorStep = currentEntry?.pageName === STEP.REQUESTOR; + + return ( + + + + ); +} + +USDVerifiedBankAccountFlowPage.displayName = 'USDVerifiedBankAccountFlowPage'; + +export default USDVerifiedBankAccountFlowPage; From cbcebe8728289cf713e8ec2e0c5206d56aa5e785 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 18 Mar 2026 11:29:37 +0100 Subject: [PATCH 02/20] fix: change page names --- src/CONST/index.ts | 10 +++++++ .../USD/USDVerifiedBankAccountFlowPage.tsx | 18 ++++++------- src/pages/ReimbursementAccount/USD/types.ts | 27 +++++++++++++++++++ 3 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 src/pages/ReimbursementAccount/USD/types.ts diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 4789213e0fff0..25cb5396aa35c 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -594,6 +594,16 @@ const CONST = { VALIDATION: 'ValidationStep', ENABLE: 'EnableStep', }, + PAGE_NAMES: { + COUNTRY: 'country', + BANK_ACCOUNT: 'bank-account', + REQUESTOR: 'requestor', + COMPANY: 'company', + BENEFICIAL_OWNERS: 'beneficial-owners', + ACH_CONTRACT: 'ach-contract', + VALIDATION: 'validation', + ENABLE: 'enable', + }, STEP_NAMES: ['1', '2', '3', '4', '5', '6'], SUBSTEP: { MANUAL: 'manual', diff --git a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx index c86356f1f4bde..5c2ba9714153a 100644 --- a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx +++ b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx @@ -18,7 +18,7 @@ import Country from './Country'; import RequestorStep from './Requestor/RequestorStep'; import type USDPageProps from './types'; -const STEP = CONST.BANK_ACCOUNT.STEP; +const PAGE_NAMES = CONST.BANK_ACCOUNT.PAGE_NAMES; type PageEntry = { pageName: string; @@ -26,13 +26,13 @@ type PageEntry = { }; const pages: PageEntry[] = [ - {pageName: STEP.COUNTRY, component: Country as React.ComponentType}, - {pageName: STEP.BANK_ACCOUNT, component: BankInfo as React.ComponentType}, - {pageName: STEP.REQUESTOR, component: RequestorStep as React.ComponentType}, - {pageName: STEP.COMPANY, component: BusinessInfo as React.ComponentType}, - {pageName: STEP.BENEFICIAL_OWNERS, component: BeneficialOwnersStep as React.ComponentType}, - {pageName: STEP.ACH_CONTRACT, component: CompleteVerification as React.ComponentType}, - {pageName: STEP.VALIDATION, component: ConnectBankAccount as React.ComponentType}, + {pageName: PAGE_NAMES.COUNTRY, component: Country as React.ComponentType}, + {pageName: PAGE_NAMES.BANK_ACCOUNT, component: BankInfo as React.ComponentType}, + {pageName: PAGE_NAMES.REQUESTOR, component: RequestorStep as React.ComponentType}, + {pageName: PAGE_NAMES.COMPANY, component: BusinessInfo as React.ComponentType}, + {pageName: PAGE_NAMES.BENEFICIAL_OWNERS, component: BeneficialOwnersStep as React.ComponentType}, + {pageName: PAGE_NAMES.ACH_CONTRACT, component: CompleteVerification as React.ComponentType}, + {pageName: PAGE_NAMES.VALIDATION, component: ConnectBankAccount as React.ComponentType}, ]; type USDVerifiedBankAccountFlowPageProps = PlatformStackScreenProps; @@ -77,7 +77,7 @@ function USDVerifiedBankAccountFlowPage({route}: USDVerifiedBankAccountFlowPageP }, [currentPageIndex, policyID]); const shouldShowOnfido = !!(onfidoToken && !reimbursementAccount?.achData?.isOnfidoSetupComplete); - const isRequestorStep = currentEntry?.pageName === STEP.REQUESTOR; + const isRequestorStep = currentEntry?.pageName === PAGE_NAMES.REQUESTOR; return ( diff --git a/src/pages/ReimbursementAccount/USD/types.ts b/src/pages/ReimbursementAccount/USD/types.ts new file mode 100644 index 0000000000000..946cc21c18857 --- /dev/null +++ b/src/pages/ReimbursementAccount/USD/types.ts @@ -0,0 +1,27 @@ +import type {ForwardedRef} from 'react'; +import type {View} from 'react-native'; + +type USDPageProps = { + /** Handles submit button press */ + onSubmit: () => void; + + /** Handles back button press */ + onBackButtonPress: () => void; + + /** ID of current policy */ + policyID?: string; + + /** Name of the current sub page */ + currentSubPage?: string; + + /** Array of step names for the progress indicator */ + stepNames?: readonly string[]; + + /** If we should show Onfido flow (used by RequestorStep) */ + shouldShowOnfido?: boolean; + + /** Reference to the outer element (used by RequestorStep) */ + ref?: ForwardedRef; +}; + +export default USDPageProps; From b9608e55406d58d8c4c06dc07a3caca896ced385 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 24 Mar 2026 12:42:48 +0100 Subject: [PATCH 03/20] feat: migrate main steps --- .../ConnectedVerifiedBankAccount.tsx | 2 +- .../ReimbursementAccountPage.tsx | 14 -------------- .../USD/BankInfo/BankInfo.tsx | 14 ++++++-------- .../USD/BankInfo/subSteps/Plaid.tsx | 10 +++------- .../BeneficialOwnerInfo/BeneficialOwnersStep.tsx | 6 +++++- .../USD/BusinessInfo/BusinessInfo.tsx | 16 +++++++++++++--- .../CompleteVerification.tsx | 8 ++++++-- .../ReimbursementAccount/USD/Country/index.tsx | 14 +++++--------- .../USD/Requestor/PersonalInfo/PersonalInfo.tsx | 16 +++++++++++++--- .../USD/Requestor/RequestorStep.tsx | 6 +++++- .../VerifiedBankAccountFlowEntryPoint.tsx | 4 ++-- 11 files changed, 59 insertions(+), 51 deletions(-) diff --git a/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx b/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx index 6d4819575eac1..3600ccf427f59 100644 --- a/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx +++ b/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx @@ -27,7 +27,7 @@ type ConnectedVerifiedBankAccountProps = { onBackButtonPress: () => void; /** Method to set the state of shouldShowConnectedVerifiedBankAccount */ - setShouldShowConnectedVerifiedBankAccount: (shouldShowConnectedVerifiedBankAccount: boolean) => void; + setShouldShowConnectedVerifiedBankAccount?: (shouldShowConnectedVerifiedBankAccount: boolean) => void; /** Method to set the state of USD bank account step */ setUSDBankAccountStep: (step: string | null) => void; diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx index dc232f9b91944..cce9871b28c56 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx @@ -576,20 +576,6 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy, navigation}: ); } - if (isNonUSDSetup && nonUSDBankAccountStep !== null && !isResettingBankAccount) { - return ( - - ); - } - if (!isNonUSDSetup && USDBankAccountStep !== null) { return ( void; + /** Handles submit button press (URL-based navigation) */ + onSubmit?: () => void; + /** Current Policy ID */ policyID: string; - - /** Set the step of the USD verified bank account flow */ - setUSDBankAccountStep: (step: string | null) => void; }; -type BankInfoSubStepProps = SubStepProps & { - setUSDBankAccountStep: (step: string | null) => void; -}; +type BankInfoSubStepProps = SubStepProps; const BANK_INFO_STEP_KEYS = INPUT_IDS.BANK_INFO_STEP; const manualSubSteps: Array> = [Manual]; const plaidSubSteps: Array> = [Plaid]; const receivedRedirectURI = getPlaidOAuthReceivedRedirectURI(); -function BankInfo({onBackButtonPress, policyID, setUSDBankAccountStep}: BankInfoProps) { +function BankInfo({onBackButtonPress, onSubmit, policyID}: BankInfoProps) { const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); const [plaidLinkToken] = useOnyx(ONYXKEYS.PLAID_LINK_TOKEN); @@ -84,6 +82,7 @@ function BankInfo({onBackButtonPress, policyID, setUSDBankAccountStep}: BankInfo policyID, ); } + onSubmit?.(); }; const bodyContent = setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID ? plaidSubSteps : manualSubSteps; @@ -124,7 +123,6 @@ function BankInfo({onBackButtonPress, policyID, setUSDBankAccountStep}: BankInfo isEditing={isEditing} onNext={nextScreen} onMove={moveTo} - setUSDBankAccountStep={setUSDBankAccountStep} /> ); diff --git a/src/pages/ReimbursementAccount/USD/BankInfo/subSteps/Plaid.tsx b/src/pages/ReimbursementAccount/USD/BankInfo/subSteps/Plaid.tsx index 0259a336648f1..2ff34d9ac3840 100644 --- a/src/pages/ReimbursementAccount/USD/BankInfo/subSteps/Plaid.tsx +++ b/src/pages/ReimbursementAccount/USD/BankInfo/subSteps/Plaid.tsx @@ -14,13 +14,11 @@ import {updateReimbursementAccountDraft} from '@userActions/ReimbursementAccount import ONYXKEYS from '@src/ONYXKEYS'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; -type PlaidProps = SubStepProps & { - setUSDBankAccountStep: (step: string | null) => void; -}; +type PlaidProps = SubStepProps; const BANK_INFO_STEP_KEYS = INPUT_IDS.BANK_INFO_STEP; -function Plaid({onNext, setUSDBankAccountStep}: PlaidProps) { +function Plaid({onNext}: PlaidProps) { const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); const [plaidData] = useOnyx(ONYXKEYS.PLAID_DATA); @@ -61,12 +59,10 @@ function Plaid({onNext, setUSDBankAccountStep}: PlaidProps) { return; } setBankAccountSubStep(null); - setUSDBankAccountStep(null); - }, [isFocused, prevIsFocused, plaidData?.bankAccounts, setUSDBankAccountStep]); + }, [isFocused, prevIsFocused, plaidData?.bankAccounts]); const handlePlaidExit = () => { setBankAccountSubStep(null); - setUSDBankAccountStep(null); }; return ( diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx index 48e31dd63b53c..a81b2a4ef941f 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx @@ -23,6 +23,9 @@ import CompanyOwnersListUBO from './subSteps/CompanyOwnersListUBO'; type BeneficialOwnersStepProps = { /** Goes to the previous step */ onBackButtonPress: () => void; + + /** Handles submit button press (URL-based navigation) */ + onSubmit?: () => void; }; type BeneficialOwnerSubStepProps = SubStepProps & {beneficialOwnerBeingModifiedID: string; setBeneficialOwnerBeingModifiedID?: (id: string) => void}; @@ -31,7 +34,7 @@ const SUBSTEP = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.SUBSTEP; const MAX_NUMBER_OF_UBOS = 4; const bodyContent: Array> = [LegalNameUBO, DateOfBirthUBO, SocialSecurityNumberUBO, AddressUBO, ConfirmationUBO]; -function BeneficialOwnersStep({onBackButtonPress}: BeneficialOwnersStepProps) { +function BeneficialOwnersStep({onBackButtonPress, onSubmit}: BeneficialOwnersStepProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -78,6 +81,7 @@ function BeneficialOwnersStep({onBackButtonPress}: BeneficialOwnersStepProps) { }, policyID, ); + onSubmit?.(); }; const addBeneficialOwner = (beneficialOwnerID: string) => { diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx index 0eb937a1050c4..7564be711e1f1 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx @@ -29,6 +29,9 @@ import WebsiteBusiness from './subSteps/WebsiteBusiness'; type BusinessInfoProps = { /** Goes to the previous step */ onBackButtonPress: () => void; + + /** Handles submit button press (URL-based navigation) */ + onSubmit?: () => void; }; const BUSINESS_INFO_STEP_KEYS = INPUT_IDS.BUSINESS_INFO_STEP; @@ -46,7 +49,7 @@ const bodyContent: Array> = [ ConfirmationBusiness, ]; -function BusinessInfo({onBackButtonPress}: BusinessInfoProps) { +function BusinessInfo({onBackButtonPress, onSubmit}: BusinessInfoProps) { const {translate} = useLocalize(); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); @@ -93,8 +96,15 @@ function BusinessInfo({onBackButtonPress}: BusinessInfoProps) { prevScreen, moveTo, goToTheLastStep, - // eslint-disable-next-line @typescript-eslint/no-deprecated - } = useSubStep({bodyContent, startFrom, onFinished: () => submit(true), onNextSubStep: () => submit(false)}); + } = useSubStep({ + bodyContent, + startFrom, + onFinished: () => { + submit(true); + onSubmit?.(); + }, + onNextSubStep: () => submit(false), + }); const handleBackButtonPress = () => { if (isEditing) { diff --git a/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx b/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx index 5d544521ba211..806f03df9e544 100644 --- a/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx +++ b/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx @@ -16,12 +16,15 @@ import ConfirmAgreements from './subSteps/ConfirmAgreements'; type CompleteVerificationProps = { /** Handles back button press */ onBackButtonPress: () => void; + + /** Handles submit button press (URL-based navigation) */ + onSubmit?: () => void; }; const COMPLETE_VERIFICATION_KEYS = INPUT_IDS.COMPLETE_VERIFICATION; const bodyContent: Array> = [ConfirmAgreements]; -function CompleteVerification({onBackButtonPress}: CompleteVerificationProps) { +function CompleteVerification({onBackButtonPress, onSubmit}: CompleteVerificationProps) { const {translate} = useLocalize(); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); @@ -43,7 +46,8 @@ function CompleteVerification({onBackButtonPress}: CompleteVerificationProps) { policyID, policyID ? lastPaymentMethod?.[policyID] : undefined, ); - }, [bankAccountID, values.isAuthorizedToUseBankAccount, values.certifyTrueInformation, values.acceptTermsAndConditions, policyID, lastPaymentMethod]); + onSubmit?.(); + }, [bankAccountID, values.isAuthorizedToUseBankAccount, values.certifyTrueInformation, values.acceptTermsAndConditions, policyID, lastPaymentMethod, onSubmit]); // eslint-disable-next-line @typescript-eslint/no-deprecated const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo, goToTheLastStep} = useSubStep({bodyContent, startFrom: 0, onFinished: submit}); diff --git a/src/pages/ReimbursementAccount/USD/Country/index.tsx b/src/pages/ReimbursementAccount/USD/Country/index.tsx index b4a28c913745d..ded09899c388f 100644 --- a/src/pages/ReimbursementAccount/USD/Country/index.tsx +++ b/src/pages/ReimbursementAccount/USD/Country/index.tsx @@ -7,24 +7,20 @@ type CountryProps = { /** Handles back button press */ onBackButtonPress: () => void; + /** Handles submit button press (URL-based navigation) */ + onSubmit?: () => void; + /** Array of step names */ stepNames: readonly string[]; - /** Method to set the state of setUSDBankAccountStep */ - setUSDBankAccountStep?: (step: string | null) => void; - /** ID of current policy */ policyID: string | undefined; }; -function Country({onBackButtonPress, stepNames, setUSDBankAccountStep, policyID}: CountryProps) { +function Country({onBackButtonPress, onSubmit, stepNames, policyID}: CountryProps) { const submit = () => { - if (!setUSDBankAccountStep) { - return; - } - - setUSDBankAccountStep(CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT); goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT); + onSubmit?.(); }; return ( diff --git a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx index 378d04406214a..2f42ebe194645 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx @@ -23,6 +23,9 @@ type PersonalInfoProps = { /** Goes to the previous step */ onBackButtonPress: () => void; + /** Handles submit button press (URL-based navigation) */ + onSubmit?: () => void; + /** Reference to the outer element */ ref?: ForwardedRef; }; @@ -30,7 +33,7 @@ type PersonalInfoProps = { const PERSONAL_INFO_STEP_KEYS = INPUT_IDS.PERSONAL_INFO_STEP; const bodyContent: Array> = [FullName, DateOfBirth, SocialSecurityNumber, Address, Confirmation]; -function PersonalInfo({onBackButtonPress, ref}: PersonalInfoProps) { +function PersonalInfo({onBackButtonPress, onSubmit, ref}: PersonalInfoProps) { const {translate} = useLocalize(); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); @@ -56,8 +59,15 @@ function PersonalInfo({onBackButtonPress, ref}: PersonalInfoProps) { prevScreen, moveTo, goToTheLastStep, - // eslint-disable-next-line @typescript-eslint/no-deprecated - } = useSubStep({bodyContent, startFrom, onFinished: () => submit(true), onNextSubStep: () => submit(false)}); + } = useSubStep({ + bodyContent, + startFrom, + onFinished: () => { + submit(true); + onSubmit?.(); + }, + onNextSubStep: () => submit(false), + }); const handleBackButtonPress = () => { if (isEditing) { diff --git a/src/pages/ReimbursementAccount/USD/Requestor/RequestorStep.tsx b/src/pages/ReimbursementAccount/USD/Requestor/RequestorStep.tsx index 4a9de8d65704a..fc57a2d04be19 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/RequestorStep.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/RequestorStep.tsx @@ -8,6 +8,9 @@ type RequestorStepProps = { /** Goes to the previous step */ onBackButtonPress: () => void; + /** Handles submit button press (URL-based navigation) */ + onSubmit?: () => void; + /** If we should show Onfido flow */ shouldShowOnfido: boolean; @@ -15,7 +18,7 @@ type RequestorStepProps = { ref?: ForwardedRef; }; -function RequestorStep({shouldShowOnfido, onBackButtonPress, ref}: RequestorStepProps) { +function RequestorStep({shouldShowOnfido, onBackButtonPress, onSubmit, ref}: RequestorStepProps) { if (shouldShowOnfido) { return ; } @@ -24,6 +27,7 @@ function RequestorStep({shouldShowOnfido, onBackButtonPress, ref}: RequestorStep ); } diff --git a/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx b/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx index f8e227f4c7139..e8a00fa0e7688 100644 --- a/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx +++ b/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx @@ -126,10 +126,10 @@ function VerifiedBankAccountFlowEntryPoint({ const prepareNextStep = useCallback( (setupType: ValueOf) => { setBankAccountSubStep(setupType); - setUSDBankAccountStep(CONST.BANK_ACCOUNT.STEP.COUNTRY); goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.COUNTRY); + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: CONST.BANK_ACCOUNT.STEP.COUNTRY})); }, - [setUSDBankAccountStep], + [setUSDBankAccountStep, policyID], ); /** From 2deff2953789c6088685006c3aaaf3c65bcbd005 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Tue, 24 Mar 2026 17:02:27 +0100 Subject: [PATCH 04/20] feat: change props --- .../ReimbursementAccount/USD/BankInfo/subSteps/Manual.tsx | 6 ++---- .../ReimbursementAccount/USD/BankInfo/subSteps/Plaid.tsx | 6 ++---- .../BeneficialOwnerDetailsFormSubSteps/AddressUBO.tsx | 4 ++-- .../BeneficialOwnerDetailsFormSubSteps/ConfirmationUBO.tsx | 4 ++-- .../BeneficialOwnerDetailsFormSubSteps/DateOfBirthUBO.tsx | 4 ++-- .../BeneficialOwnerDetailsFormSubSteps/LegalNameUBO.tsx | 4 ++-- .../SocialSecurityNumberUBO.tsx | 4 ++-- .../USD/BusinessInfo/subSteps/AddressBusiness.tsx | 4 ++-- .../USD/BusinessInfo/subSteps/ConfirmationBusiness.tsx | 4 ++-- .../USD/BusinessInfo/subSteps/IncorporationCode.tsx | 4 ++-- .../USD/BusinessInfo/subSteps/IncorporationDateBusiness.tsx | 4 ++-- .../BusinessInfo/subSteps/IncorporationStateBusiness.tsx | 4 ++-- .../USD/BusinessInfo/subSteps/NameBusiness.tsx | 4 ++-- .../USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx | 4 ++-- .../USD/BusinessInfo/subSteps/TaxIdBusiness.tsx | 4 ++-- .../USD/BusinessInfo/subSteps/TypeBusiness/TypeBusiness.tsx | 4 ++-- .../USD/BusinessInfo/subSteps/WebsiteBusiness.tsx | 4 ++-- .../USD/CompleteVerification/subSteps/ConfirmAgreements.tsx | 6 ++---- .../USD/Requestor/PersonalInfo/subSteps/Address.tsx | 4 ++-- .../USD/Requestor/PersonalInfo/subSteps/Confirmation.tsx | 4 ++-- .../USD/Requestor/PersonalInfo/subSteps/DateOfBirth.tsx | 4 ++-- .../USD/Requestor/PersonalInfo/subSteps/FullName.tsx | 4 ++-- .../PersonalInfo/subSteps/SocialSecurityNumber.tsx | 4 ++-- 23 files changed, 46 insertions(+), 52 deletions(-) diff --git a/src/pages/ReimbursementAccount/USD/BankInfo/subSteps/Manual.tsx b/src/pages/ReimbursementAccount/USD/BankInfo/subSteps/Manual.tsx index 6e89550cb6d83..41048d40dab23 100644 --- a/src/pages/ReimbursementAccount/USD/BankInfo/subSteps/Manual.tsx +++ b/src/pages/ReimbursementAccount/USD/BankInfo/subSteps/Manual.tsx @@ -8,7 +8,7 @@ import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import useThemeStyles from '@hooks/useThemeStyles'; import {getFieldRequiredErrors, isValidRoutingNumber} from '@libs/ValidationUtils'; import ExampleCheckImage from '@pages/ReimbursementAccount/USD/BankInfo/ExampleCheck'; @@ -17,12 +17,10 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; -type ManualProps = SubStepProps; - const BANK_INFO_STEP_KEYS = INPUT_IDS.BANK_INFO_STEP; const STEP_FIELDS = [BANK_INFO_STEP_KEYS.ROUTING_NUMBER, BANK_INFO_STEP_KEYS.ACCOUNT_NUMBER]; -function Manual({onNext}: ManualProps) { +function Manual({onNext}: SubPageProps) { const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); diff --git a/src/pages/ReimbursementAccount/USD/BankInfo/subSteps/Plaid.tsx b/src/pages/ReimbursementAccount/USD/BankInfo/subSteps/Plaid.tsx index 2ff34d9ac3840..711a73fa42014 100644 --- a/src/pages/ReimbursementAccount/USD/BankInfo/subSteps/Plaid.tsx +++ b/src/pages/ReimbursementAccount/USD/BankInfo/subSteps/Plaid.tsx @@ -6,7 +6,7 @@ import InputWrapper from '@components/Form/InputWrapper'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePrevious from '@hooks/usePrevious'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import useThemeStyles from '@hooks/useThemeStyles'; import {getBankAccountIDAsNumber} from '@libs/ReimbursementAccountUtils'; import {setBankAccountSubStep, validatePlaidSelection} from '@userActions/BankAccounts'; @@ -14,11 +14,9 @@ import {updateReimbursementAccountDraft} from '@userActions/ReimbursementAccount import ONYXKEYS from '@src/ONYXKEYS'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; -type PlaidProps = SubStepProps; - const BANK_INFO_STEP_KEYS = INPUT_IDS.BANK_INFO_STEP; -function Plaid({onNext}: PlaidProps) { +function Plaid({onNext}: SubPageProps) { const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); const [plaidData] = useOnyx(ONYXKEYS.PLAID_DATA); diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/AddressUBO.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/AddressUBO.tsx index 1f3507f8357ab..03e1ad8a24941 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/AddressUBO.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/AddressUBO.tsx @@ -3,7 +3,7 @@ import AddressStep from '@components/SubStepForms/AddressStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import SafeString from '@src/utils/SafeString'; @@ -11,7 +11,7 @@ import SafeString from '@src/utils/SafeString'; const BENEFICIAL_OWNER_INFO_KEY = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.BENEFICIAL_OWNER_DATA; const BENEFICIAL_OWNER_PREFIX = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.BENEFICIAL_OWNER_DATA.PREFIX; -type AddressUBOProps = SubStepProps & {beneficialOwnerBeingModifiedID: string}; +type AddressUBOProps = SubPageProps & {beneficialOwnerBeingModifiedID: string}; function AddressUBO({onNext, onMove, isEditing, beneficialOwnerBeingModifiedID}: AddressUBOProps) { const {translate} = useLocalize(); diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/ConfirmationUBO.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/ConfirmationUBO.tsx index 6ed56f6d79efe..657ad604a3ed9 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/ConfirmationUBO.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/ConfirmationUBO.tsx @@ -2,13 +2,13 @@ import React from 'react'; import ConfirmationStep from '@components/SubStepForms/ConfirmationStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import * as ErrorUtils from '@libs/ErrorUtils'; import getValuesForBeneficialOwner from '@pages/ReimbursementAccount/USD/utils/getValuesForBeneficialOwner'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -type ConfirmationUBOProps = SubStepProps & {beneficialOwnerBeingModifiedID: string}; +type ConfirmationUBOProps = SubPageProps & {beneficialOwnerBeingModifiedID: string}; const UBO_STEP_INDEXES = CONST.REIMBURSEMENT_ACCOUNT.SUBSTEP_INDEX.UBO; diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/DateOfBirthUBO.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/DateOfBirthUBO.tsx index 8f824cf543344..9eb85e749b36e 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/DateOfBirthUBO.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/DateOfBirthUBO.tsx @@ -3,7 +3,7 @@ import DateOfBirthStep from '@components/SubStepForms/DateOfBirthStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import SafeString from '@src/utils/SafeString'; @@ -11,7 +11,7 @@ import SafeString from '@src/utils/SafeString'; const DOB = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.BENEFICIAL_OWNER_DATA.DOB; const BENEFICIAL_OWNER_PREFIX = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.BENEFICIAL_OWNER_DATA.PREFIX; -type DateOfBirthUBOProps = SubStepProps & {beneficialOwnerBeingModifiedID: string}; +type DateOfBirthUBOProps = SubPageProps & {beneficialOwnerBeingModifiedID: string}; function DateOfBirthUBO({onNext, onMove, isEditing, beneficialOwnerBeingModifiedID}: DateOfBirthUBOProps) { const {translate} = useLocalize(); diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/LegalNameUBO.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/LegalNameUBO.tsx index ac34d4e4132f5..dcd23543abbd7 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/LegalNameUBO.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/LegalNameUBO.tsx @@ -4,7 +4,7 @@ import FullNameStep from '@components/SubStepForms/FullNameStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import SafeString from '@src/utils/SafeString'; @@ -12,7 +12,7 @@ import SafeString from '@src/utils/SafeString'; const {FIRST_NAME, LAST_NAME} = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.BENEFICIAL_OWNER_DATA; const BENEFICIAL_OWNER_PREFIX = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.BENEFICIAL_OWNER_DATA.PREFIX; -type LegalNameUBOProps = SubStepProps & {beneficialOwnerBeingModifiedID: string}; +type LegalNameUBOProps = SubPageProps & {beneficialOwnerBeingModifiedID: string}; function LegalNameUBO({onNext, onMove, isEditing, beneficialOwnerBeingModifiedID}: LegalNameUBOProps) { const {translate} = useLocalize(); diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/SocialSecurityNumberUBO.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/SocialSecurityNumberUBO.tsx index 84c8723cf296c..94fbc06fe636a 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/SocialSecurityNumberUBO.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/SocialSecurityNumberUBO.tsx @@ -4,7 +4,7 @@ import SingleFieldStep from '@components/SubStepForms/SingleFieldStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import {getFieldRequiredErrors, isValidSSNLastFour} from '@libs/ValidationUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -13,7 +13,7 @@ import SafeString from '@src/utils/SafeString'; const SSN_LAST_4 = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.BENEFICIAL_OWNER_DATA.SSN_LAST_4; const BENEFICIAL_OWNER_PREFIX = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.BENEFICIAL_OWNER_DATA.PREFIX; -type SocialSecurityNumberUBOProps = SubStepProps & {beneficialOwnerBeingModifiedID: string}; +type SocialSecurityNumberUBOProps = SubPageProps & {beneficialOwnerBeingModifiedID: string}; function SocialSecurityNumberUBO({onNext, onMove, isEditing, beneficialOwnerBeingModifiedID}: SocialSecurityNumberUBOProps) { const {translate} = useLocalize(); diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/AddressBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/AddressBusiness.tsx index 9d68d1da372f3..69fc14e84caac 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/AddressBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/AddressBusiness.tsx @@ -4,7 +4,7 @@ import AddressStep from '@components/SubStepForms/AddressStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import ONYXKEYS from '@src/ONYXKEYS'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; @@ -21,7 +21,7 @@ const INPUT_KEYS = { const STEP_FIELDS = [COMPANY_BUSINESS_INFO_KEY.STREET, COMPANY_BUSINESS_INFO_KEY.CITY, COMPANY_BUSINESS_INFO_KEY.STATE, COMPANY_BUSINESS_INFO_KEY.ZIP_CODE]; -function AddressBusiness({onNext, onMove, isEditing}: SubStepProps) { +function AddressBusiness({onNext, onMove, isEditing}: SubPageProps) { const {translate} = useLocalize(); const [reimbursementAccount, reimbursementAccountResult] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/ConfirmationBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/ConfirmationBusiness.tsx index 4bdeebd55e214..1c6b94b2337af 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/ConfirmationBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/ConfirmationBusiness.tsx @@ -10,7 +10,7 @@ import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import useThemeStyles from '@hooks/useThemeStyles'; import {getFieldRequiredErrors} from '@libs/ValidationUtils'; import getSubStepValues from '@pages/ReimbursementAccount/utils/getSubStepValues'; @@ -35,7 +35,7 @@ function ConfirmCompanyLabel() { ); } -function ConfirmationBusiness({onNext, onMove}: SubStepProps) { +function ConfirmationBusiness({onNext, onMove}: SubPageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IncorporationCode.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IncorporationCode.tsx index 579ac48913fe8..8cca170661eb7 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IncorporationCode.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IncorporationCode.tsx @@ -6,7 +6,7 @@ import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import useThemeStyles from '@hooks/useThemeStyles'; import {isValidIndustryCode} from '@libs/ValidationUtils'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -16,7 +16,7 @@ import IndustryCodeSelector from './IndustryCode/IndustryCodeSelector'; const COMPANY_INCORPORATION_CODE_KEY = INPUT_IDS.BUSINESS_INFO_STEP.INCORPORATION_CODE; const STEP_FIELDS = [COMPANY_INCORPORATION_CODE_KEY]; -function IncorporationCode({onNext, isEditing}: SubStepProps) { +function IncorporationCode({onNext, isEditing}: SubPageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IncorporationDateBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IncorporationDateBusiness.tsx index 2febf55e42b5c..7674f9b770d66 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IncorporationDateBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IncorporationDateBusiness.tsx @@ -8,7 +8,7 @@ import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import useThemeStyles from '@hooks/useThemeStyles'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import {getFieldRequiredErrors, isValidDate, isValidPastDate} from '@libs/ValidationUtils'; @@ -19,7 +19,7 @@ import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; const COMPANY_INCORPORATION_DATE_KEY = INPUT_IDS.BUSINESS_INFO_STEP.INCORPORATION_DATE; const STEP_FIELDS = [COMPANY_INCORPORATION_DATE_KEY]; -function IncorporationDateBusiness({onNext, isEditing}: SubStepProps) { +function IncorporationDateBusiness({onNext, isEditing}: SubPageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IncorporationStateBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IncorporationStateBusiness.tsx index 5d10d77469b0f..24d899552ea9f 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IncorporationStateBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IncorporationStateBusiness.tsx @@ -9,7 +9,7 @@ import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import useThemeStyles from '@hooks/useThemeStyles'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import {getFieldRequiredErrors} from '@libs/ValidationUtils'; @@ -25,7 +25,7 @@ const validate = ( translate: LocalizedTranslate, ): FormInputErrors => getFieldRequiredErrors(values, STEP_FIELDS, translate); -function IncorporationStateBusiness({onNext, isEditing}: SubStepProps) { +function IncorporationStateBusiness({onNext, isEditing}: SubPageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/NameBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/NameBusiness.tsx index 6e18b09b29235..1156f7fd54571 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/NameBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/NameBusiness.tsx @@ -4,7 +4,7 @@ import SingleFieldStep from '@components/SubStepForms/SingleFieldStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import {getFieldRequiredErrors, isValidCompanyName} from '@libs/ValidationUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -13,7 +13,7 @@ import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; const COMPANY_NAME_KEY = INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_NAME; const STEP_FIELDS = [COMPANY_NAME_KEY]; -function NameBusiness({onNext, onMove, isEditing}: SubStepProps) { +function NameBusiness({onNext, onMove, isEditing}: SubPageProps) { const {translate} = useLocalize(); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx index 4437c83e62284..6fa565649d4c5 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx @@ -5,7 +5,7 @@ import SingleFieldStep from '@components/SubStepForms/SingleFieldStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import {getFieldRequiredErrors, isValidUSPhone} from '@libs/ValidationUtils'; import CONST from '@src/CONST'; @@ -16,7 +16,7 @@ import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; const COMPANY_PHONE_NUMBER_KEY = INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_PHONE; const STEP_FIELDS = [COMPANY_PHONE_NUMBER_KEY]; -function PhoneNumberBusiness({onNext, onMove, isEditing}: SubStepProps) { +function PhoneNumberBusiness({onNext, onMove, isEditing}: SubPageProps) { const {translate} = useLocalize(); const [reimbursementAccount, reimbursementAccountResult] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TaxIdBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TaxIdBusiness.tsx index 94a85398e8fba..18e77e094113d 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TaxIdBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TaxIdBusiness.tsx @@ -5,7 +5,7 @@ import SingleFieldStep from '@components/SubStepForms/SingleFieldStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import {getFieldRequiredErrors, isValidTaxID} from '@libs/ValidationUtils'; import CONST from '@src/CONST'; @@ -15,7 +15,7 @@ import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; const COMPANY_TAX_ID_KEY = INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_TAX_ID; const STEP_FIELDS = [COMPANY_TAX_ID_KEY]; -function TaxIdBusiness({onNext, onMove, isEditing}: SubStepProps) { +function TaxIdBusiness({onNext, onMove, isEditing}: SubPageProps) { const {translate} = useLocalize(); const [reimbursementAccount, reimbursementAccountResult] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TypeBusiness/TypeBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TypeBusiness/TypeBusiness.tsx index f8a296965496f..0154ec35c1889 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TypeBusiness/TypeBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TypeBusiness/TypeBusiness.tsx @@ -7,7 +7,7 @@ import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import useThemeStyles from '@hooks/useThemeStyles'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import {getFieldRequiredErrors} from '@libs/ValidationUtils'; @@ -19,7 +19,7 @@ import BusinessTypePicker from './BusinessTypePicker'; const COMPANY_INCORPORATION_TYPE_KEY = INPUT_IDS.BUSINESS_INFO_STEP.INCORPORATION_TYPE; const STEP_FIELDS = [COMPANY_INCORPORATION_TYPE_KEY]; -function TypeBusiness({onNext, isEditing}: SubStepProps) { +function TypeBusiness({onNext, isEditing}: SubPageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx index 8a15cbcf8908e..7c83dc7bbb518 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx @@ -6,7 +6,7 @@ import SingleFieldStep from '@components/SubStepForms/SingleFieldStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import {getDefaultCompanyWebsite} from '@libs/BankAccountUtils'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import {getFieldRequiredErrors, isValidWebsite} from '@libs/ValidationUtils'; @@ -19,7 +19,7 @@ import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; const COMPANY_WEBSITE_KEY = INPUT_IDS.BUSINESS_INFO_STEP.COMPANY_WEBSITE; const STEP_FIELDS = [COMPANY_WEBSITE_KEY]; -function WebsiteBusiness({onNext, onMove, isEditing}: SubStepProps) { +function WebsiteBusiness({onNext, onMove, isEditing}: SubPageProps) { const {translate} = useLocalize(); const [reimbursementAccount, reimbursementAccountResult] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); const isLoadingReimbursementAccount = isLoadingOnyxValue(reimbursementAccountResult); diff --git a/src/pages/ReimbursementAccount/USD/CompleteVerification/subSteps/ConfirmAgreements.tsx b/src/pages/ReimbursementAccount/USD/CompleteVerification/subSteps/ConfirmAgreements.tsx index 0799cece14181..3e47077aa1890 100644 --- a/src/pages/ReimbursementAccount/USD/CompleteVerification/subSteps/ConfirmAgreements.tsx +++ b/src/pages/ReimbursementAccount/USD/CompleteVerification/subSteps/ConfirmAgreements.tsx @@ -7,15 +7,13 @@ import RenderHTML from '@components/RenderHTML'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import useThemeStyles from '@hooks/useThemeStyles'; import {getFieldRequiredErrors, isRequiredFulfilled} from '@libs/ValidationUtils'; import getSubStepValues from '@pages/ReimbursementAccount/utils/getSubStepValues'; import ONYXKEYS from '@src/ONYXKEYS'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; -type ConfirmAgreementsProps = SubStepProps; - const COMPLETE_VERIFICATION_KEYS = INPUT_IDS.COMPLETE_VERIFICATION; const STEP_FIELDS = [ INPUT_IDS.COMPLETE_VERIFICATION.IS_AUTHORIZED_TO_USE_BANK_ACCOUNT, @@ -38,7 +36,7 @@ function TermsAndConditionsLabel() { return ; } -function ConfirmAgreements({onNext}: ConfirmAgreementsProps) { +function ConfirmAgreements({onNext}: SubPageProps) { const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); const {translate} = useLocalize(); diff --git a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/Address.tsx b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/Address.tsx index cc63886621cec..39c912e0ce38e 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/Address.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/Address.tsx @@ -4,7 +4,7 @@ import AddressStep from '@components/SubStepForms/AddressStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -22,7 +22,7 @@ const INPUT_KEYS = { const STEP_FIELDS = [PERSONAL_INFO_STEP_KEY.STREET, PERSONAL_INFO_STEP_KEY.CITY, PERSONAL_INFO_STEP_KEY.STATE, PERSONAL_INFO_STEP_KEY.ZIP_CODE]; -function Address({onNext, onMove, isEditing}: SubStepProps) { +function Address({onNext, onMove, isEditing}: SubPageProps) { const {translate} = useLocalize(); const [reimbursementAccount, reimbursementAccountResult] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); diff --git a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/Confirmation.tsx b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/Confirmation.tsx index 17c29db3ce128..e9c1a8749b9c6 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/Confirmation.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/Confirmation.tsx @@ -2,7 +2,7 @@ import React, {useMemo} from 'react'; import ConfirmationStep from '@components/SubStepForms/ConfirmationStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import {getLatestErrorMessage} from '@libs/ErrorUtils'; import getSubStepValues from '@pages/ReimbursementAccount/utils/getSubStepValues'; import CONST from '@src/CONST'; @@ -12,7 +12,7 @@ import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; const PERSONAL_INFO_STEP_KEYS = INPUT_IDS.PERSONAL_INFO_STEP; const PERSONAL_INFO_STEP_INDEXES = CONST.REIMBURSEMENT_ACCOUNT.SUBSTEP_INDEX.PERSONAL_INFO; -function Confirmation({onNext, onMove, isEditing}: SubStepProps) { +function Confirmation({onNext, onMove, isEditing}: SubPageProps) { const {translate} = useLocalize(); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); diff --git a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/DateOfBirth.tsx b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/DateOfBirth.tsx index cde22e01ed979..54adf2a4be871 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/DateOfBirth.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/DateOfBirth.tsx @@ -4,7 +4,7 @@ import DateOfBirthStep from '@components/SubStepForms/DateOfBirthStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import useThemeStyles from '@hooks/useThemeStyles'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import HelpLinks from '@pages/ReimbursementAccount/USD/Requestor/PersonalInfo/HelpLinks'; @@ -16,7 +16,7 @@ import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; const PERSONAL_INFO_DOB_KEY = INPUT_IDS.PERSONAL_INFO_STEP.DOB; const STEP_FIELDS = [PERSONAL_INFO_DOB_KEY]; -function DateOfBirth({onNext, onMove, isEditing}: SubStepProps) { +function DateOfBirth({onNext, onMove, isEditing}: SubPageProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); diff --git a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/FullName.tsx b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/FullName.tsx index a1f8419637924..6093b3c2a77ab 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/FullName.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/FullName.tsx @@ -3,7 +3,7 @@ import FullNameStep from '@components/SubStepForms/FullNameStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; @@ -11,7 +11,7 @@ import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; const PERSONAL_INFO_STEP_KEY = INPUT_IDS.PERSONAL_INFO_STEP; const STEP_FIELDS = [PERSONAL_INFO_STEP_KEY.FIRST_NAME, PERSONAL_INFO_STEP_KEY.LAST_NAME]; -function FullName({onNext, onMove, isEditing}: SubStepProps) { +function FullName({onNext, onMove, isEditing}: SubPageProps) { const {translate} = useLocalize(); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); diff --git a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/SocialSecurityNumber.tsx b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/SocialSecurityNumber.tsx index ff9d07476a6a5..97d7bc35638ac 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/SocialSecurityNumber.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/SocialSecurityNumber.tsx @@ -5,7 +5,7 @@ import SingleFieldStep from '@components/SubStepForms/SingleFieldStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReimbursementAccountStepFormSubmit from '@hooks/useReimbursementAccountStepFormSubmit'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import {getFieldRequiredErrors, isValidSSNLastFour} from '@libs/ValidationUtils'; import CONST from '@src/CONST'; @@ -16,7 +16,7 @@ import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; const PERSONAL_INFO_STEP_KEY = INPUT_IDS.PERSONAL_INFO_STEP; const STEP_FIELDS = [PERSONAL_INFO_STEP_KEY.SSN_LAST_4]; -function SocialSecurityNumber({onNext, onMove, isEditing}: SubStepProps) { +function SocialSecurityNumber({onNext, onMove, isEditing}: SubPageProps) { const {translate} = useLocalize(); const [reimbursementAccount, reimbursementAccountResult] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); From 131310d9310ccc8c3f86d0d4cf692adaf3db8dde Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 25 Mar 2026 16:39:59 +0100 Subject: [PATCH 05/20] fix: route fixes --- src/CONST/index.ts | 47 ++++++++++++++++++++++++++++++++++++ src/ROUTES.ts | 9 ++++--- src/libs/Navigation/types.ts | 3 ++- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 25cb5396aa35c..de44e8fa86323 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -605,6 +605,53 @@ const CONST = { ENABLE: 'enable', }, STEP_NAMES: ['1', '2', '3', '4', '5', '6'], + BANK_INFO_STEP: { + SUB_PAGE_NAMES: { + MANUAL: 'manual', + PLAID: 'plaid', + }, + }, + PERSONAL_INFO_STEP: { + SUB_PAGE_NAMES: { + FULL_NAME: 'full-name', + DATE_OF_BIRTH: 'date-of-birth', + SSN: 'ssn', + ADDRESS: 'address', + CONFIRMATION: 'confirmation', + }, + }, + BUSINESS_INFO_STEP: { + SUB_PAGE_NAMES: { + NAME: 'name', + TAX_ID: 'tax-id', + WEBSITE: 'website', + PHONE: 'phone', + ADDRESS: 'address', + TYPE: 'type', + INCORPORATION_DATE: 'incorporation-date', + INCORPORATION_STATE: 'incorporation-state', + INCORPORATION_CODE: 'incorporation-code', + CONFIRMATION: 'confirmation', + }, + }, + BENEFICIAL_OWNERS_STEP: { + SUB_PAGE_NAMES: { + IS_USER_UBO: 'is-user-ubo', + IS_ANYONE_ELSE_UBO: 'is-anyone-else-ubo', + ARE_THERE_MORE_UBOS: 'are-there-more-ubos', + UBOS_LIST: 'ubos-list', + LEGAL_NAME: 'legal-name', + DATE_OF_BIRTH: 'date-of-birth', + SSN: 'ssn', + ADDRESS: 'address', + CONFIRMATION: 'confirmation', + }, + }, + COMPLETE_VERIFICATION_STEP: { + SUB_PAGE_NAMES: { + CONFIRM_AGREEMENTS: 'confirm-agreements', + }, + }, SUBSTEP: { MANUAL: 'manual', PLAID: 'plaid', diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 727cbdf24d893..241ff1e73629c 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -313,15 +313,16 @@ const ROUTES = { getRoute: (policyID: string) => `bank-account/connect-existing-business-bank-account?policyID=${policyID}` as const, }, BANK_ACCOUNT_USD_SETUP: { - route: 'bank-account/us/:step?/:subStep?', + route: 'bank-account/us/:step?/:subPage?/:action?', // eslint-disable-next-line no-restricted-syntax -- Legacy route generation - getRoute: ({policyID, step, subStep, backTo}: {policyID?: string; step?: string; subStep?: string; backTo?: string}) => { + getRoute: ({policyID, step, subPage, action, backTo}: {policyID?: string; step?: string; subPage?: string; action?: 'edit'; backTo?: string}) => { const base = 'bank-account/us'; const stepPart = step ? `/${step}` : ''; - const subStepPart = subStep ? `/${subStep}` : ''; + const subStepPart = subPage ? `/${subPage}` : ''; + const actionPart = action ? `/${action}` : ''; const queryString = policyID ? `?policyID=${policyID}` : ''; // eslint-disable-next-line no-restricted-syntax -- Legacy route generation - return getUrlWithBackToParam(`${base}${stepPart}${subStepPart}${queryString}`, backTo); + return getUrlWithBackToParam(`${base}${stepPart}${subStepPart}${actionPart}${queryString}`, backTo); }, }, SETTINGS: 'settings', diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index cc651c9ed2f43..bb4c39d396623 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -2245,7 +2245,8 @@ type ReimbursementAccountNavigatorParamList = { }; [SCREENS.REIMBURSEMENT_ACCOUNT_USD]: { step?: string; - subStep?: string; + subPage?: string; + action?: 'edit'; policyID?: string; // 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 backTo?: Routes; From 07ba0240b916a375c3b4e842ba7e8798b656b405 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Wed, 25 Mar 2026 18:12:27 +0100 Subject: [PATCH 06/20] fix: types --- .../ReimbursementAccount/ConnectedVerifiedBankAccount.tsx | 2 +- .../USD/ConnectBankAccount/ConnectBankAccount.tsx | 4 ++-- .../USD/ConnectBankAccount/components/FinishChatCard.tsx | 4 ++-- .../USD/USDVerifiedBankAccountFlowPage.tsx | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx b/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx index 3600ccf427f59..3466cbdb1da6b 100644 --- a/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx +++ b/src/pages/ReimbursementAccount/ConnectedVerifiedBankAccount.tsx @@ -30,7 +30,7 @@ type ConnectedVerifiedBankAccountProps = { setShouldShowConnectedVerifiedBankAccount?: (shouldShowConnectedVerifiedBankAccount: boolean) => void; /** Method to set the state of USD bank account step */ - setUSDBankAccountStep: (step: string | null) => void; + setUSDBankAccountStep?: (step: string | null) => void; /** Method to set the state of setNonUSDBankAccountStep */ setNonUSDBankAccountStep?: (step: string | null) => void; diff --git a/src/pages/ReimbursementAccount/USD/ConnectBankAccount/ConnectBankAccount.tsx b/src/pages/ReimbursementAccount/USD/ConnectBankAccount/ConnectBankAccount.tsx index 69a87b5233bf2..d0f3ca3ffaba2 100644 --- a/src/pages/ReimbursementAccount/USD/ConnectBankAccount/ConnectBankAccount.tsx +++ b/src/pages/ReimbursementAccount/USD/ConnectBankAccount/ConnectBankAccount.tsx @@ -20,10 +20,10 @@ type ConnectBankAccountProps = { onBackButtonPress: () => void; /** Method to set the state of shouldShowConnectedVerifiedBankAccount */ - setShouldShowConnectedVerifiedBankAccount: (shouldShowConnectedVerifiedBankAccount: boolean) => void; + setShouldShowConnectedVerifiedBankAccount?: (shouldShowConnectedVerifiedBankAccount: boolean) => void; /** Method to set the state of shouldShowConnectedVerifiedBankAccount */ - setUSDBankAccountStep: (step: string | null) => void; + setUSDBankAccountStep?: (step: string | null) => void; }; function ConnectBankAccount({onBackButtonPress, setShouldShowConnectedVerifiedBankAccount, setUSDBankAccountStep}: ConnectBankAccountProps) { diff --git a/src/pages/ReimbursementAccount/USD/ConnectBankAccount/components/FinishChatCard.tsx b/src/pages/ReimbursementAccount/USD/ConnectBankAccount/components/FinishChatCard.tsx index 3c753ade889f9..2ca74811965dc 100644 --- a/src/pages/ReimbursementAccount/USD/ConnectBankAccount/components/FinishChatCard.tsx +++ b/src/pages/ReimbursementAccount/USD/ConnectBankAccount/components/FinishChatCard.tsx @@ -25,7 +25,7 @@ type FinishChatCardProps = { requiresTwoFactorAuth: boolean; /** Method to set the state of USD bank account step */ - setUSDBankAccountStep: (step: string | null) => void; + setUSDBankAccountStep?: (step: string | null) => void; }; function FinishChatCard({requiresTwoFactorAuth, reimbursementAccount, setUSDBankAccountStep}: FinishChatCardProps) { @@ -65,7 +65,7 @@ function FinishChatCard({requiresTwoFactorAuth, reimbursementAccount, setUSDBank title={translate('workspace.bankAccount.updateDetails')} onPress={() => { setBankAccountSubStep(CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL).then(() => { - setUSDBankAccountStep(CONST.BANK_ACCOUNT.STEP.REQUESTOR); + setUSDBankAccountStep?.(CONST.BANK_ACCOUNT.STEP.REQUESTOR); goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.REQUESTOR); }); }} diff --git a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx index 5c2ba9714153a..6cd8d8517556d 100644 --- a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx +++ b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx @@ -41,7 +41,7 @@ function USDVerifiedBankAccountFlowPage({route}: USDVerifiedBankAccountFlowPageP const styles = useThemeStyles(); const policyID = route.params?.policyID; const currentStep = route.params?.step; - const currentSubPage = route.params?.subStep; + const currentSubPage = route.params?.subPage; const [onfidoToken = ''] = useOnyx(ONYXKEYS.ONFIDO_TOKEN); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); From a31ac82064ec08468503f339b6983d3cfe5af14c Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 26 Mar 2026 09:44:21 +0100 Subject: [PATCH 07/20] feat: migrate substeps to sub pages --- .../USD/BankInfo/BankInfo.tsx | 35 ++-- .../BeneficialOwnerDetailsFormPages.tsx | 113 +++++++++++++ .../BeneficialOwnersStep.tsx | 160 ++++++++---------- .../USD/BusinessInfo/BusinessInfo.tsx | 72 ++++---- .../CompleteVerification.tsx | 30 ++-- .../Requestor/PersonalInfo/PersonalInfo.tsx | 59 ++++--- .../USD/USDVerifiedBankAccountFlowPage.tsx | 41 ++++- 7 files changed, 333 insertions(+), 177 deletions(-) create mode 100644 src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormPages.tsx diff --git a/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx b/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx index 7547a0a372cb5..cc29017e0e503 100644 --- a/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx @@ -1,9 +1,9 @@ -import React, {useEffect, useRef} from 'react'; +import React, {useCallback, useEffect, useRef} from 'react'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import useSubStep from '@hooks/useSubStep'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import useSubPage from '@hooks/useSubPage'; +import type {SubPageProps} from '@hooks/useSubPage/types'; import getPlaidOAuthReceivedRedirectURI from '@libs/getPlaidOAuthReceivedRedirectURI'; import {getBankAccountIDAsNumber} from '@libs/ReimbursementAccountUtils'; import getSubStepValues from '@pages/ReimbursementAccount/utils/getSubStepValues'; @@ -11,6 +11,7 @@ import {connectBankAccountManually, connectBankAccountWithPlaid} from '@userActi import {hideBankAccountErrors} from '@userActions/ReimbursementAccount'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; import type {ReimbursementAccountForm} from '@src/types/form'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; import Manual from './subSteps/Manual'; @@ -27,13 +28,14 @@ type BankInfoProps = { policyID: string; }; -type BankInfoSubStepProps = SubStepProps; - const BANK_INFO_STEP_KEYS = INPUT_IDS.BANK_INFO_STEP; -const manualSubSteps: Array> = [Manual]; -const plaidSubSteps: Array> = [Plaid]; +const PAGE_NAMES = CONST.BANK_ACCOUNT.PAGE_NAMES; +const SUB_PAGE_NAMES = CONST.BANK_ACCOUNT.BANK_INFO_STEP.SUB_PAGE_NAMES; const receivedRedirectURI = getPlaidOAuthReceivedRedirectURI(); +const manualPages = [{pageName: SUB_PAGE_NAMES.MANUAL, component: Manual}]; +const plaidPages = [{pageName: SUB_PAGE_NAMES.PLAID, component: Plaid}]; + function BankInfo({onBackButtonPress, onSubmit, policyID}: BankInfoProps) { const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); @@ -85,9 +87,14 @@ function BankInfo({onBackButtonPress, onSubmit, policyID}: BankInfoProps) { onSubmit?.(); }; - const bodyContent = setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID ? plaidSubSteps : manualSubSteps; - // eslint-disable-next-line @typescript-eslint/no-deprecated - const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo} = useSubStep({bodyContent, startFrom: 0, onFinished: submit}); + const pages = setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID ? plaidPages : manualPages; + + const buildRoute = useCallback( + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.BANK_ACCOUNT, subPage: pageName, action}), + [policyID], + ); + + const {CurrentPage, isEditing, pageIndex, nextPage, prevPage, moveTo} = useSubPage({pages, startFrom: 0, onFinished: submit, buildRoute}); // Some services user connects to via Plaid return dummy account numbers and routing numbers e.g. Chase // In this case we need to redirect user to manual flow to enter real account number and routing number @@ -102,11 +109,11 @@ function BankInfo({onBackButtonPress, onSubmit, policyID}: BankInfoProps) { }, [setupType, values.bankName]); const handleBackButtonPress = () => { - if (screenIndex === 0) { + if (pageIndex === 0) { onBackButtonPress(); hideBankAccountErrors(); } else { - prevScreen(); + prevPage(); } }; @@ -119,9 +126,9 @@ function BankInfo({onBackButtonPress, onSubmit, policyID}: BankInfoProps) { startStepIndex={1} stepNames={CONST.BANK_ACCOUNT.STEP_NAMES} > - diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormPages.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormPages.tsx new file mode 100644 index 0000000000000..615755500baea --- /dev/null +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormPages.tsx @@ -0,0 +1,113 @@ +import React, {useCallback} from 'react'; +import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; +import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; +import useLocalize from '@hooks/useLocalize'; +import useSubPage from '@hooks/useSubPage'; +import type {SubPageProps} from '@hooks/useSubPage/types'; +import Navigation from '@libs/Navigation/Navigation'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; +import AddressUBO from './subSteps/BeneficialOwnerDetailsFormSubSteps/AddressUBO'; +import ConfirmationUBO from './subSteps/BeneficialOwnerDetailsFormSubSteps/ConfirmationUBO'; +import DateOfBirthUBO from './subSteps/BeneficialOwnerDetailsFormSubSteps/DateOfBirthUBO'; +import LegalNameUBO from './subSteps/BeneficialOwnerDetailsFormSubSteps/LegalNameUBO'; +import SocialSecurityNumberUBO from './subSteps/BeneficialOwnerDetailsFormSubSteps/SocialSecurityNumberUBO'; + +const PAGE_NAMES = CONST.BANK_ACCOUNT.PAGE_NAMES; +const SUB_PAGE_NAMES = CONST.BANK_ACCOUNT.BENEFICIAL_OWNERS_STEP.SUB_PAGE_NAMES; + +type BeneficialOwnerSubPageProps = SubPageProps & { + beneficialOwnerBeingModifiedID: string; + setBeneficialOwnerBeingModifiedID?: (id: string) => void; +}; + +const pages = [ + {pageName: SUB_PAGE_NAMES.LEGAL_NAME, component: LegalNameUBO}, + {pageName: SUB_PAGE_NAMES.DATE_OF_BIRTH, component: DateOfBirthUBO}, + {pageName: SUB_PAGE_NAMES.SSN, component: SocialSecurityNumberUBO}, + {pageName: SUB_PAGE_NAMES.ADDRESS, component: AddressUBO}, + {pageName: SUB_PAGE_NAMES.CONFIRMATION, component: ConfirmationUBO}, +]; + +type BeneficialOwnerDetailsFormPagesProps = { + /** ID of current policy */ + policyID?: string; + + /** ID of the beneficial owner being modified */ + beneficialOwnerBeingModifiedID: string; + + /** Setter for the beneficial owner being modified */ + setBeneficialOwnerBeingModifiedID: (id: string) => void; + + /** Whether user is editing an already-created beneficial owner */ + isEditingCreatedBeneficialOwner: boolean; + + /** Callback triggered after the last form page is completed */ + onFinished: () => void; +}; + +function BeneficialOwnerDetailsFormPages({ + policyID, + beneficialOwnerBeingModifiedID, + setBeneficialOwnerBeingModifiedID, + isEditingCreatedBeneficialOwner, + onFinished, +}: BeneficialOwnerDetailsFormPagesProps) { + const {translate} = useLocalize(); + + const buildRoute = useCallback( + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.BENEFICIAL_OWNERS, subPage: pageName, action}), + [policyID], + ); + + const {CurrentPage, isEditing, currentPageName, pageIndex, prevPage, nextPage, moveTo, isRedirecting} = useSubPage({ + pages, + startFrom: 0, + onFinished, + buildRoute, + }); + + const handleBackButtonPress = useCallback(() => { + if (isEditing) { + Navigation.goBack(buildRoute(SUB_PAGE_NAMES.CONFIRMATION)); + return; + } + + if (pageIndex === 0) { + if (isEditingCreatedBeneficialOwner) { + Navigation.goBack(buildRoute(SUB_PAGE_NAMES.UBOS_LIST)); + } else { + Navigation.goBack(buildRoute(SUB_PAGE_NAMES.IS_USER_UBO)); + } + } else { + prevPage(); + } + }, [buildRoute, isEditing, isEditingCreatedBeneficialOwner, pageIndex, prevPage]); + + if (isRedirecting) { + return ; + } + + return ( + + + + ); +} + +export default BeneficialOwnerDetailsFormPages; diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx index a81b2a4ef941f..d89e2d11bcaf6 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx @@ -1,23 +1,19 @@ import {Str} from 'expensify-common'; -import React, {useState} from 'react'; +import React, {useCallback, useState} from 'react'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import YesNoStep from '@components/SubStepForms/YesNoStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import useSubStep from '@hooks/useSubStep'; -import type {SubStepProps} from '@hooks/useSubStep/types'; import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; import {getBankAccountIDAsNumber} from '@libs/ReimbursementAccountUtils'; import {updateBeneficialOwnersForBankAccount} from '@userActions/BankAccounts'; import {setDraftValues} from '@userActions/FormActions'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; import SafeString from '@src/utils/SafeString'; -import AddressUBO from './subSteps/BeneficialOwnerDetailsFormSubSteps/AddressUBO'; -import ConfirmationUBO from './subSteps/BeneficialOwnerDetailsFormSubSteps/ConfirmationUBO'; -import DateOfBirthUBO from './subSteps/BeneficialOwnerDetailsFormSubSteps/DateOfBirthUBO'; -import LegalNameUBO from './subSteps/BeneficialOwnerDetailsFormSubSteps/LegalNameUBO'; -import SocialSecurityNumberUBO from './subSteps/BeneficialOwnerDetailsFormSubSteps/SocialSecurityNumberUBO'; +import BeneficialOwnerDetailsFormPages from './BeneficialOwnerDetailsFormPages'; import CompanyOwnersListUBO from './subSteps/CompanyOwnersListUBO'; type BeneficialOwnersStepProps = { @@ -26,15 +22,21 @@ type BeneficialOwnersStepProps = { /** Handles submit button press (URL-based navigation) */ onSubmit?: () => void; -}; -type BeneficialOwnerSubStepProps = SubStepProps & {beneficialOwnerBeingModifiedID: string; setBeneficialOwnerBeingModifiedID?: (id: string) => void}; + /** Name of the current sub page */ + currentSubPage?: string; + + /** ID of current policy */ + policyID?: string; +}; -const SUBSTEP = CONST.BANK_ACCOUNT.BENEFICIAL_OWNER_INFO_STEP.SUBSTEP; +const PAGE_NAMES = CONST.BANK_ACCOUNT.PAGE_NAMES; +const SUB_PAGE_NAMES = CONST.BANK_ACCOUNT.BENEFICIAL_OWNERS_STEP.SUB_PAGE_NAMES; const MAX_NUMBER_OF_UBOS = 4; -const bodyContent: Array> = [LegalNameUBO, DateOfBirthUBO, SocialSecurityNumberUBO, AddressUBO, ConfirmationUBO]; -function BeneficialOwnersStep({onBackButtonPress, onSubmit}: BeneficialOwnersStepProps) { +const OUTER_SUB_PAGES = new Set([SUB_PAGE_NAMES.IS_USER_UBO, SUB_PAGE_NAMES.IS_ANYONE_ELSE_UBO, SUB_PAGE_NAMES.ARE_THERE_MORE_UBOS, SUB_PAGE_NAMES.UBOS_LIST]); + +function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, policyID}: BeneficialOwnersStepProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -42,7 +44,6 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit}: BeneficialOwnersSte const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); const companyName = reimbursementAccount?.achData?.companyName ?? ''; - const policyID = reimbursementAccount?.achData?.policyID; const defaultValues = { ownsMoreThan25Percent: reimbursementAccount?.achData?.ownsMoreThan25Percent ?? reimbursementAccountDraft?.ownsMoreThan25Percent ?? false, hasOtherBeneficialOwners: reimbursementAccount?.achData?.hasOtherBeneficialOwners ?? reimbursementAccountDraft?.hasOtherBeneficialOwners ?? false, @@ -57,9 +58,22 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit}: BeneficialOwnersSte const [isEditingCreatedBeneficialOwner, setIsEditingCreatedBeneficialOwner] = useState(false); const [isUserUBO, setIsUserUBO] = useState(defaultValues.ownsMoreThan25Percent); const [isAnyoneElseUBO, setIsAnyoneElseUBO] = useState(defaultValues.hasOtherBeneficialOwners); - const [currentUBOSubStep, setCurrentUBOSubStep] = useState(1); const canAddMoreUBOS = beneficialOwnerKeys.length < (isUserUBO ? MAX_NUMBER_OF_UBOS - 1 : MAX_NUMBER_OF_UBOS); + const navigateToSubPage = useCallback( + (subPage: string) => { + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.BENEFICIAL_OWNERS, subPage})); + }, + [policyID], + ); + + const navigateBackToSubPage = useCallback( + (subPage: string) => { + Navigation.goBack(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.BENEFICIAL_OWNERS, subPage})); + }, + [policyID], + ); + const submit = () => { const beneficialOwnerFields = ['firstName', 'lastName', 'dob', 'ssnLast4', 'street', 'city', 'state', 'zipCode']; const beneficialOwners = beneficialOwnerKeys.map((ownerKey) => @@ -85,13 +99,11 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit}: BeneficialOwnersSte }; const addBeneficialOwner = (beneficialOwnerID: string) => { - // Each beneficial owner is assigned a unique key that will connect it to values in saved ONYX. - // That way we can dynamically render each Identity Form based on which keys are present in the beneficial owners array. const newBeneficialOwners = [...beneficialOwnerKeys, beneficialOwnerID]; - setBeneficialOwnerKeys(newBeneficialOwners); setDraftValues(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {beneficialOwners: JSON.stringify(newBeneficialOwners)}); }; + const handleBeneficialOwnerDetailsFormSubmit = () => { const shouldAddBeneficialOwner = !beneficialOwnerKeys.find((beneficialOwnerID) => beneficialOwnerID === beneficialOwnerBeingModifiedID) && canAddMoreUBOS; @@ -99,54 +111,35 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit}: BeneficialOwnersSte addBeneficialOwner(beneficialOwnerBeingModifiedID); } - // Because beneficialOwnerKeys array is not yet updated at this point we need to check against lower MAX_NUMBER_OF_UBOS (account for the one that is being added) const isLastUBOThatCanBeAdded = beneficialOwnerKeys.length === (isUserUBO ? MAX_NUMBER_OF_UBOS - 2 : MAX_NUMBER_OF_UBOS - 1); - setCurrentUBOSubStep(isEditingCreatedBeneficialOwner || isLastUBOThatCanBeAdded ? SUBSTEP.UBOS_LIST : SUBSTEP.ARE_THERE_MORE_UBOS); + const nextSubPage = isEditingCreatedBeneficialOwner || isLastUBOThatCanBeAdded ? SUB_PAGE_NAMES.UBOS_LIST : SUB_PAGE_NAMES.ARE_THERE_MORE_UBOS; setIsEditingCreatedBeneficialOwner(false); + navigateToSubPage(nextSubPage); }; - const { - componentToRender: BeneficialOwnerDetailsForm, - isEditing, - screenIndex, - nextScreen, - prevScreen, - moveTo, - resetScreenIndex, - goToTheLastStep, - // eslint-disable-next-line @typescript-eslint/no-deprecated - } = useSubStep({ - bodyContent, - startFrom: 0, - onFinished: handleBeneficialOwnerDetailsFormSubmit, - }); - const prepareBeneficialOwnerDetailsForm = () => { const beneficialOwnerID = Str.guid(); setBeneficialOwnerBeingModifiedID(beneficialOwnerID); - // Reset Beneficial Owner Details Form to first subStep - resetScreenIndex(); - setCurrentUBOSubStep(SUBSTEP.UBO_DETAILS_FORM); + navigateToSubPage(SUB_PAGE_NAMES.LEGAL_NAME); }; const handleNextUBOSubstep = (value: boolean) => { - if (currentUBOSubStep === SUBSTEP.IS_USER_UBO) { + if (currentSubPage === SUB_PAGE_NAMES.IS_USER_UBO) { setIsUserUBO(value); - // User is an owner but there are 4 other owners already added, so we remove last one if (value && beneficialOwnerKeys.length === 4) { setBeneficialOwnerKeys((previousBeneficialOwners) => previousBeneficialOwners.slice(0, 3)); } - setCurrentUBOSubStep(SUBSTEP.IS_ANYONE_ELSE_UBO); + navigateToSubPage(SUB_PAGE_NAMES.IS_ANYONE_ELSE_UBO); return; } - if (currentUBOSubStep === SUBSTEP.IS_ANYONE_ELSE_UBO) { + if (currentSubPage === SUB_PAGE_NAMES.IS_ANYONE_ELSE_UBO) { setIsAnyoneElseUBO(value); if (!canAddMoreUBOS && value) { - setCurrentUBOSubStep(SUBSTEP.UBOS_LIST); + navigateToSubPage(SUB_PAGE_NAMES.UBOS_LIST); return; } @@ -155,66 +148,61 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit}: BeneficialOwnersSte return; } - // User is not an owner and no one else is an owner if (!isUserUBO && !value) { submit(); return; } - // User is an owner and no one else is an owner if (isUserUBO && !value) { - setCurrentUBOSubStep(SUBSTEP.UBOS_LIST); + navigateToSubPage(SUB_PAGE_NAMES.UBOS_LIST); return; } } - // Are there more UBOs - if (currentUBOSubStep === SUBSTEP.ARE_THERE_MORE_UBOS) { + if (currentSubPage === SUB_PAGE_NAMES.ARE_THERE_MORE_UBOS) { if (value) { prepareBeneficialOwnerDetailsForm(); return; } - setCurrentUBOSubStep(SUBSTEP.UBOS_LIST); - return; - } - - // User reached the limit of UBOs - if (currentUBOSubStep === SUBSTEP.UBO_DETAILS_FORM && !canAddMoreUBOS) { - setCurrentUBOSubStep(SUBSTEP.UBOS_LIST); + navigateToSubPage(SUB_PAGE_NAMES.UBOS_LIST); } }; const handleBackButtonPress = () => { - if (isEditing) { - goToTheLastStep(); - return; - } - - // User goes back to previous step - if (currentUBOSubStep === SUBSTEP.IS_USER_UBO) { + if (currentSubPage === SUB_PAGE_NAMES.IS_USER_UBO) { onBackButtonPress(); - // User reached limit of UBOs and goes back to initial question about additional UBOs - } else if (currentUBOSubStep === SUBSTEP.UBOS_LIST && !canAddMoreUBOS) { - setCurrentUBOSubStep(SUBSTEP.IS_ANYONE_ELSE_UBO); - // User goes back to last radio button - } else if (currentUBOSubStep === SUBSTEP.UBOS_LIST && isAnyoneElseUBO) { - setCurrentUBOSubStep(SUBSTEP.ARE_THERE_MORE_UBOS); - } else if (currentUBOSubStep === SUBSTEP.UBOS_LIST && isUserUBO && !isAnyoneElseUBO) { - setCurrentUBOSubStep(SUBSTEP.IS_ANYONE_ELSE_UBO); - // User moves between subSteps of beneficial owner details form - } else if (currentUBOSubStep === SUBSTEP.UBO_DETAILS_FORM && screenIndex > 0) { - prevScreen(); + } else if (currentSubPage === SUB_PAGE_NAMES.IS_ANYONE_ELSE_UBO) { + navigateBackToSubPage(SUB_PAGE_NAMES.IS_USER_UBO); + } else if (currentSubPage === SUB_PAGE_NAMES.UBOS_LIST && !canAddMoreUBOS) { + navigateBackToSubPage(SUB_PAGE_NAMES.IS_ANYONE_ELSE_UBO); + } else if (currentSubPage === SUB_PAGE_NAMES.UBOS_LIST && isAnyoneElseUBO) { + navigateBackToSubPage(SUB_PAGE_NAMES.ARE_THERE_MORE_UBOS); + } else if (currentSubPage === SUB_PAGE_NAMES.UBOS_LIST && isUserUBO && !isAnyoneElseUBO) { + navigateBackToSubPage(SUB_PAGE_NAMES.IS_ANYONE_ELSE_UBO); } else { - setCurrentUBOSubStep((currentSubstep) => currentSubstep - 1); + Navigation.goBack(); } }; const handleUBOEdit = (beneficialOwnerID: string) => { setBeneficialOwnerBeingModifiedID(beneficialOwnerID); setIsEditingCreatedBeneficialOwner(true); - setCurrentUBOSubStep(SUBSTEP.UBO_DETAILS_FORM); + navigateToSubPage(SUB_PAGE_NAMES.LEGAL_NAME); }; + // If the current sub page is not an outer page, render the details form + if (currentSubPage && !OUTER_SUB_PAGES.has(currentSubPage)) { + return ( + + ); + } + return ( - {currentUBOSubStep === SUBSTEP.IS_USER_UBO && ( + {currentSubPage === SUB_PAGE_NAMES.IS_USER_UBO && ( )} - {currentUBOSubStep === SUBSTEP.IS_ANYONE_ELSE_UBO && ( + {currentSubPage === SUB_PAGE_NAMES.IS_ANYONE_ELSE_UBO && ( )} - {currentUBOSubStep === SUBSTEP.UBO_DETAILS_FORM && ( - - )} - - {currentUBOSubStep === SUBSTEP.ARE_THERE_MORE_UBOS && ( + {currentSubPage === SUB_PAGE_NAMES.ARE_THERE_MORE_UBOS && ( )} - {currentUBOSubStep === SUBSTEP.UBOS_LIST && ( + {currentSubPage === SUB_PAGE_NAMES.UBOS_LIST && ( > = [ - NameBusiness, - TaxIdBusiness, - WebsiteBusiness, - PhoneNumberBusiness, - AddressBusiness, - TypeBusiness, - IncorporationDateBusiness, - IncorporationStateBusiness, - IncorporationCode, - ConfirmationBusiness, +const pages = [ + {pageName: SUB_PAGE_NAMES.NAME, component: NameBusiness}, + {pageName: SUB_PAGE_NAMES.TAX_ID, component: TaxIdBusiness}, + {pageName: SUB_PAGE_NAMES.WEBSITE, component: WebsiteBusiness}, + {pageName: SUB_PAGE_NAMES.PHONE, component: PhoneNumberBusiness}, + {pageName: SUB_PAGE_NAMES.ADDRESS, component: AddressBusiness}, + {pageName: SUB_PAGE_NAMES.TYPE, component: TypeBusiness}, + {pageName: SUB_PAGE_NAMES.INCORPORATION_DATE, component: IncorporationDateBusiness}, + {pageName: SUB_PAGE_NAMES.INCORPORATION_STATE, component: IncorporationStateBusiness}, + {pageName: SUB_PAGE_NAMES.INCORPORATION_CODE, component: IncorporationCode}, + {pageName: SUB_PAGE_NAMES.CONFIRMATION, component: ConfirmationBusiness}, ]; function BusinessInfo({onBackButtonPress, onSubmit}: BusinessInfoProps) { @@ -88,34 +93,32 @@ function BusinessInfo({onBackButtonPress, onSubmit}: BusinessInfoProps) { const isBankAccountVerifying = reimbursementAccount?.achData?.state === CONST.BANK_ACCOUNT.STATE.VERIFYING; const startFrom = useMemo(() => (isBankAccountVerifying ? 0 : getInitialSubStepForBusinessInfo(values)), [values, isBankAccountVerifying]); - const { - componentToRender: SubStep, - isEditing, - screenIndex, - nextScreen, - prevScreen, - moveTo, - goToTheLastStep, - } = useSubStep({ - bodyContent, + const buildRoute = useCallback( + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.COMPANY, subPage: pageName, action}), + [policyID], + ); + + const {CurrentPage, isEditing, currentPageName, pageIndex, nextPage, prevPage, moveTo, isRedirecting} = useSubPage({ + pages, startFrom, onFinished: () => { submit(true); onSubmit?.(); }, - onNextSubStep: () => submit(false), + onPageChange: () => submit(false), + buildRoute, }); const handleBackButtonPress = () => { if (isEditing) { - goToTheLastStep(); + Navigation.goBack(buildRoute(SUB_PAGE_NAMES.CONFIRMATION)); return; } - if (screenIndex === 0) { + if (pageIndex === 0) { onBackButtonPress(); } else { - prevScreen(); + prevPage(); } }; @@ -129,11 +132,16 @@ function BusinessInfo({onBackButtonPress, onSubmit}: BusinessInfoProps) { startStepIndex={4} stepNames={CONST.BANK_ACCOUNT.STEP_NAMES} > - + {isRedirecting ? ( + + ) : ( + + )} ); } diff --git a/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx b/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx index 806f03df9e544..4cb778c2871f1 100644 --- a/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx +++ b/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx @@ -1,15 +1,16 @@ import React, {useCallback, useMemo} from 'react'; -import type {ComponentType} from 'react'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import useSubStep from '@hooks/useSubStep'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import useSubPage from '@hooks/useSubPage'; +import type {SubPageProps} from '@hooks/useSubPage/types'; +import Navigation from '@libs/Navigation/Navigation'; import {getBankAccountIDAsNumber} from '@libs/ReimbursementAccountUtils'; import getSubStepValues from '@pages/ReimbursementAccount/utils/getSubStepValues'; import {acceptACHContractForBankAccount} from '@userActions/BankAccounts'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; import ConfirmAgreements from './subSteps/ConfirmAgreements'; @@ -22,7 +23,10 @@ type CompleteVerificationProps = { }; const COMPLETE_VERIFICATION_KEYS = INPUT_IDS.COMPLETE_VERIFICATION; -const bodyContent: Array> = [ConfirmAgreements]; +const PAGE_NAMES = CONST.BANK_ACCOUNT.PAGE_NAMES; +const SUB_PAGE_NAMES = CONST.BANK_ACCOUNT.COMPLETE_VERIFICATION_STEP.SUB_PAGE_NAMES; + +const pages = [{pageName: SUB_PAGE_NAMES.CONFIRM_AGREEMENTS, component: ConfirmAgreements}]; function CompleteVerification({onBackButtonPress, onSubmit}: CompleteVerificationProps) { const {translate} = useLocalize(); @@ -49,19 +53,23 @@ function CompleteVerification({onBackButtonPress, onSubmit}: CompleteVerificatio onSubmit?.(); }, [bankAccountID, values.isAuthorizedToUseBankAccount, values.certifyTrueInformation, values.acceptTermsAndConditions, policyID, lastPaymentMethod, onSubmit]); - // eslint-disable-next-line @typescript-eslint/no-deprecated - const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo, goToTheLastStep} = useSubStep({bodyContent, startFrom: 0, onFinished: submit}); + const buildRoute = useCallback( + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.ACH_CONTRACT, subPage: pageName, action}), + [policyID], + ); + + const {CurrentPage, isEditing, pageIndex, nextPage, prevPage, moveTo} = useSubPage({pages, startFrom: 0, onFinished: submit, buildRoute}); const handleBackButtonPress = () => { if (isEditing) { - goToTheLastStep(); + Navigation.goBack(buildRoute(SUB_PAGE_NAMES.CONFIRM_AGREEMENTS)); return; } - if (screenIndex === 0) { + if (pageIndex === 0) { onBackButtonPress(); } else { - prevScreen(); + prevPage(); } }; @@ -75,9 +83,9 @@ function CompleteVerification({onBackButtonPress, onSubmit}: CompleteVerificatio startStepIndex={6} stepNames={CONST.BANK_ACCOUNT.STEP_NAMES} > - diff --git a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx index 2f42ebe194645..f4dcdef4cad37 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx @@ -1,17 +1,20 @@ import type {ForwardedRef} from 'react'; import React, {useCallback, useMemo} from 'react'; import type {View} from 'react-native'; +import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; -import useSubStep from '@hooks/useSubStep'; -import type {SubStepProps} from '@hooks/useSubStep/types'; +import useSubPage from '@hooks/useSubPage'; +import type {SubPageProps} from '@hooks/useSubPage/types'; +import Navigation from '@libs/Navigation/Navigation'; import {getBankAccountIDAsNumber} from '@libs/ReimbursementAccountUtils'; import getInitialSubStepForPersonalInfo from '@pages/ReimbursementAccount/USD/utils/getInitialSubStepForPersonalInfo'; import getSubStepValues from '@pages/ReimbursementAccount/utils/getSubStepValues'; import {updatePersonalInformationForBankAccount} from '@userActions/BankAccounts'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/ReimbursementAccountForm'; import Address from './subSteps/Address'; import Confirmation from './subSteps/Confirmation'; @@ -31,7 +34,16 @@ type PersonalInfoProps = { }; const PERSONAL_INFO_STEP_KEYS = INPUT_IDS.PERSONAL_INFO_STEP; -const bodyContent: Array> = [FullName, DateOfBirth, SocialSecurityNumber, Address, Confirmation]; +const PAGE_NAMES = CONST.BANK_ACCOUNT.PAGE_NAMES; +const SUB_PAGE_NAMES = CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.SUB_PAGE_NAMES; + +const pages = [ + {pageName: SUB_PAGE_NAMES.FULL_NAME, component: FullName}, + {pageName: SUB_PAGE_NAMES.DATE_OF_BIRTH, component: DateOfBirth}, + {pageName: SUB_PAGE_NAMES.SSN, component: SocialSecurityNumber}, + {pageName: SUB_PAGE_NAMES.ADDRESS, component: Address}, + {pageName: SUB_PAGE_NAMES.CONFIRMATION, component: Confirmation}, +]; function PersonalInfo({onBackButtonPress, onSubmit, ref}: PersonalInfoProps) { const {translate} = useLocalize(); @@ -51,34 +63,32 @@ function PersonalInfo({onBackButtonPress, onSubmit, ref}: PersonalInfoProps) { const isBankAccountVerifying = reimbursementAccount?.achData?.state === CONST.BANK_ACCOUNT.STATE.VERIFYING; const startFrom = useMemo(() => (isBankAccountVerifying ? 0 : getInitialSubStepForPersonalInfo(values)), [values, isBankAccountVerifying]); - const { - componentToRender: SubStep, - isEditing, - screenIndex, - nextScreen, - prevScreen, - moveTo, - goToTheLastStep, - } = useSubStep({ - bodyContent, + const buildRoute = useCallback( + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.REQUESTOR, subPage: pageName, action}), + [policyID], + ); + + const {CurrentPage, isEditing, currentPageName, pageIndex, nextPage, prevPage, moveTo, isRedirecting} = useSubPage({ + pages, startFrom, onFinished: () => { submit(true); onSubmit?.(); }, - onNextSubStep: () => submit(false), + onPageChange: () => submit(false), + buildRoute, }); const handleBackButtonPress = () => { if (isEditing) { - goToTheLastStep(); + Navigation.goBack(buildRoute(SUB_PAGE_NAMES.CONFIRMATION)); return; } - if (screenIndex === 0) { + if (pageIndex === 0) { onBackButtonPress(); } else { - prevScreen(); + prevPage(); } }; @@ -93,11 +103,16 @@ function PersonalInfo({onBackButtonPress, onSubmit, ref}: PersonalInfoProps) { startStepIndex={2} stepNames={CONST.BANK_ACCOUNT.STEP_NAMES} > - + {isRedirecting ? ( + + ) : ( + + )} ); } diff --git a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx index 6cd8d8517556d..ef3cb8051cc80 100644 --- a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx +++ b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx @@ -19,19 +19,46 @@ import RequestorStep from './Requestor/RequestorStep'; import type USDPageProps from './types'; const PAGE_NAMES = CONST.BANK_ACCOUNT.PAGE_NAMES; +const BANK_INFO_SUB_PAGES = CONST.BANK_ACCOUNT.BANK_INFO_STEP.SUB_PAGE_NAMES; +const PERSONAL_INFO_SUB_PAGES = CONST.BANK_ACCOUNT.PERSONAL_INFO_STEP.SUB_PAGE_NAMES; +const BUSINESS_INFO_SUB_PAGES = CONST.BANK_ACCOUNT.BUSINESS_INFO_STEP.SUB_PAGE_NAMES; +const BENEFICIAL_OWNERS_SUB_PAGES = CONST.BANK_ACCOUNT.BENEFICIAL_OWNERS_STEP.SUB_PAGE_NAMES; +const COMPLETE_VERIFICATION_SUB_PAGES = CONST.BANK_ACCOUNT.COMPLETE_VERIFICATION_STEP.SUB_PAGE_NAMES; type PageEntry = { pageName: string; component: React.ComponentType; + firstSubPage?: string; + lastSubPage?: string; }; const pages: PageEntry[] = [ {pageName: PAGE_NAMES.COUNTRY, component: Country as React.ComponentType}, - {pageName: PAGE_NAMES.BANK_ACCOUNT, component: BankInfo as React.ComponentType}, - {pageName: PAGE_NAMES.REQUESTOR, component: RequestorStep as React.ComponentType}, - {pageName: PAGE_NAMES.COMPANY, component: BusinessInfo as React.ComponentType}, - {pageName: PAGE_NAMES.BENEFICIAL_OWNERS, component: BeneficialOwnersStep as React.ComponentType}, - {pageName: PAGE_NAMES.ACH_CONTRACT, component: CompleteVerification as React.ComponentType}, + {pageName: PAGE_NAMES.BANK_ACCOUNT, component: BankInfo as React.ComponentType, firstSubPage: BANK_INFO_SUB_PAGES.PLAID, lastSubPage: BANK_INFO_SUB_PAGES.PLAID}, + { + pageName: PAGE_NAMES.REQUESTOR, + component: RequestorStep as React.ComponentType, + firstSubPage: PERSONAL_INFO_SUB_PAGES.FULL_NAME, + lastSubPage: PERSONAL_INFO_SUB_PAGES.CONFIRMATION, + }, + { + pageName: PAGE_NAMES.COMPANY, + component: BusinessInfo as React.ComponentType, + firstSubPage: BUSINESS_INFO_SUB_PAGES.NAME, + lastSubPage: BUSINESS_INFO_SUB_PAGES.CONFIRMATION, + }, + { + pageName: PAGE_NAMES.BENEFICIAL_OWNERS, + component: BeneficialOwnersStep as React.ComponentType, + firstSubPage: BENEFICIAL_OWNERS_SUB_PAGES.IS_USER_UBO, + lastSubPage: BENEFICIAL_OWNERS_SUB_PAGES.UBOS_LIST, + }, + { + pageName: PAGE_NAMES.ACH_CONTRACT, + component: CompleteVerification as React.ComponentType, + firstSubPage: COMPLETE_VERIFICATION_SUB_PAGES.CONFIRM_AGREEMENTS, + lastSubPage: COMPLETE_VERIFICATION_SUB_PAGES.CONFIRM_AGREEMENTS, + }, {pageName: PAGE_NAMES.VALIDATION, component: ConnectBankAccount as React.ComponentType}, ]; @@ -63,7 +90,7 @@ function USDVerifiedBankAccountFlowPage({route}: USDVerifiedBankAccountFlowPageP return; } const nextPage = pages.at(nextIndex); - Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: nextPage?.pageName})); + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: nextPage?.pageName, subPage: nextPage?.firstSubPage})); }, [currentPageIndex, policyID]); const onBackButtonPress = useCallback(() => { @@ -73,7 +100,7 @@ function USDVerifiedBankAccountFlowPage({route}: USDVerifiedBankAccountFlowPageP return; } const prevPage = pages.at(prevIndex); - Navigation.goBack(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: prevPage?.pageName})); + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: prevPage?.pageName, subPage: prevPage?.lastSubPage})); }, [currentPageIndex, policyID]); const shouldShowOnfido = !!(onfidoToken && !reimbursementAccount?.achData?.isOnfidoSetupComplete); From 1879cc646e6218fa7c47c4db56f2a5be6dbf7d2d Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 26 Mar 2026 10:19:25 +0100 Subject: [PATCH 08/20] fix: delay focus on inputs --- .../SocialSecurityNumberUBO.tsx | 1 + .../USD/BusinessInfo/subSteps/NameBusiness.tsx | 1 + .../USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx | 1 + .../USD/BusinessInfo/subSteps/TaxIdBusiness.tsx | 1 + .../USD/BusinessInfo/subSteps/WebsiteBusiness.tsx | 1 + .../USD/Requestor/PersonalInfo/subSteps/SocialSecurityNumber.tsx | 1 + 6 files changed, 6 insertions(+) diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/SocialSecurityNumberUBO.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/SocialSecurityNumberUBO.tsx index 94fbc06fe636a..2df5a39d837db 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/SocialSecurityNumberUBO.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/SocialSecurityNumberUBO.tsx @@ -54,6 +54,7 @@ function SocialSecurityNumberUBO({onNext, onMove, isEditing, beneficialOwnerBein defaultValue={defaultSsnLast4} shouldShowHelpLinks={false} maxLength={CONST.BANK_ACCOUNT.MAX_LENGTH.SSN} + shouldDelayAutoFocus /> ); } diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/NameBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/NameBusiness.tsx index 1156f7fd54571..fd819f39875da 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/NameBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/NameBusiness.tsx @@ -63,6 +63,7 @@ function NameBusiness({onNext, onMove, isEditing}: SubPageProps) { shouldUseDefaultValue={shouldDisableCompanyName} disabled={shouldDisableCompanyName} shouldShowHelpLinks={false} + shouldDelayAutoFocus /> ); } diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx index 6fa565649d4c5..85dec7f7c1f04 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/PhoneNumberBusiness.tsx @@ -67,6 +67,7 @@ function PhoneNumberBusiness({onNext, onMove, isEditing}: SubPageProps) { defaultValue={defaultCompanyPhoneNumber} shouldShowHelpLinks={false} placeholder={translate('common.phoneNumberPlaceholder')} + shouldDelayAutoFocus /> ); } diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TaxIdBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TaxIdBusiness.tsx index 18e77e094113d..5e3e9b13f73e6 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TaxIdBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/TaxIdBusiness.tsx @@ -77,6 +77,7 @@ function TaxIdBusiness({onNext, onMove, isEditing}: SubPageProps) { shouldShowHelpLinks={false} placeholder={translate('businessInfoStep.taxIDNumberPlaceholder')} inputMode={CONST.INPUT_MODE.NUMERIC} + shouldDelayAutoFocus /> ); } diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx index 7c83dc7bbb518..7214ee4aa6879 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/WebsiteBusiness.tsx @@ -74,6 +74,7 @@ function WebsiteBusiness({onNext, onMove, isEditing}: SubPageProps) { defaultValue={defaultCompanyWebsite} inputMode={CONST.INPUT_MODE.URL} shouldShowHelpLinks={false} + shouldDelayAutoFocus /> ); } diff --git a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/SocialSecurityNumber.tsx b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/SocialSecurityNumber.tsx index 97d7bc35638ac..6e7384be05abc 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/SocialSecurityNumber.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/subSteps/SocialSecurityNumber.tsx @@ -68,6 +68,7 @@ function SocialSecurityNumber({onNext, onMove, isEditing}: SubPageProps) { maxLength={CONST.BANK_ACCOUNT.MAX_LENGTH.SSN} enabledWhenOffline forwardedFSClass={CONST.FULLSTORY.CLASS.MASK} + shouldDelayAutoFocus /> ); } From 8019251ef30072507e515a3efafa2ecf440e9525 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 26 Mar 2026 14:06:41 +0100 Subject: [PATCH 09/20] fix: focus for industry step --- .../IndustryCode/IndustryCodeSelector.tsx | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IndustryCode/IndustryCodeSelector.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IndustryCode/IndustryCodeSelector.tsx index 113bd42714d6b..9876116569111 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IndustryCode/IndustryCodeSelector.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/subSteps/IndustryCode/IndustryCodeSelector.tsx @@ -1,9 +1,11 @@ -import React, {useEffect, useMemo, useState} from 'react'; +import React, {useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/ListItem/RadioListItem'; +import type {ListItem, SelectionListHandle} from '@components/SelectionList/types'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import CONST from '@src/CONST'; import {ALL_NAICS, NAICS, NAICS_MAPPING_WITH_ID} from '@src/NAICS'; type IndustryCodeSelectorProps = { @@ -14,11 +16,22 @@ type IndustryCodeSelectorProps = { function IndustryCodeSelector({onInputChange, value, errorText}: IndustryCodeSelectorProps) { const styles = useThemeStyles(); + const selectionListRef = useRef>(null); const [searchValue, setSearchValue] = useState(value); + const [isReady, setIsReady] = useState(false); const [shouldDisplayChildItems, setShouldDisplayChildItems] = useState(false); const {translate} = useLocalize(); + useEffect(() => { + const timeout = setTimeout(() => { + setIsReady(true); + selectionListRef.current?.focusTextInput(); + }, CONST.ANIMATED_TRANSITION); + + return () => clearTimeout(timeout); + }, []); + const codeOptions = useMemo(() => { if (!searchValue) { return NAICS.map((item) => { @@ -62,6 +75,7 @@ function IndustryCodeSelector({onInputChange, value, errorText}: IndustryCodeSel onInputChange?.(val); }, value: searchValue, + disableAutoFocus: true, errorText, }), [errorText, onInputChange, searchValue, translate], @@ -70,7 +84,8 @@ function IndustryCodeSelector({onInputChange, value, errorText}: IndustryCodeSel return ( { setSearchValue(item.value); From 11ab86b10d24dc900a52b9b9594b8328556cb49d Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Thu, 26 Mar 2026 19:34:57 +0100 Subject: [PATCH 10/20] fix: navigation conflicting route names --- src/ROUTES.ts | 24 ++++++------- src/components/Navigation/DebugTabView.tsx | 5 +-- src/libs/Navigation/types.ts | 2 +- .../ReimbursementAccountPage.tsx | 35 +++++++------------ .../ReimbursementAccountVerifyAccountPage.tsx | 3 +- .../USD/BankInfo/BankInfo.tsx | 2 +- .../BeneficialOwnerDetailsFormPages.tsx | 2 +- .../BeneficialOwnersStep.tsx | 4 +-- .../USD/BusinessInfo/BusinessInfo.tsx | 2 +- .../CompleteVerification.tsx | 2 +- .../Requestor/PersonalInfo/PersonalInfo.tsx | 2 +- .../VerifiedBankAccountFlowEntryPoint.tsx | 2 +- .../WorkspaceExpensifyCardBankAccounts.tsx | 1 - .../WorkspaceExpensifyCardPageEmptyState.tsx | 1 - .../WorkspaceTravelInvoicingSection.tsx | 1 - ...ceTravelInvoicingSettlementAccountPage.tsx | 1 - 16 files changed, 35 insertions(+), 54 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 0c8a6d77a5d30..44cc35404b5c9 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -268,36 +268,32 @@ const ROUTES = { // eslint-disable-next-line no-restricted-syntax -- Legacy route generation getRoute: (policyID?: string, backTo?: string) => getUrlWithBackToParam(`bank-account/${VERIFY_ACCOUNT}?policyID=${policyID}`, backTo), }, - BANK_ACCOUNT_NEW: 'bank-account/new', BANK_ACCOUNT_PERSONAL: 'bank-account/personal', + // TODO: rename the route as no longer accepts step BANK_ACCOUNT_WITH_STEP_TO_OPEN: { - route: 'bank-account/:stepToOpen?', + route: 'bank-account/new', getRoute: ({ policyID, - stepToOpen = '', bankAccountID, backTo, - subStepToOpen, }: { policyID: string | undefined; - stepToOpen?: ReimbursementAccountStepToOpen; bankAccountID?: number; backTo?: string; - subStepToOpen?: typeof CONST.BANK_ACCOUNT.STEP.COUNTRY; }) => { if (!policyID && !bankAccountID) { // eslint-disable-next-line no-restricted-syntax -- Legacy route generation - return getUrlWithBackToParam(`bank-account/${stepToOpen}`, backTo); + return getUrlWithBackToParam(`bank-account/new`, backTo); } if (bankAccountID) { // eslint-disable-next-line no-restricted-syntax -- Legacy route generation - return getUrlWithBackToParam(`bank-account/${stepToOpen}?bankAccountID=${bankAccountID}`, backTo); + return getUrlWithBackToParam(`bank-account/new?bankAccountID=${bankAccountID}`, backTo); } // TODO this backTo comes from drilling it through bank account form screens // should be removed once https://github.com/Expensify/App/pull/72219 is resolved // eslint-disable-next-line no-restricted-syntax -- Legacy route generation - return getUrlWithBackToParam(`bank-account/${stepToOpen}?policyID=${policyID}${subStepToOpen ? `&subStep=${subStepToOpen}` : ''}`, backTo); + return getUrlWithBackToParam(`bank-account/new?policyID=${policyID}`, backTo); }, }, BANK_ACCOUNT_ENTER_SIGNER_INFO: { @@ -330,16 +326,16 @@ const ROUTES = { }, }, BANK_ACCOUNT_USD_SETUP: { - route: 'bank-account/us/:step?/:subPage?/:action?', + route: 'bank-account/new/us/:step?/:subPage?/:action?', // eslint-disable-next-line no-restricted-syntax -- Legacy route generation - getRoute: ({policyID, step, subPage, action, backTo}: {policyID?: string; step?: string; subPage?: string; action?: 'edit'; backTo?: string}) => { - const base = 'bank-account/us'; - const stepPart = step ? `/${step}` : ''; + getRoute: ({policyID, page, subPage, action, backTo}: {policyID?: string; page?: string; subPage?: string; action?: 'edit'; backTo?: string}) => { + const base = 'bank-account/new/us'; + const pagePart = page ? `/${page}` : ''; const subStepPart = subPage ? `/${subPage}` : ''; const actionPart = action ? `/${action}` : ''; const queryString = policyID ? `?policyID=${policyID}` : ''; // eslint-disable-next-line no-restricted-syntax -- Legacy route generation - return getUrlWithBackToParam(`${base}${stepPart}${subStepPart}${actionPart}${queryString}`, backTo); + return getUrlWithBackToParam(`${base}${pagePart}${subStepPart}${actionPart}${queryString}`, backTo); }, }, SETTINGS: 'settings', diff --git a/src/components/Navigation/DebugTabView.tsx b/src/components/Navigation/DebugTabView.tsx index 95ecf5ec7d0d1..d8a84247bd0f3 100644 --- a/src/components/Navigation/DebugTabView.tsx +++ b/src/components/Navigation/DebugTabView.tsx @@ -80,10 +80,7 @@ function getSettingsRoute(status: IndicatorStatus | undefined, reimbursementAcco case CONST.INDICATOR_STATUS.HAS_POLICY_ERRORS: return ROUTES.WORKSPACE_INITIAL.getRoute(policyIDWithErrors); case CONST.INDICATOR_STATUS.HAS_REIMBURSEMENT_ACCOUNT_ERRORS: - return ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute({ - policyID: reimbursementAccount?.achData?.policyID, - stepToOpen: getReimbursementAccountRouteForCurrentStep(reimbursementAccount?.achData?.currentStep ?? CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT), - }); + return ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute({policyID: reimbursementAccount?.achData?.policyID}); case CONST.INDICATOR_STATUS.HAS_SUBSCRIPTION_ERRORS: return ROUTES.SETTINGS_SUBSCRIPTION.route; case CONST.INDICATOR_STATUS.HAS_SUBSCRIPTION_INFO: diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 4630ca69b2f9d..742739a9978e7 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -2252,7 +2252,7 @@ type ReimbursementAccountNavigatorParamList = { subStep?: typeof CONST.BANK_ACCOUNT.STEP.COUNTRY; }; [SCREENS.REIMBURSEMENT_ACCOUNT_USD]: { - step?: string; + page?: string; subPage?: string; action?: 'edit'; policyID?: string; diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx index bd4864c0ca8f8..00d88d7145739 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx @@ -60,7 +60,6 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; import ConnectedVerifiedBankAccount from './ConnectedVerifiedBankAccount'; import getStartPageForContinueSetup from './NonUSD/utils/getStartPageForContinueSetup'; -import USDVerifiedBankAccountFlow from './USD/USDVerifiedBankAccountFlow'; import getFieldsForStep from './USD/utils/getFieldsForStep'; import getStepToOpenFromRouteParams from './USD/utils/getStepToOpenFromRouteParams'; import VerifiedBankAccountFlowEntryPoint from './VerifiedBankAccountFlowEntryPoint'; @@ -77,7 +76,7 @@ const OFFLINE_ACCESSIBLE_STEPS = [ CONST.BANK_ACCOUNT.STEP.ACH_CONTRACT, ] as const; -function ReimbursementAccountPage({route, policy, isLoadingPolicy, navigation}: ReimbursementAccountPageProps) { +function ReimbursementAccountPage({route, policy, isLoadingPolicy}: ReimbursementAccountPageProps) { const {environmentURL} = useEnvironment(); const session = useSession(); const [reimbursementAccount, reimbursementAccountMetadata] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); @@ -333,10 +332,6 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy, navigation}: // so we don't clear it. We only want to clear the errors if we are moving between steps. hideBankAccountErrors(); } - - // Use the current page navigation object to set the param to the correct route in the stack - const stepToOpen = getRouteForCurrentStep(currentStep); - navigation.setParams({stepToOpen}); }, // eslint-disable-next-line react-hooks/exhaustive-deps [isOffline, reimbursementAccount?.draftStep, reimbursementAccount?.pendingAction, reimbursementAccount?.isLoading, hasACHDataBeenLoaded, shouldShowContinueSetupButton, currentStep], @@ -347,9 +342,19 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy, navigation}: // so we're always showing manual setup with locked numbers he can not change setBankAccountSubStep(CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL).then(() => { setShouldShowContinueSetupButton(false); - setUSDBankAccountStep(currentStep); + const stepToPageName: Record = { + [CONST.BANK_ACCOUNT.STEP.COUNTRY]: CONST.BANK_ACCOUNT.PAGE_NAMES.COUNTRY, + [CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT]: CONST.BANK_ACCOUNT.PAGE_NAMES.BANK_ACCOUNT, + [CONST.BANK_ACCOUNT.STEP.REQUESTOR]: CONST.BANK_ACCOUNT.PAGE_NAMES.REQUESTOR, + [CONST.BANK_ACCOUNT.STEP.COMPANY]: CONST.BANK_ACCOUNT.PAGE_NAMES.COMPANY, + [CONST.BANK_ACCOUNT.STEP.BENEFICIAL_OWNERS]: CONST.BANK_ACCOUNT.PAGE_NAMES.BENEFICIAL_OWNERS, + [CONST.BANK_ACCOUNT.STEP.ACH_CONTRACT]: CONST.BANK_ACCOUNT.PAGE_NAMES.ACH_CONTRACT, + [CONST.BANK_ACCOUNT.STEP.VALIDATION]: CONST.BANK_ACCOUNT.PAGE_NAMES.VALIDATION, + }; + const page = stepToPageName[currentStep] ?? CONST.BANK_ACCOUNT.PAGE_NAMES.COUNTRY; + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID: policyIDParam, page})); }); - }, [currentStep]); + }, [currentStep, policyIDParam]); const continueNonUSDVBBASetup = () => { const {page: startPage, subPage: startSubPage} = getStartPageForContinueSetup(achData, nonUSDCountryDraftValue, policyCurrency, reimbursementAccountDraft); @@ -519,20 +524,6 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy, navigation}: ); } - if (!isNonUSDSetup && USDBankAccountStep !== null) { - return ( - - ); - } - return ( { - Navigation.goBack(ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute({policyID, backTo, subStepToOpen: CONST.BANK_ACCOUNT.STEP.COUNTRY}), {compareParams: false}); + // TODO: check if it's not breaking + Navigation.goBack(ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute({policyID, backTo}), {compareParams: false}); }} /> ); diff --git a/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx b/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx index cc29017e0e503..298937afc2a81 100644 --- a/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx @@ -90,7 +90,7 @@ function BankInfo({onBackButtonPress, onSubmit, policyID}: BankInfoProps) { const pages = setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID ? plaidPages : manualPages; const buildRoute = useCallback( - (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.BANK_ACCOUNT, subPage: pageName, action}), + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BANK_ACCOUNT, subPage: pageName, action}), [policyID], ); diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormPages.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormPages.tsx index 615755500baea..0334b3c3c24cb 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormPages.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormPages.tsx @@ -56,7 +56,7 @@ function BeneficialOwnerDetailsFormPages({ const {translate} = useLocalize(); const buildRoute = useCallback( - (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.BENEFICIAL_OWNERS, subPage: pageName, action}), + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BENEFICIAL_OWNERS, subPage: pageName, action}), [policyID], ); diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx index d89e2d11bcaf6..29c5eb619f811 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx @@ -62,14 +62,14 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli const navigateToSubPage = useCallback( (subPage: string) => { - Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.BENEFICIAL_OWNERS, subPage})); + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BENEFICIAL_OWNERS, subPage})); }, [policyID], ); const navigateBackToSubPage = useCallback( (subPage: string) => { - Navigation.goBack(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.BENEFICIAL_OWNERS, subPage})); + Navigation.goBack(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BENEFICIAL_OWNERS, subPage})); }, [policyID], ); diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx index b7d133f7acfc5..4b6bb26b8b23d 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx @@ -94,7 +94,7 @@ function BusinessInfo({onBackButtonPress, onSubmit}: BusinessInfoProps) { const startFrom = useMemo(() => (isBankAccountVerifying ? 0 : getInitialSubStepForBusinessInfo(values)), [values, isBankAccountVerifying]); const buildRoute = useCallback( - (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.COMPANY, subPage: pageName, action}), + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.COMPANY, subPage: pageName, action}), [policyID], ); diff --git a/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx b/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx index 4cb778c2871f1..2a50872c3fcff 100644 --- a/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx +++ b/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx @@ -54,7 +54,7 @@ function CompleteVerification({onBackButtonPress, onSubmit}: CompleteVerificatio }, [bankAccountID, values.isAuthorizedToUseBankAccount, values.certifyTrueInformation, values.acceptTermsAndConditions, policyID, lastPaymentMethod, onSubmit]); const buildRoute = useCallback( - (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.ACH_CONTRACT, subPage: pageName, action}), + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.ACH_CONTRACT, subPage: pageName, action}), [policyID], ); diff --git a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx index f4dcdef4cad37..aa6b3ebf7d1c7 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx @@ -64,7 +64,7 @@ function PersonalInfo({onBackButtonPress, onSubmit, ref}: PersonalInfoProps) { const startFrom = useMemo(() => (isBankAccountVerifying ? 0 : getInitialSubStepForPersonalInfo(values)), [values, isBankAccountVerifying]); const buildRoute = useCallback( - (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: PAGE_NAMES.REQUESTOR, subPage: pageName, action}), + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.REQUESTOR, subPage: pageName, action}), [policyID], ); diff --git a/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx b/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx index d9df2f702e81b..2f9f27310b6e7 100644 --- a/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx +++ b/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx @@ -126,7 +126,7 @@ function VerifiedBankAccountFlowEntryPoint({ goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.COUNTRY); Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: CONST.BANK_ACCOUNT.STEP.COUNTRY})); }, - [setUSDBankAccountStep, policyID], + [policyID], ); /** diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx index ff3f23995a316..a1c3f6d4d21b7 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx @@ -66,7 +66,6 @@ function WorkspaceExpensifyCardBankAccounts({route}: WorkspaceExpensifyCardBankA Navigation.navigate( ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute({ policyID, - stepToOpen: REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.NEW, backTo: ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID), }), ); diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx index 9e919333f8c46..3febbdbf28aa8 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx @@ -69,7 +69,6 @@ function WorkspaceExpensifyCardPageEmptyState({route, policy}: WorkspaceExpensif Navigation.navigate( ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute({ policyID: policy?.id, - stepToOpen: REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.NEW, backTo: ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policy?.id), }), ); diff --git a/src/pages/workspace/travel/WorkspaceTravelInvoicingSection.tsx b/src/pages/workspace/travel/WorkspaceTravelInvoicingSection.tsx index b54d7951346dc..5e0521ccdfd3b 100644 --- a/src/pages/workspace/travel/WorkspaceTravelInvoicingSection.tsx +++ b/src/pages/workspace/travel/WorkspaceTravelInvoicingSection.tsx @@ -167,7 +167,6 @@ function WorkspaceTravelInvoicingSection({policyID}: WorkspaceTravelInvoicingSec Navigation.navigate( ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute({ policyID, - stepToOpen: REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.NEW, backTo: ROUTES.WORKSPACE_TRAVEL.getRoute(policyID), }), ); diff --git a/src/pages/workspace/travel/WorkspaceTravelInvoicingSettlementAccountPage.tsx b/src/pages/workspace/travel/WorkspaceTravelInvoicingSettlementAccountPage.tsx index 1203dfce00b20..5923dfe9d5d43 100644 --- a/src/pages/workspace/travel/WorkspaceTravelInvoicingSettlementAccountPage.tsx +++ b/src/pages/workspace/travel/WorkspaceTravelInvoicingSettlementAccountPage.tsx @@ -97,7 +97,6 @@ function WorkspaceTravelInvoicingSettlementAccountPage({route}: WorkspaceTravelI Navigation.navigate( ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute({ policyID, - stepToOpen: REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.NEW, backTo: ROUTES.WORKSPACE_TRAVEL_SETTINGS_ACCOUNT.getRoute(policyID), }), ); From ab5534a48c2f6594a802eb49435038713511b565 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Fri, 27 Mar 2026 11:05:21 +0100 Subject: [PATCH 11/20] fix: handle backTo param --- src/ROUTES.ts | 6 +++--- .../ReimbursementAccountPage.tsx | 6 +++--- .../USD/BankInfo/BankInfo.tsx | 9 ++++++--- .../BeneficialOwnerDetailsFormPages.tsx | 8 ++++++-- .../BeneficialOwnerInfo/BeneficialOwnersStep.tsx | 14 +++++++++----- .../USD/BusinessInfo/BusinessInfo.tsx | 9 ++++++--- .../CompleteVerification.tsx | 9 ++++++--- .../USD/Requestor/PersonalInfo/PersonalInfo.tsx | 9 ++++++--- .../USD/Requestor/RequestorStep.tsx | 6 +++++- .../USD/USDVerifiedBankAccountFlowPage.tsx | 16 +++++++++------- src/pages/ReimbursementAccount/USD/types.ts | 4 ++++ .../VerifiedBankAccountFlowEntryPoint.tsx | 4 ++-- 12 files changed, 65 insertions(+), 35 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 728e4c7a5dae6..caedca668ef30 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -326,16 +326,16 @@ const ROUTES = { }, }, BANK_ACCOUNT_USD_SETUP: { - route: 'bank-account/new/us/:step?/:subPage?/:action?', + route: 'bank-account/new/us/:page?/:subPage?/:action?', // eslint-disable-next-line no-restricted-syntax -- Legacy route generation getRoute: ({policyID, page, subPage, action, backTo}: {policyID?: string; page?: string; subPage?: string; action?: 'edit'; backTo?: string}) => { const base = 'bank-account/new/us'; const pagePart = page ? `/${page}` : ''; - const subStepPart = subPage ? `/${subPage}` : ''; + const subPagePart = subPage ? `/${subPage}` : ''; const actionPart = action ? `/${action}` : ''; const queryString = policyID ? `?policyID=${policyID}` : ''; // eslint-disable-next-line no-restricted-syntax -- Legacy route generation - return getUrlWithBackToParam(`${base}${pagePart}${subStepPart}${actionPart}${queryString}`, backTo); + return getUrlWithBackToParam(`${base}${pagePart}${subPagePart}${actionPart}${queryString}`, backTo); }, }, SETTINGS: 'settings', diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx index c7c4156ebe556..942275f42a8c3 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx @@ -28,7 +28,7 @@ import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {ReimbursementAccountNavigatorParamList} from '@libs/Navigation/types'; import {goBackFromInvalidPolicy, isPendingDeletePolicy, isPolicyAdmin} from '@libs/PolicyUtils'; -import {getRouteForCurrentStep, hasInProgressUSDVBBA, hasInProgressVBBA} from '@libs/ReimbursementAccountUtils'; +import {hasInProgressUSDVBBA, hasInProgressVBBA} from '@libs/ReimbursementAccountUtils'; import shouldReopenOnfido from '@libs/shouldReopenOnfido'; import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan'; import {isFullScreenName} from '@navigation/helpers/isNavigatorName'; @@ -352,9 +352,9 @@ function ReimbursementAccountPage({route, policy, isLoadingPolicy}: Reimbursemen [CONST.BANK_ACCOUNT.STEP.VALIDATION]: CONST.BANK_ACCOUNT.PAGE_NAMES.VALIDATION, }; const page = stepToPageName[currentStep] ?? CONST.BANK_ACCOUNT.PAGE_NAMES.COUNTRY; - Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID: policyIDParam, page})); + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID: policyIDParam, page, backTo})); }); - }, [currentStep, policyIDParam]); + }, [currentStep, policyIDParam, backTo]); const continueNonUSDVBBASetup = () => { const {page: startPage, subPage: startSubPage} = getStartPageForContinueSetup(achData, nonUSDCountryDraftValue, policyCurrency, reimbursementAccountDraft); diff --git a/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx b/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx index 298937afc2a81..67e84f7d29944 100644 --- a/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx @@ -26,6 +26,9 @@ type BankInfoProps = { /** Current Policy ID */ policyID: string; + + /** Back to URL for preserving navigation context */ + backTo?: string; }; const BANK_INFO_STEP_KEYS = INPUT_IDS.BANK_INFO_STEP; @@ -36,7 +39,7 @@ const receivedRedirectURI = getPlaidOAuthReceivedRedirectURI(); const manualPages = [{pageName: SUB_PAGE_NAMES.MANUAL, component: Manual}]; const plaidPages = [{pageName: SUB_PAGE_NAMES.PLAID, component: Plaid}]; -function BankInfo({onBackButtonPress, onSubmit, policyID}: BankInfoProps) { +function BankInfo({onBackButtonPress, onSubmit, policyID, backTo}: BankInfoProps) { const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); const [plaidLinkToken] = useOnyx(ONYXKEYS.PLAID_LINK_TOKEN); @@ -90,8 +93,8 @@ function BankInfo({onBackButtonPress, onSubmit, policyID}: BankInfoProps) { const pages = setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID ? plaidPages : manualPages; const buildRoute = useCallback( - (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BANK_ACCOUNT, subPage: pageName, action}), - [policyID], + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BANK_ACCOUNT, subPage: pageName, action, backTo}), + [policyID, backTo], ); const {CurrentPage, isEditing, pageIndex, nextPage, prevPage, moveTo} = useSubPage({pages, startFrom: 0, onFinished: submit, buildRoute}); diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormPages.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormPages.tsx index 0334b3c3c24cb..5be519b3f65b4 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormPages.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnerDetailsFormPages.tsx @@ -44,6 +44,9 @@ type BeneficialOwnerDetailsFormPagesProps = { /** Callback triggered after the last form page is completed */ onFinished: () => void; + + /** Back to URL for preserving navigation context */ + backTo?: string; }; function BeneficialOwnerDetailsFormPages({ @@ -52,12 +55,13 @@ function BeneficialOwnerDetailsFormPages({ setBeneficialOwnerBeingModifiedID, isEditingCreatedBeneficialOwner, onFinished, + backTo, }: BeneficialOwnerDetailsFormPagesProps) { const {translate} = useLocalize(); const buildRoute = useCallback( - (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BENEFICIAL_OWNERS, subPage: pageName, action}), - [policyID], + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BENEFICIAL_OWNERS, subPage: pageName, action, backTo}), + [policyID, backTo], ); const {CurrentPage, isEditing, currentPageName, pageIndex, prevPage, nextPage, moveTo, isRedirecting} = useSubPage({ diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx index 29c5eb619f811..2a9babb395574 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx @@ -28,6 +28,9 @@ type BeneficialOwnersStepProps = { /** ID of current policy */ policyID?: string; + + /** Back to URL for preserving navigation context */ + backTo?: string; }; const PAGE_NAMES = CONST.BANK_ACCOUNT.PAGE_NAMES; @@ -36,7 +39,7 @@ const MAX_NUMBER_OF_UBOS = 4; const OUTER_SUB_PAGES = new Set([SUB_PAGE_NAMES.IS_USER_UBO, SUB_PAGE_NAMES.IS_ANYONE_ELSE_UBO, SUB_PAGE_NAMES.ARE_THERE_MORE_UBOS, SUB_PAGE_NAMES.UBOS_LIST]); -function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, policyID}: BeneficialOwnersStepProps) { +function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, policyID, backTo}: BeneficialOwnersStepProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); @@ -62,16 +65,16 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli const navigateToSubPage = useCallback( (subPage: string) => { - Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BENEFICIAL_OWNERS, subPage})); + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BENEFICIAL_OWNERS, subPage, backTo})); }, - [policyID], + [policyID, backTo], ); const navigateBackToSubPage = useCallback( (subPage: string) => { - Navigation.goBack(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BENEFICIAL_OWNERS, subPage})); + Navigation.goBack(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BENEFICIAL_OWNERS, subPage, backTo})); }, - [policyID], + [policyID, backTo], ); const submit = () => { @@ -199,6 +202,7 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli setBeneficialOwnerBeingModifiedID={setBeneficialOwnerBeingModifiedID} isEditingCreatedBeneficialOwner={isEditingCreatedBeneficialOwner} onFinished={handleBeneficialOwnerDetailsFormSubmit} + backTo={backTo} /> ); } diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx index 4b6bb26b8b23d..ef2e7262be071 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx @@ -35,6 +35,9 @@ type BusinessInfoProps = { /** Handles submit button press (URL-based navigation) */ onSubmit?: () => void; + + /** Back to URL for preserving navigation context */ + backTo?: string; }; const BUSINESS_INFO_STEP_KEYS = INPUT_IDS.BUSINESS_INFO_STEP; @@ -54,7 +57,7 @@ const pages = [ {pageName: SUB_PAGE_NAMES.CONFIRMATION, component: ConfirmationBusiness}, ]; -function BusinessInfo({onBackButtonPress, onSubmit}: BusinessInfoProps) { +function BusinessInfo({onBackButtonPress, onSubmit, backTo}: BusinessInfoProps) { const {translate} = useLocalize(); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); @@ -94,8 +97,8 @@ function BusinessInfo({onBackButtonPress, onSubmit}: BusinessInfoProps) { const startFrom = useMemo(() => (isBankAccountVerifying ? 0 : getInitialSubStepForBusinessInfo(values)), [values, isBankAccountVerifying]); const buildRoute = useCallback( - (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.COMPANY, subPage: pageName, action}), - [policyID], + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.COMPANY, subPage: pageName, action, backTo}), + [policyID, backTo], ); const {CurrentPage, isEditing, currentPageName, pageIndex, nextPage, prevPage, moveTo, isRedirecting} = useSubPage({ diff --git a/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx b/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx index 2a50872c3fcff..142ce9a2576cc 100644 --- a/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx +++ b/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx @@ -20,6 +20,9 @@ type CompleteVerificationProps = { /** Handles submit button press (URL-based navigation) */ onSubmit?: () => void; + + /** Back to URL for preserving navigation context */ + backTo?: string; }; const COMPLETE_VERIFICATION_KEYS = INPUT_IDS.COMPLETE_VERIFICATION; @@ -28,7 +31,7 @@ const SUB_PAGE_NAMES = CONST.BANK_ACCOUNT.COMPLETE_VERIFICATION_STEP.SUB_PAGE_NA const pages = [{pageName: SUB_PAGE_NAMES.CONFIRM_AGREEMENTS, component: ConfirmAgreements}]; -function CompleteVerification({onBackButtonPress, onSubmit}: CompleteVerificationProps) { +function CompleteVerification({onBackButtonPress, onSubmit, backTo}: CompleteVerificationProps) { const {translate} = useLocalize(); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); @@ -54,8 +57,8 @@ function CompleteVerification({onBackButtonPress, onSubmit}: CompleteVerificatio }, [bankAccountID, values.isAuthorizedToUseBankAccount, values.certifyTrueInformation, values.acceptTermsAndConditions, policyID, lastPaymentMethod, onSubmit]); const buildRoute = useCallback( - (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.ACH_CONTRACT, subPage: pageName, action}), - [policyID], + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.ACH_CONTRACT, subPage: pageName, action, backTo}), + [policyID, backTo], ); const {CurrentPage, isEditing, pageIndex, nextPage, prevPage, moveTo} = useSubPage({pages, startFrom: 0, onFinished: submit, buildRoute}); diff --git a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx index aa6b3ebf7d1c7..cbdff5960409e 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx @@ -31,6 +31,9 @@ type PersonalInfoProps = { /** Reference to the outer element */ ref?: ForwardedRef; + + /** Back to URL for preserving navigation context */ + backTo?: string; }; const PERSONAL_INFO_STEP_KEYS = INPUT_IDS.PERSONAL_INFO_STEP; @@ -45,7 +48,7 @@ const pages = [ {pageName: SUB_PAGE_NAMES.CONFIRMATION, component: Confirmation}, ]; -function PersonalInfo({onBackButtonPress, onSubmit, ref}: PersonalInfoProps) { +function PersonalInfo({onBackButtonPress, onSubmit, ref, backTo}: PersonalInfoProps) { const {translate} = useLocalize(); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); @@ -64,8 +67,8 @@ function PersonalInfo({onBackButtonPress, onSubmit, ref}: PersonalInfoProps) { const startFrom = useMemo(() => (isBankAccountVerifying ? 0 : getInitialSubStepForPersonalInfo(values)), [values, isBankAccountVerifying]); const buildRoute = useCallback( - (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.REQUESTOR, subPage: pageName, action}), - [policyID], + (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.REQUESTOR, subPage: pageName, action, backTo}), + [policyID, backTo], ); const {CurrentPage, isEditing, currentPageName, pageIndex, nextPage, prevPage, moveTo, isRedirecting} = useSubPage({ diff --git a/src/pages/ReimbursementAccount/USD/Requestor/RequestorStep.tsx b/src/pages/ReimbursementAccount/USD/Requestor/RequestorStep.tsx index fc57a2d04be19..3217d3542307b 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/RequestorStep.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/RequestorStep.tsx @@ -16,9 +16,12 @@ type RequestorStepProps = { /** Reference to the outer element */ ref?: ForwardedRef; + + /** Back to URL for preserving navigation context */ + backTo?: string; }; -function RequestorStep({shouldShowOnfido, onBackButtonPress, onSubmit, ref}: RequestorStepProps) { +function RequestorStep({shouldShowOnfido, onBackButtonPress, onSubmit, ref, backTo}: RequestorStepProps) { if (shouldShowOnfido) { return ; } @@ -28,6 +31,7 @@ function RequestorStep({shouldShowOnfido, onBackButtonPress, onSubmit, ref}: Req ref={ref} onBackButtonPress={onBackButtonPress} onSubmit={onSubmit} + backTo={backTo} /> ); } diff --git a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx index ef3cb8051cc80..c405bd87f6593 100644 --- a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx +++ b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx @@ -67,8 +67,9 @@ type USDVerifiedBankAccountFlowPageProps = PlatformStackScreenProps(null); const currentPageIndex = useMemo(() => { - const index = pages.findIndex((p) => p.pageName === currentStep); + const index = pages.findIndex((p) => p.pageName === currentPage); return index >= 0 ? index : 0; - }, [currentStep]); + }, [currentPage]); const currentEntry = pages.at(currentPageIndex); const CurrentPage = currentEntry?.component ?? (Country as React.ComponentType); @@ -90,8 +91,8 @@ function USDVerifiedBankAccountFlowPage({route}: USDVerifiedBankAccountFlowPageP return; } const nextPage = pages.at(nextIndex); - Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: nextPage?.pageName, subPage: nextPage?.firstSubPage})); - }, [currentPageIndex, policyID]); + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: nextPage?.pageName, subPage: nextPage?.firstSubPage, backTo})); + }, [backTo, currentPageIndex, policyID]); const onBackButtonPress = useCallback(() => { const prevIndex = currentPageIndex - 1; @@ -100,8 +101,8 @@ function USDVerifiedBankAccountFlowPage({route}: USDVerifiedBankAccountFlowPageP return; } const prevPage = pages.at(prevIndex); - Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: prevPage?.pageName, subPage: prevPage?.lastSubPage})); - }, [currentPageIndex, policyID]); + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: prevPage?.pageName, subPage: prevPage?.lastSubPage, backTo})); + }, [backTo, currentPageIndex, policyID]); const shouldShowOnfido = !!(onfidoToken && !reimbursementAccount?.achData?.isOnfidoSetupComplete); const isRequestorStep = currentEntry?.pageName === PAGE_NAMES.REQUESTOR; @@ -116,6 +117,7 @@ function USDVerifiedBankAccountFlowPage({route}: USDVerifiedBankAccountFlowPageP stepNames={CONST.BANK_ACCOUNT.STEP_NAMES} shouldShowOnfido={isRequestorStep ? shouldShowOnfido : undefined} ref={isRequestorStep ? requestorStepRef : undefined} + backTo={backTo} /> ); diff --git a/src/pages/ReimbursementAccount/USD/types.ts b/src/pages/ReimbursementAccount/USD/types.ts index 946cc21c18857..12fae45bd46ca 100644 --- a/src/pages/ReimbursementAccount/USD/types.ts +++ b/src/pages/ReimbursementAccount/USD/types.ts @@ -1,5 +1,6 @@ import type {ForwardedRef} from 'react'; import type {View} from 'react-native'; +import type {Route} from '@src/ROUTES'; type USDPageProps = { /** Handles submit button press */ @@ -22,6 +23,9 @@ type USDPageProps = { /** Reference to the outer element (used by RequestorStep) */ ref?: ForwardedRef; + + /** Back to URL for preserving navigation context */ + backTo?: Route; }; export default USDPageProps; diff --git a/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx b/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx index 2f9f27310b6e7..8d6d899182812 100644 --- a/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx +++ b/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx @@ -124,9 +124,9 @@ function VerifiedBankAccountFlowEntryPoint({ (setupType: ValueOf) => { setBankAccountSubStep(setupType); goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.COUNTRY); - Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, step: CONST.BANK_ACCOUNT.STEP.COUNTRY})); + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: CONST.BANK_ACCOUNT.STEP.COUNTRY, backTo})); }, - [policyID], + [policyID, backTo], ); /** From 4f045ff301d81f60f466833e8af920c47da3d749 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Sat, 28 Mar 2026 18:27:23 +0100 Subject: [PATCH 12/20] fix: navigating back from UBO step --- .../BeneficialOwnersStep.tsx | 54 ++++++----- .../USD/BusinessInfo/BusinessInfo.tsx | 20 ++-- .../USD/USDVerifiedBankAccountFlow.tsx | 97 ------------------- .../USD/USDVerifiedBankAccountFlowPage.tsx | 4 +- 4 files changed, 40 insertions(+), 135 deletions(-) delete mode 100644 src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlow.tsx diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx index 2a9babb395574..47b4bb70fe3ce 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx @@ -1,5 +1,5 @@ import {Str} from 'expensify-common'; -import React, {useCallback, useState} from 'react'; +import React, {useCallback, useEffect} from 'react'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import YesNoStep from '@components/SubStepForms/YesNoStep'; import useLocalize from '@hooks/useLocalize'; @@ -47,22 +47,25 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); const companyName = reimbursementAccount?.achData?.companyName ?? ''; - const defaultValues = { - ownsMoreThan25Percent: reimbursementAccount?.achData?.ownsMoreThan25Percent ?? reimbursementAccountDraft?.ownsMoreThan25Percent ?? false, - hasOtherBeneficialOwners: reimbursementAccount?.achData?.hasOtherBeneficialOwners ?? reimbursementAccountDraft?.hasOtherBeneficialOwners ?? false, - beneficialOwnerKeys: reimbursementAccount?.achData?.beneficialOwnerKeys ?? reimbursementAccountDraft?.beneficialOwnerKeys ?? [], - }; - // We're only reading beneficialOwnerKeys from draft values because there is not option to remove UBO - // if we were to set them based on values saved in BE then there would be no option to enter different UBOs - // user would always see the same UBOs that was saved in BE when returning to this step and trying to change something - const [beneficialOwnerKeys, setBeneficialOwnerKeys] = useState(defaultValues.beneficialOwnerKeys); - const [beneficialOwnerBeingModifiedID, setBeneficialOwnerBeingModifiedID] = useState(''); - const [isEditingCreatedBeneficialOwner, setIsEditingCreatedBeneficialOwner] = useState(false); - const [isUserUBO, setIsUserUBO] = useState(defaultValues.ownsMoreThan25Percent); - const [isAnyoneElseUBO, setIsAnyoneElseUBO] = useState(defaultValues.hasOtherBeneficialOwners); + // Read state from Onyx draft so it survives URL-based navigation (component remounts) + const isUserUBO = reimbursementAccount?.achData?.ownsMoreThan25Percent ?? reimbursementAccountDraft?.ownsMoreThan25Percent ?? false; + const beneficialOwners = reimbursementAccount?.achData?.beneficialOwners; + const isAnyoneElseUBO = beneficialOwners?.length ? true : reimbursementAccountDraft?.hasOtherBeneficialOwners ?? false; + const beneficialOwnerKeys: string[] = reimbursementAccountDraft?.beneficialOwnerKeys ?? reimbursementAccount?.achData?.beneficialOwnerKeys ?? []; + const beneficialOwnerBeingModifiedID = reimbursementAccountDraft?.ownerBeingModifiedID ?? ''; + const isEditingCreatedBeneficialOwner = reimbursementAccountDraft?.isEditingCreatedOwner ?? false; const canAddMoreUBOS = beneficialOwnerKeys.length < (isUserUBO ? MAX_NUMBER_OF_UBOS - 1 : MAX_NUMBER_OF_UBOS); + // Redirect to the correct sub-page if no subPage is in the URL + useEffect(() => { + if (currentSubPage) { + return; + } + const subPage = isUserUBO || (isAnyoneElseUBO && beneficialOwnerKeys.length > 0) ? SUB_PAGE_NAMES.UBOS_LIST : SUB_PAGE_NAMES.IS_USER_UBO; + Navigation.setParams({subPage} as Record); + }, [currentSubPage, policyID, backTo, isAnyoneElseUBO, beneficialOwnerKeys.length]); + const navigateToSubPage = useCallback( (subPage: string) => { Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.BENEFICIAL_OWNERS, subPage, backTo})); @@ -79,7 +82,7 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli const submit = () => { const beneficialOwnerFields = ['firstName', 'lastName', 'dob', 'ssnLast4', 'street', 'city', 'state', 'zipCode']; - const beneficialOwners = beneficialOwnerKeys.map((ownerKey) => + const beneficialOwnersData = beneficialOwnerKeys.map((ownerKey) => beneficialOwnerFields.reduce( (acc, fieldName) => { acc[fieldName] = reimbursementAccountDraft ? SafeString(reimbursementAccountDraft[`beneficialOwner_${ownerKey}_${fieldName}`]) : undefined; @@ -93,7 +96,7 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli getBankAccountIDAsNumber(reimbursementAccount?.achData), { ownsMoreThan25Percent: isUserUBO, - beneficialOwners: JSON.stringify(beneficialOwners), + beneficialOwners: JSON.stringify(beneficialOwnersData), beneficialOwnerKeys, }, policyID, @@ -103,8 +106,7 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli const addBeneficialOwner = (beneficialOwnerID: string) => { const newBeneficialOwners = [...beneficialOwnerKeys, beneficialOwnerID]; - setBeneficialOwnerKeys(newBeneficialOwners); - setDraftValues(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {beneficialOwners: JSON.stringify(newBeneficialOwners)}); + setDraftValues(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {beneficialOwnerKeys: newBeneficialOwners, beneficialOwners: JSON.stringify(newBeneficialOwners)}); }; const handleBeneficialOwnerDetailsFormSubmit = () => { @@ -116,22 +118,22 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli const isLastUBOThatCanBeAdded = beneficialOwnerKeys.length === (isUserUBO ? MAX_NUMBER_OF_UBOS - 2 : MAX_NUMBER_OF_UBOS - 1); const nextSubPage = isEditingCreatedBeneficialOwner || isLastUBOThatCanBeAdded ? SUB_PAGE_NAMES.UBOS_LIST : SUB_PAGE_NAMES.ARE_THERE_MORE_UBOS; - setIsEditingCreatedBeneficialOwner(false); + setDraftValues(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {isEditingCreatedOwner: false}); navigateToSubPage(nextSubPage); }; const prepareBeneficialOwnerDetailsForm = () => { const beneficialOwnerID = Str.guid(); - setBeneficialOwnerBeingModifiedID(beneficialOwnerID); + setDraftValues(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {ownerBeingModifiedID: beneficialOwnerID}); navigateToSubPage(SUB_PAGE_NAMES.LEGAL_NAME); }; const handleNextUBOSubstep = (value: boolean) => { if (currentSubPage === SUB_PAGE_NAMES.IS_USER_UBO) { - setIsUserUBO(value); + setDraftValues(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {ownsMoreThan25Percent: value}); if (value && beneficialOwnerKeys.length === 4) { - setBeneficialOwnerKeys((previousBeneficialOwners) => previousBeneficialOwners.slice(0, 3)); + setDraftValues(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {beneficialOwnerKeys: beneficialOwnerKeys.slice(0, 3)}); } navigateToSubPage(SUB_PAGE_NAMES.IS_ANYONE_ELSE_UBO); @@ -139,7 +141,7 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli } if (currentSubPage === SUB_PAGE_NAMES.IS_ANYONE_ELSE_UBO) { - setIsAnyoneElseUBO(value); + setDraftValues(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {hasOtherBeneficialOwners: value}); if (!canAddMoreUBOS && value) { navigateToSubPage(SUB_PAGE_NAMES.UBOS_LIST); @@ -188,8 +190,7 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli }; const handleUBOEdit = (beneficialOwnerID: string) => { - setBeneficialOwnerBeingModifiedID(beneficialOwnerID); - setIsEditingCreatedBeneficialOwner(true); + setDraftValues(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {ownerBeingModifiedID: beneficialOwnerID, isEditingCreatedOwner: true}); navigateToSubPage(SUB_PAGE_NAMES.LEGAL_NAME); }; @@ -199,7 +200,8 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli setDraftValues(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {ownerBeingModifiedID: id})} isEditingCreatedBeneficialOwner={isEditingCreatedBeneficialOwner} onFinished={handleBeneficialOwnerDetailsFormSubmit} backTo={backTo} diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx index ef2e7262be071..7da5ec265485c 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx @@ -125,6 +125,10 @@ function BusinessInfo({onBackButtonPress, onSubmit, backTo}: BusinessInfoProps) } }; + if (isRedirecting) { + return ; + } + return ( - {isRedirecting ? ( - - ) : ( - - )} + ); } diff --git a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlow.tsx b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlow.tsx deleted file mode 100644 index c13784998b2a5..0000000000000 --- a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlow.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import React from 'react'; -import {View} from 'react-native'; -import useOnyx from '@hooks/useOnyx'; -import useThemeStyles from '@hooks/useThemeStyles'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import BankInfo from './BankInfo/BankInfo'; -import BeneficialOwnersStep from './BeneficialOwnerInfo/BeneficialOwnersStep'; -import BusinessInfo from './BusinessInfo/BusinessInfo'; -import CompleteVerification from './CompleteVerification/CompleteVerification'; -import ConnectBankAccount from './ConnectBankAccount/ConnectBankAccount'; -import Country from './Country'; -import RequestorStep from './Requestor/RequestorStep'; - -type USDVerifiedBankAccountFlowProps = { - USDBankAccountStep: string; - policyID: string | undefined; - onBackButtonPress: () => void; - requestorStepRef: React.RefObject; - onfidoToken: string; - setUSDBankAccountStep: (step: string | null) => void; - setShouldShowConnectedVerifiedBankAccount: (shouldShowConnectedVerifiedBankAccount: boolean) => void; -}; - -function USDVerifiedBankAccountFlow({ - USDBankAccountStep, - policyID = '', - onBackButtonPress, - requestorStepRef, - onfidoToken, - setUSDBankAccountStep, - setShouldShowConnectedVerifiedBankAccount, -}: USDVerifiedBankAccountFlowProps) { - const styles = useThemeStyles(); - const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); - - let CurrentStep: React.JSX.Element | null; - switch (USDBankAccountStep) { - case CONST.BANK_ACCOUNT.STEP.COUNTRY: - CurrentStep = ( - - ); - break; - case CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT: - CurrentStep = ( - - ); - break; - case CONST.BANK_ACCOUNT.STEP.REQUESTOR: - CurrentStep = ( - - ); - break; - case CONST.BANK_ACCOUNT.STEP.COMPANY: - CurrentStep = ; - break; - case CONST.BANK_ACCOUNT.STEP.BENEFICIAL_OWNERS: - CurrentStep = ; - break; - case CONST.BANK_ACCOUNT.STEP.ACH_CONTRACT: - CurrentStep = ; - break; - case CONST.BANK_ACCOUNT.STEP.VALIDATION: - CurrentStep = ( - - ); - break; - default: - CurrentStep = null; - break; - } - - if (CurrentStep) { - return {CurrentStep}; - } - - return null; -} - -export default USDVerifiedBankAccountFlow; diff --git a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx index c405bd87f6593..2dfffc2f943df 100644 --- a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx +++ b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx @@ -51,7 +51,7 @@ const pages: PageEntry[] = [ pageName: PAGE_NAMES.BENEFICIAL_OWNERS, component: BeneficialOwnersStep as React.ComponentType, firstSubPage: BENEFICIAL_OWNERS_SUB_PAGES.IS_USER_UBO, - lastSubPage: BENEFICIAL_OWNERS_SUB_PAGES.UBOS_LIST, + lastSubPage: undefined, }, { pageName: PAGE_NAMES.ACH_CONTRACT, @@ -101,7 +101,7 @@ function USDVerifiedBankAccountFlowPage({route}: USDVerifiedBankAccountFlowPageP return; } const prevPage = pages.at(prevIndex); - Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: prevPage?.pageName, subPage: prevPage?.lastSubPage, backTo})); + Navigation.goBack(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: prevPage?.pageName, subPage: prevPage?.lastSubPage, backTo})); }, [backTo, currentPageIndex, policyID]); const shouldShowOnfido = !!(onfidoToken && !reimbursementAccount?.achData?.isOnfidoSetupComplete); From 05534d6caf67390d9304de79c187868c35189e71 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 30 Mar 2026 12:14:10 +0200 Subject: [PATCH 13/20] fix: show loading before navigating to the next step --- src/hooks/useReimbursementAccountSubmit.ts | 28 +++++++++++++++++++ .../USD/BankInfo/BankInfo.tsx | 4 ++- .../BeneficialOwnersStep.tsx | 6 ++-- .../USD/BusinessInfo/BusinessInfo.tsx | 4 ++- .../CompleteVerification.tsx | 6 ++-- .../Requestor/PersonalInfo/PersonalInfo.tsx | 4 ++- 6 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 src/hooks/useReimbursementAccountSubmit.ts diff --git a/src/hooks/useReimbursementAccountSubmit.ts b/src/hooks/useReimbursementAccountSubmit.ts new file mode 100644 index 0000000000000..6fff0ec34c2ed --- /dev/null +++ b/src/hooks/useReimbursementAccountSubmit.ts @@ -0,0 +1,28 @@ +import {useCallback, useEffect, useRef} from 'react'; +import ONYXKEYS from '@src/ONYXKEYS'; +import useOnyx from './useOnyx'; + +/** + * Defers navigation (onSubmit) until the reimbursement account API call completes. + * Instead of navigating to the next step immediately after firing the API call, + * this hook waits for `isLoading` to go back to `false` and checks for errors. + * + * @param onSubmit - callback that navigates to the next step + * @returns markSubmitting - call this right after firing the API action + */ +export default function useReimbursementAccountSubmit(onSubmit?: () => void) { + const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); + const isSubmittingRef = useRef(false); + + useEffect(() => { + if (!isSubmittingRef.current || reimbursementAccount?.isLoading || reimbursementAccount?.errors) { + return; + } + isSubmittingRef.current = false; + onSubmit?.(); + }, [reimbursementAccount?.isLoading, reimbursementAccount?.errors, onSubmit]); + + return useCallback(() => { + isSubmittingRef.current = true; + }, []); +} diff --git a/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx b/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx index 67e84f7d29944..b7a2afa21cfa5 100644 --- a/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/BankInfo/BankInfo.tsx @@ -2,6 +2,7 @@ import React, {useCallback, useEffect, useRef} from 'react'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import useReimbursementAccountSubmit from '@hooks/useReimbursementAccountSubmit'; import useSubPage from '@hooks/useSubPage'; import type {SubPageProps} from '@hooks/useSubPage/types'; import getPlaidOAuthReceivedRedirectURI from '@libs/getPlaidOAuthReceivedRedirectURI'; @@ -44,6 +45,7 @@ function BankInfo({onBackButtonPress, onSubmit, policyID, backTo}: BankInfoProps const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); const [plaidLinkToken] = useOnyx(ONYXKEYS.PLAID_LINK_TOKEN); const {translate} = useLocalize(); + const markSubmitting = useReimbursementAccountSubmit(onSubmit); const redirectedFromPlaidToManualRef = useRef(false); const values = getSubStepValues(BANK_INFO_STEP_KEYS, reimbursementAccountDraft, reimbursementAccount ?? {}); @@ -87,7 +89,7 @@ function BankInfo({onBackButtonPress, onSubmit, policyID, backTo}: BankInfoProps policyID, ); } - onSubmit?.(); + markSubmitting(); }; const pages = setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID ? plaidPages : manualPages; diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx index 47b4bb70fe3ce..f12455e4189ef 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx @@ -4,6 +4,7 @@ import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import YesNoStep from '@components/SubStepForms/YesNoStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import useReimbursementAccountSubmit from '@hooks/useReimbursementAccountSubmit'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import {getBankAccountIDAsNumber} from '@libs/ReimbursementAccountUtils'; @@ -47,11 +48,12 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); const companyName = reimbursementAccount?.achData?.companyName ?? ''; + const markSubmitting = useReimbursementAccountSubmit(onSubmit); // Read state from Onyx draft so it survives URL-based navigation (component remounts) const isUserUBO = reimbursementAccount?.achData?.ownsMoreThan25Percent ?? reimbursementAccountDraft?.ownsMoreThan25Percent ?? false; const beneficialOwners = reimbursementAccount?.achData?.beneficialOwners; - const isAnyoneElseUBO = beneficialOwners?.length ? true : reimbursementAccountDraft?.hasOtherBeneficialOwners ?? false; + const isAnyoneElseUBO = beneficialOwners?.length ? true : (reimbursementAccountDraft?.hasOtherBeneficialOwners ?? false); const beneficialOwnerKeys: string[] = reimbursementAccountDraft?.beneficialOwnerKeys ?? reimbursementAccount?.achData?.beneficialOwnerKeys ?? []; const beneficialOwnerBeingModifiedID = reimbursementAccountDraft?.ownerBeingModifiedID ?? ''; const isEditingCreatedBeneficialOwner = reimbursementAccountDraft?.isEditingCreatedOwner ?? false; @@ -101,7 +103,7 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli }, policyID, ); - onSubmit?.(); + markSubmitting(); }; const addBeneficialOwner = (beneficialOwnerID: string) => { diff --git a/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx b/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx index 7da5ec265485c..78026ce7d38c5 100644 --- a/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/BusinessInfo/BusinessInfo.tsx @@ -5,6 +5,7 @@ import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import useReimbursementAccountSubmit from '@hooks/useReimbursementAccountSubmit'; import useSubPage from '@hooks/useSubPage'; import type {SubPageProps} from '@hooks/useSubPage/types'; import Navigation from '@libs/Navigation/Navigation'; @@ -72,6 +73,7 @@ function BusinessInfo({onBackButtonPress, onSubmit, backTo}: BusinessInfoProps) const policyID = reimbursementAccount?.achData?.policyID; const bankAccountID = getBankAccountIDAsNumber(reimbursementAccount?.achData); + const markSubmitting = useReimbursementAccountSubmit(onSubmit); const values = useMemo(() => getSubStepValues(BUSINESS_INFO_STEP_KEYS, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]); const submit = useCallback( @@ -106,7 +108,7 @@ function BusinessInfo({onBackButtonPress, onSubmit, backTo}: BusinessInfoProps) startFrom, onFinished: () => { submit(true); - onSubmit?.(); + markSubmitting(); }, onPageChange: () => submit(false), buildRoute, diff --git a/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx b/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx index 142ce9a2576cc..821d17eeca623 100644 --- a/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx +++ b/src/pages/ReimbursementAccount/USD/CompleteVerification/CompleteVerification.tsx @@ -2,6 +2,7 @@ import React, {useCallback, useMemo} from 'react'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import useReimbursementAccountSubmit from '@hooks/useReimbursementAccountSubmit'; import useSubPage from '@hooks/useSubPage'; import type {SubPageProps} from '@hooks/useSubPage/types'; import Navigation from '@libs/Navigation/Navigation'; @@ -41,6 +42,7 @@ function CompleteVerification({onBackButtonPress, onSubmit, backTo}: CompleteVer const values = useMemo(() => getSubStepValues(COMPLETE_VERIFICATION_KEYS, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]); const policyID = reimbursementAccount?.achData?.policyID; const bankAccountID = getBankAccountIDAsNumber(reimbursementAccount?.achData); + const markSubmitting = useReimbursementAccountSubmit(onSubmit); const submit = useCallback(() => { acceptACHContractForBankAccount( @@ -53,8 +55,8 @@ function CompleteVerification({onBackButtonPress, onSubmit, backTo}: CompleteVer policyID, policyID ? lastPaymentMethod?.[policyID] : undefined, ); - onSubmit?.(); - }, [bankAccountID, values.isAuthorizedToUseBankAccount, values.certifyTrueInformation, values.acceptTermsAndConditions, policyID, lastPaymentMethod, onSubmit]); + markSubmitting(); + }, [bankAccountID, values.isAuthorizedToUseBankAccount, values.certifyTrueInformation, values.acceptTermsAndConditions, policyID, lastPaymentMethod, markSubmitting]); const buildRoute = useCallback( (pageName: string, action?: 'edit') => ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: PAGE_NAMES.ACH_CONTRACT, subPage: pageName, action, backTo}), diff --git a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx index cbdff5960409e..9f0a9057bbc0b 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/PersonalInfo/PersonalInfo.tsx @@ -5,6 +5,7 @@ import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import useReimbursementAccountSubmit from '@hooks/useReimbursementAccountSubmit'; import useSubPage from '@hooks/useSubPage'; import type {SubPageProps} from '@hooks/useSubPage/types'; import Navigation from '@libs/Navigation/Navigation'; @@ -57,6 +58,7 @@ function PersonalInfo({onBackButtonPress, onSubmit, ref, backTo}: PersonalInfoPr const policyID = reimbursementAccount?.achData?.policyID; const values = useMemo(() => getSubStepValues(PERSONAL_INFO_STEP_KEYS, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]); const bankAccountID = getBankAccountIDAsNumber(reimbursementAccount?.achData); + const markSubmitting = useReimbursementAccountSubmit(onSubmit); const submit = useCallback( (isConfirmPage: boolean) => { updatePersonalInformationForBankAccount(bankAccountID, {...values}, policyID, isConfirmPage); @@ -76,7 +78,7 @@ function PersonalInfo({onBackButtonPress, onSubmit, ref, backTo}: PersonalInfoPr startFrom, onFinished: () => { submit(true); - onSubmit?.(); + markSubmitting(); }, onPageChange: () => submit(false), buildRoute, From 3eaf0f523f45a99bbcb16705b2234f3557584f63 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 30 Mar 2026 13:15:56 +0200 Subject: [PATCH 14/20] fix: show proper success page --- .../ConnectBankAccount/ConnectBankAccount.tsx | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/pages/ReimbursementAccount/USD/ConnectBankAccount/ConnectBankAccount.tsx b/src/pages/ReimbursementAccount/USD/ConnectBankAccount/ConnectBankAccount.tsx index 11e6f33b4654c..491c737067c6c 100644 --- a/src/pages/ReimbursementAccount/USD/ConnectBankAccount/ConnectBankAccount.tsx +++ b/src/pages/ReimbursementAccount/USD/ConnectBankAccount/ConnectBankAccount.tsx @@ -1,6 +1,7 @@ import {hasSeenTourSelector} from '@selectors/Onboarding'; import React from 'react'; import {View} from 'react-native'; +import ConfirmationPage from '@components/ConfirmationPage'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; @@ -8,10 +9,14 @@ import TextLink from '@components/TextLink'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; +import useRootNavigationState from '@hooks/useRootNavigationState'; import useThemeStyles from '@hooks/useThemeStyles'; +import {isFullScreenName} from '@navigation/helpers/isNavigatorName'; +import Navigation from '@navigation/Navigation'; import ConnectedVerifiedBankAccount from '@pages/ReimbursementAccount/ConnectedVerifiedBankAccount'; import {navigateToConciergeChat} from '@userActions/Report'; import CONST from '@src/CONST'; +import NAVIGATORS from '@src/NAVIGATORS'; import ONYXKEYS from '@src/ONYXKEYS'; import BankAccountValidationForm from './components/BankAccountValidationForm'; import FinishChatCard from './components/FinishChatCard'; @@ -30,6 +35,7 @@ type ConnectBankAccountProps = { function ConnectBankAccount({onBackButtonPress, setShouldShowConnectedVerifiedBankAccount, setUSDBankAccountStep}: ConnectBankAccountProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); + const topmostFullScreenRoute = useRootNavigationState((state) => state?.routes.findLast((lastRoute) => isFullScreenName(lastRoute.name))); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${reimbursementAccount?.achData?.policyID}`); @@ -45,6 +51,24 @@ function ConnectBankAccount({onBackButtonPress, setShouldShowConnectedVerifiedBa // If a user tries to navigate directly to the validate page we'll show them the EnableStep if (bankAccountState === CONST.BANK_ACCOUNT.STATE.OPEN) { + if (topmostFullScreenRoute?.name === NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR) { + return ( + + Navigation.dismissModal()} + /> + Navigation.dismissModal()} + /> + + ); + } return ( Date: Mon, 30 Mar 2026 14:17:46 +0200 Subject: [PATCH 15/20] fix: remove unnecessary comment --- .../ReimbursementAccountVerifyAccountPage.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountVerifyAccountPage.tsx b/src/pages/ReimbursementAccount/ReimbursementAccountVerifyAccountPage.tsx index 52ea1acd2ccc1..f7f5e8be32b78 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountVerifyAccountPage.tsx +++ b/src/pages/ReimbursementAccount/ReimbursementAccountVerifyAccountPage.tsx @@ -3,7 +3,6 @@ import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import VerifyAccountPageBase from '@pages/settings/VerifyAccountPageBase'; -import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; @@ -15,7 +14,6 @@ function ReimbursementAccountVerifyAccountPage({route}: ReimbursementAccountVeri { - // TODO: check if it's not breaking Navigation.goBack(ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute({policyID, backTo}), {compareParams: false}); }} /> From befbf499c10436b8125b65f7c03759badab62626 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 30 Mar 2026 14:31:56 +0200 Subject: [PATCH 16/20] fix: eslint, prettier --- src/ROUTES.ts | 11 +-------- src/components/Navigation/DebugTabView.tsx | 1 - src/libs/ReimbursementAccountUtils.ts | 23 +------------------ .../BeneficialOwnersStep.tsx | 8 +++---- .../ConfirmationUBO.tsx | 4 ++-- .../WorkspaceExpensifyCardBankAccounts.tsx | 1 - .../WorkspaceExpensifyCardPageEmptyState.tsx | 2 +- .../WorkspaceTravelInvoicingSection.tsx | 2 +- ...ceTravelInvoicingSettlementAccountPage.tsx | 1 - tests/unit/ReimbursementAccountUtilsTest.ts | 9 +------- 10 files changed, 11 insertions(+), 51 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index a936a4f1e52c9..f1b6fa03b63f8 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -14,7 +14,6 @@ import type {ReplacementReason} from './libs/actions/Card'; import type {IOURequestType} from './libs/actions/IOU'; import Log from './libs/Log'; import type {RootNavigatorParamList} from './libs/Navigation/types'; -import type {ReimbursementAccountStepToOpen} from './libs/ReimbursementAccountUtils'; import StringUtils from './libs/StringUtils'; import {getUrlWithParams} from './libs/Url'; import SCREENS from './SCREENS'; @@ -299,15 +298,7 @@ const ROUTES = { // TODO: rename the route as no longer accepts step BANK_ACCOUNT_WITH_STEP_TO_OPEN: { route: 'bank-account/new', - getRoute: ({ - policyID, - bankAccountID, - backTo, - }: { - policyID: string | undefined; - bankAccountID?: number; - backTo?: string; - }) => { + getRoute: ({policyID, bankAccountID, backTo}: {policyID: string | undefined; bankAccountID?: number; backTo?: string}) => { if (!policyID && !bankAccountID) { // eslint-disable-next-line no-restricted-syntax -- Legacy route generation return getUrlWithBackToParam(`bank-account/new`, backTo); diff --git a/src/components/Navigation/DebugTabView.tsx b/src/components/Navigation/DebugTabView.tsx index 482330e520c42..8e25ec0753107 100644 --- a/src/components/Navigation/DebugTabView.tsx +++ b/src/components/Navigation/DebugTabView.tsx @@ -16,7 +16,6 @@ import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; -import {getRouteForCurrentStep as getReimbursementAccountRouteForCurrentStep} from '@libs/ReimbursementAccountUtils'; import type {BrickRoad} from '@libs/WorkspacesSettingsUtils'; import {getChatTabBrickRoadReportID} from '@libs/WorkspacesSettingsUtils'; import CONST from '@src/CONST'; diff --git a/src/libs/ReimbursementAccountUtils.ts b/src/libs/ReimbursementAccountUtils.ts index 0610e2d0dd10e..37c9ecfe3a23f 100644 --- a/src/libs/ReimbursementAccountUtils.ts +++ b/src/libs/ReimbursementAccountUtils.ts @@ -14,27 +14,6 @@ const REIMBURSEMENT_ACCOUNT_ROUTE_NAMES = { NEW: 'new', } as const; -function getRouteForCurrentStep(currentStep: ReimbursementAccountStep): ReimbursementAccountStepToOpen { - switch (currentStep) { - case CONST.BANK_ACCOUNT.STEP.COMPANY: - return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.COMPANY; - case CONST.BANK_ACCOUNT.STEP.REQUESTOR: - return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.PERSONAL_INFORMATION; - case CONST.BANK_ACCOUNT.STEP.BENEFICIAL_OWNERS: - return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.BENEFICIAL_OWNERS; - case CONST.BANK_ACCOUNT.STEP.ACH_CONTRACT: - return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.CONTRACT; - case CONST.BANK_ACCOUNT.STEP.VALIDATION: - return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.VALIDATE; - case CONST.BANK_ACCOUNT.STEP.ENABLE: - return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.ENABLE; - case CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT: - case CONST.BANK_ACCOUNT.STEP.COUNTRY: - default: - return REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.NEW; - } -} - /** * Returns true if a VBBA exists in any state other than OPEN or LOCKED */ @@ -67,5 +46,5 @@ const hasInProgressVBBA = (achData?: ACHDataReimbursementAccount, isNonUSDWorksp return hasInProgressUSDVBBA(achData); }; -export {getBankAccountIDAsNumber, getRouteForCurrentStep, hasInProgressUSDVBBA, hasInProgressNonUSDVBBA, hasInProgressVBBA, REIMBURSEMENT_ACCOUNT_ROUTE_NAMES}; +export {getBankAccountIDAsNumber, hasInProgressUSDVBBA, hasInProgressNonUSDVBBA, hasInProgressVBBA, REIMBURSEMENT_ACCOUNT_ROUTE_NAMES}; export type {ReimbursementAccountStepToOpen}; diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx index f12455e4189ef..a804f8b259753 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx @@ -55,7 +55,7 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli const beneficialOwners = reimbursementAccount?.achData?.beneficialOwners; const isAnyoneElseUBO = beneficialOwners?.length ? true : (reimbursementAccountDraft?.hasOtherBeneficialOwners ?? false); const beneficialOwnerKeys: string[] = reimbursementAccountDraft?.beneficialOwnerKeys ?? reimbursementAccount?.achData?.beneficialOwnerKeys ?? []; - const beneficialOwnerBeingModifiedID = reimbursementAccountDraft?.ownerBeingModifiedID ?? ''; + const beneficialOwnerBeingModifiedID = reimbursementAccountDraft?.ownerBeingModifiedID; const isEditingCreatedBeneficialOwner = reimbursementAccountDraft?.isEditingCreatedOwner ?? false; const canAddMoreUBOS = beneficialOwnerKeys.length < (isUserUBO ? MAX_NUMBER_OF_UBOS - 1 : MAX_NUMBER_OF_UBOS); @@ -66,7 +66,7 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli } const subPage = isUserUBO || (isAnyoneElseUBO && beneficialOwnerKeys.length > 0) ? SUB_PAGE_NAMES.UBOS_LIST : SUB_PAGE_NAMES.IS_USER_UBO; Navigation.setParams({subPage} as Record); - }, [currentSubPage, policyID, backTo, isAnyoneElseUBO, beneficialOwnerKeys.length]); + }, [currentSubPage, policyID, backTo, isAnyoneElseUBO, beneficialOwnerKeys.length, isUserUBO]); const navigateToSubPage = useCallback( (subPage: string) => { @@ -114,7 +114,7 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli const handleBeneficialOwnerDetailsFormSubmit = () => { const shouldAddBeneficialOwner = !beneficialOwnerKeys.find((beneficialOwnerID) => beneficialOwnerID === beneficialOwnerBeingModifiedID) && canAddMoreUBOS; - if (shouldAddBeneficialOwner) { + if (shouldAddBeneficialOwner && beneficialOwnerBeingModifiedID) { addBeneficialOwner(beneficialOwnerBeingModifiedID); } @@ -201,7 +201,7 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli return ( setDraftValues(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {ownerBeingModifiedID: id})} isEditingCreatedBeneficialOwner={isEditingCreatedBeneficialOwner} diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/ConfirmationUBO.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/ConfirmationUBO.tsx index 657ad604a3ed9..db3260ed398c0 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/ConfirmationUBO.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/subSteps/BeneficialOwnerDetailsFormSubSteps/ConfirmationUBO.tsx @@ -3,7 +3,7 @@ import ConfirmationStep from '@components/SubStepForms/ConfirmationStep'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import type {SubPageProps} from '@hooks/useSubPage/types'; -import * as ErrorUtils from '@libs/ErrorUtils'; +import {getLatestErrorMessage} from '@libs/ErrorUtils'; import getValuesForBeneficialOwner from '@pages/ReimbursementAccount/USD/utils/getValuesForBeneficialOwner'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -19,7 +19,7 @@ function ConfirmationUBO({onNext, onMove, isEditing, beneficialOwnerBeingModifie const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT); const values = getValuesForBeneficialOwner(beneficialOwnerBeingModifiedID, reimbursementAccountDraft); - const error = reimbursementAccount ? ErrorUtils.getLatestErrorMessage(reimbursementAccount) : ''; + const error = reimbursementAccount ? getLatestErrorMessage(reimbursementAccount) : ''; const summaryItems = [ { diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx index a1c3f6d4d21b7..77aed07555935 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardBankAccounts.tsx @@ -18,7 +18,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {getLastFourDigits} from '@libs/BankAccountUtils'; import {getEligibleBankAccountsForCard, getEligibleBankAccountsForUkEuCard} from '@libs/CardUtils'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; -import {REIMBURSEMENT_ACCOUNT_ROUTE_NAMES} from '@libs/ReimbursementAccountUtils'; import Navigation from '@navigation/Navigation'; import type {SettingsNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; diff --git a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx index 3febbdbf28aa8..11bafebd9a861 100644 --- a/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx +++ b/src/pages/workspace/expensifyCard/WorkspaceExpensifyCardPageEmptyState.tsx @@ -18,7 +18,7 @@ import useWindowDimensions from '@hooks/useWindowDimensions'; import {getEligibleBankAccountsForCard, getEligibleBankAccountsForUkEuCard} from '@libs/CardUtils'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types'; -import {hasInProgressUSDVBBA, REIMBURSEMENT_ACCOUNT_ROUTE_NAMES} from '@libs/ReimbursementAccountUtils'; +import {hasInProgressUSDVBBA} from '@libs/ReimbursementAccountUtils'; import Navigation from '@navigation/Navigation'; import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading'; import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading'; diff --git a/src/pages/workspace/travel/WorkspaceTravelInvoicingSection.tsx b/src/pages/workspace/travel/WorkspaceTravelInvoicingSection.tsx index 5e0521ccdfd3b..f8e68e43f4b05 100644 --- a/src/pages/workspace/travel/WorkspaceTravelInvoicingSection.tsx +++ b/src/pages/workspace/travel/WorkspaceTravelInvoicingSection.tsx @@ -26,7 +26,7 @@ import {getCardSettings, getEligibleBankAccountsForCard} from '@libs/CardUtils'; import {convertToDisplayString} from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import {areTravelPersonalDetailsMissing} from '@libs/PersonalDetailsUtils'; -import {hasInProgressUSDVBBA, REIMBURSEMENT_ACCOUNT_ROUTE_NAMES} from '@libs/ReimbursementAccountUtils'; +import {hasInProgressUSDVBBA} from '@libs/ReimbursementAccountUtils'; import { getIsTravelInvoicingEnabled, getTravelInvoicingCardSettingsKey, diff --git a/src/pages/workspace/travel/WorkspaceTravelInvoicingSettlementAccountPage.tsx b/src/pages/workspace/travel/WorkspaceTravelInvoicingSettlementAccountPage.tsx index 5923dfe9d5d43..981ab69e16fff 100644 --- a/src/pages/workspace/travel/WorkspaceTravelInvoicingSettlementAccountPage.tsx +++ b/src/pages/workspace/travel/WorkspaceTravelInvoicingSettlementAccountPage.tsx @@ -15,7 +15,6 @@ import {configureTravelInvoicingForPolicy, setTravelInvoicingSettlementAccount} import {getLastFourDigits} from '@libs/BankAccountUtils'; import {getCardSettings, getEligibleBankAccountsForCard} from '@libs/CardUtils'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; -import {REIMBURSEMENT_ACCOUNT_ROUTE_NAMES} from '@libs/ReimbursementAccountUtils'; import {getIsTravelInvoicingEnabled, getTravelInvoicingCardSettingsKey} from '@libs/TravelInvoicingUtils'; import Navigation from '@navigation/Navigation'; import type {SettingsNavigatorParamList} from '@navigation/types'; diff --git a/tests/unit/ReimbursementAccountUtilsTest.ts b/tests/unit/ReimbursementAccountUtilsTest.ts index b531357e98656..e2f3be2e87031 100644 --- a/tests/unit/ReimbursementAccountUtilsTest.ts +++ b/tests/unit/ReimbursementAccountUtilsTest.ts @@ -1,19 +1,12 @@ import Onyx from 'react-native-onyx'; import CONST from '../../src/CONST'; -import {getBankAccountIDAsNumber, getRouteForCurrentStep, REIMBURSEMENT_ACCOUNT_ROUTE_NAMES} from '../../src/libs/ReimbursementAccountUtils'; +import {getBankAccountIDAsNumber} from '../../src/libs/ReimbursementAccountUtils'; import ONYXKEYS from '../../src/ONYXKEYS'; import type {ACHDataReimbursementAccount} from '../../src/types/onyx/ReimbursementAccount'; Onyx.init({keys: ONYXKEYS}); describe('ReimbursementAccountUtils', () => { - describe('getRouteForCurrentStep', () => { - it("should return 'new' step if 'BankAccountStep' or '' is provided", () => { - expect(getRouteForCurrentStep(CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT)).toEqual(REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.NEW); - expect(getRouteForCurrentStep('')).toEqual(REIMBURSEMENT_ACCOUNT_ROUTE_NAMES.NEW); - }); - }); - describe('getBankAccountIDAsNumber', () => { it('should return DEFAULT_NUMBER_ID when achData is undefined', () => { // Given no ACH data From fdf92e3304b451608c070dd9ac910cce69b2fee5 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 30 Mar 2026 15:33:16 +0200 Subject: [PATCH 17/20] fix: minor fix --- .../ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx b/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx index 8d6d899182812..33c3b64325184 100644 --- a/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx +++ b/src/pages/ReimbursementAccount/VerifiedBankAccountFlowEntryPoint.tsx @@ -124,7 +124,7 @@ function VerifiedBankAccountFlowEntryPoint({ (setupType: ValueOf) => { setBankAccountSubStep(setupType); goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.COUNTRY); - Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: CONST.BANK_ACCOUNT.STEP.COUNTRY, backTo})); + Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: CONST.BANK_ACCOUNT.PAGE_NAMES.COUNTRY, backTo})); }, [policyID, backTo], ); From ff25202b5708ea6d0d173330d550c8766272dcf3 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 30 Mar 2026 16:27:27 +0200 Subject: [PATCH 18/20] fix: onfido step --- src/CONST/index.ts | 1 + .../USD/Requestor/RequestorStep.tsx | 10 +------- .../VerifyIdentity/VerifyIdentity.tsx | 25 ++++++++++++++----- .../USD/USDVerifiedBankAccountFlowPage.tsx | 25 ++++++++++++------- src/pages/ReimbursementAccount/USD/types.ts | 3 --- 5 files changed, 37 insertions(+), 27 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 3d635f14806c0..76588faa3eafa 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -598,6 +598,7 @@ const CONST = { COUNTRY: 'country', BANK_ACCOUNT: 'bank-account', REQUESTOR: 'requestor', + VERIFY_IDENTITY: 'verify-identity', COMPANY: 'company', BENEFICIAL_OWNERS: 'beneficial-owners', ACH_CONTRACT: 'ach-contract', diff --git a/src/pages/ReimbursementAccount/USD/Requestor/RequestorStep.tsx b/src/pages/ReimbursementAccount/USD/Requestor/RequestorStep.tsx index 3217d3542307b..f02b5186081d4 100644 --- a/src/pages/ReimbursementAccount/USD/Requestor/RequestorStep.tsx +++ b/src/pages/ReimbursementAccount/USD/Requestor/RequestorStep.tsx @@ -2,7 +2,6 @@ import React from 'react'; import type {ForwardedRef} from 'react'; import type {View} from 'react-native'; import PersonalInfo from './PersonalInfo/PersonalInfo'; -import VerifyIdentity from './VerifyIdentity/VerifyIdentity'; type RequestorStepProps = { /** Goes to the previous step */ @@ -11,9 +10,6 @@ type RequestorStepProps = { /** Handles submit button press (URL-based navigation) */ onSubmit?: () => void; - /** If we should show Onfido flow */ - shouldShowOnfido: boolean; - /** Reference to the outer element */ ref?: ForwardedRef; @@ -21,11 +17,7 @@ type RequestorStepProps = { backTo?: string; }; -function RequestorStep({shouldShowOnfido, onBackButtonPress, onSubmit, ref, backTo}: RequestorStepProps) { - if (shouldShowOnfido) { - return ; - } - +function RequestorStep({onBackButtonPress, onSubmit, ref, backTo}: RequestorStepProps) { return ( void; + + /** Navigates to the next step */ + onSubmit?: () => void; }; const ONFIDO_ERROR_DISPLAY_DURATION = 10000; -function VerifyIdentity({onBackButtonPress}: VerifyIdentityProps) { +function VerifyIdentity({onBackButtonPress, onSubmit}: VerifyIdentityProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -31,25 +34,35 @@ function VerifyIdentity({onBackButtonPress}: VerifyIdentityProps) { const policyID = reimbursementAccount?.achData?.policyID; const bankAccountID = reimbursementAccount?.achData?.bankAccountID; + // If Onfido is already complete (e.g. direct URL navigation), skip to next step + useEffect(() => { + if (!reimbursementAccount?.achData?.isOnfidoSetupComplete) { + return; + } + onSubmit?.(); + // eslint-disable-next-line react-hooks/exhaustive-deps -- only check on mount + }, []); + const handleOnfidoSuccess = useCallback( (onfidoData: OnfidoData) => { verifyIdentityForBankAccount(Number(bankAccountID), {...onfidoData, applicantID: onfidoApplicantID}, policyID); updateReimbursementAccountDraft({isOnfidoSetupComplete: true}); + onSubmit?.(); }, - [bankAccountID, onfidoApplicantID, policyID], + [bankAccountID, onfidoApplicantID, policyID, onSubmit], ); const handleOnfidoError = () => { // In case of any unexpected error we log it to the server, show a growl, and return the user back to the requestor step so they can try again. Growl.error(translate('onfidoStep.genericError'), ONFIDO_ERROR_DISPLAY_DURATION); clearOnfidoToken(); - goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.REQUESTOR); + onBackButtonPress(); }; const handleOnfidoUserExit = (isUserInitiated?: boolean) => { if (isUserInitiated) { clearOnfidoToken(); - goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.REQUESTOR); + onBackButtonPress(); } else { setOnfidoKey(Math.floor(Math.random() * 1000000)); } diff --git a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx index 2dfffc2f943df..1d6e952904371 100644 --- a/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx +++ b/src/pages/ReimbursementAccount/USD/USDVerifiedBankAccountFlowPage.tsx @@ -16,6 +16,7 @@ import CompleteVerification from './CompleteVerification/CompleteVerification'; import ConnectBankAccount from './ConnectBankAccount/ConnectBankAccount'; import Country from './Country'; import RequestorStep from './Requestor/RequestorStep'; +import VerifyIdentity from './Requestor/VerifyIdentity/VerifyIdentity'; import type USDPageProps from './types'; const PAGE_NAMES = CONST.BANK_ACCOUNT.PAGE_NAMES; @@ -41,6 +42,7 @@ const pages: PageEntry[] = [ firstSubPage: PERSONAL_INFO_SUB_PAGES.FULL_NAME, lastSubPage: PERSONAL_INFO_SUB_PAGES.CONFIRMATION, }, + {pageName: PAGE_NAMES.VERIFY_IDENTITY, component: VerifyIdentity as React.ComponentType}, { pageName: PAGE_NAMES.COMPANY, component: BusinessInfo as React.ComponentType, @@ -71,10 +73,10 @@ function USDVerifiedBankAccountFlowPage({route}: USDVerifiedBankAccountFlowPageP const currentSubPage = route.params?.subPage; const backTo = route.params?.backTo; - const [onfidoToken = ''] = useOnyx(ONYXKEYS.ONFIDO_TOKEN); const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT); const requestorStepRef = useRef(null); + const isOnfidoSetupComplete = reimbursementAccount?.achData?.isOnfidoSetupComplete; const currentPageIndex = useMemo(() => { const index = pages.findIndex((p) => p.pageName === currentPage); @@ -83,29 +85,35 @@ function USDVerifiedBankAccountFlowPage({route}: USDVerifiedBankAccountFlowPageP const currentEntry = pages.at(currentPageIndex); const CurrentPage = currentEntry?.component ?? (Country as React.ComponentType); + const isRequestorStep = currentEntry?.pageName === PAGE_NAMES.REQUESTOR; + + const shouldSkipVerifyIdentity = useCallback((pageName?: string) => pageName === PAGE_NAMES.VERIFY_IDENTITY && isOnfidoSetupComplete, [isOnfidoSetupComplete]); const onSubmit = useCallback(() => { - const nextIndex = currentPageIndex + 1; + let nextIndex = currentPageIndex + 1; + if (shouldSkipVerifyIdentity(pages.at(nextIndex)?.pageName)) { + nextIndex += 1; + } if (nextIndex >= pages.length) { Navigation.goBack(); return; } const nextPage = pages.at(nextIndex); Navigation.navigate(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: nextPage?.pageName, subPage: nextPage?.firstSubPage, backTo})); - }, [backTo, currentPageIndex, policyID]); + }, [backTo, currentPageIndex, policyID, shouldSkipVerifyIdentity]); const onBackButtonPress = useCallback(() => { - const prevIndex = currentPageIndex - 1; + let prevIndex = currentPageIndex - 1; + if (shouldSkipVerifyIdentity(pages.at(prevIndex)?.pageName)) { + prevIndex -= 1; + } if (prevIndex < 0) { Navigation.goBack(); return; } const prevPage = pages.at(prevIndex); Navigation.goBack(ROUTES.BANK_ACCOUNT_USD_SETUP.getRoute({policyID, page: prevPage?.pageName, subPage: prevPage?.lastSubPage, backTo})); - }, [backTo, currentPageIndex, policyID]); - - const shouldShowOnfido = !!(onfidoToken && !reimbursementAccount?.achData?.isOnfidoSetupComplete); - const isRequestorStep = currentEntry?.pageName === PAGE_NAMES.REQUESTOR; + }, [backTo, currentPageIndex, policyID, shouldSkipVerifyIdentity]); return ( @@ -115,7 +123,6 @@ function USDVerifiedBankAccountFlowPage({route}: USDVerifiedBankAccountFlowPageP policyID={policyID} currentSubPage={currentSubPage} stepNames={CONST.BANK_ACCOUNT.STEP_NAMES} - shouldShowOnfido={isRequestorStep ? shouldShowOnfido : undefined} ref={isRequestorStep ? requestorStepRef : undefined} backTo={backTo} /> diff --git a/src/pages/ReimbursementAccount/USD/types.ts b/src/pages/ReimbursementAccount/USD/types.ts index 12fae45bd46ca..c808a68bff8f4 100644 --- a/src/pages/ReimbursementAccount/USD/types.ts +++ b/src/pages/ReimbursementAccount/USD/types.ts @@ -18,9 +18,6 @@ type USDPageProps = { /** Array of step names for the progress indicator */ stepNames?: readonly string[]; - /** If we should show Onfido flow (used by RequestorStep) */ - shouldShowOnfido?: boolean; - /** Reference to the outer element (used by RequestorStep) */ ref?: ForwardedRef; From 507fc44bd2d1205258453fd03f777c1bdf5a797e Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 30 Mar 2026 17:21:32 +0200 Subject: [PATCH 19/20] fix: remove unused import --- src/libs/ReimbursementAccountUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReimbursementAccountUtils.ts b/src/libs/ReimbursementAccountUtils.ts index 37c9ecfe3a23f..912ac6f24fcde 100644 --- a/src/libs/ReimbursementAccountUtils.ts +++ b/src/libs/ReimbursementAccountUtils.ts @@ -1,6 +1,6 @@ import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; -import type {ACHDataReimbursementAccount, ReimbursementAccountStep} from '@src/types/onyx/ReimbursementAccount'; +import type {ACHDataReimbursementAccount} from '@src/types/onyx/ReimbursementAccount'; type ReimbursementAccountStepToOpen = ValueOf | ''; From 78ba0f5a378f867e8392721f22f1121235f81b81 Mon Sep 17 00:00:00 2001 From: Agata Kosior Date: Mon, 30 Mar 2026 17:29:39 +0200 Subject: [PATCH 20/20] fix: eslint --- .../USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx index a804f8b259753..a984c54e54b69 100644 --- a/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx +++ b/src/pages/ReimbursementAccount/USD/BeneficialOwnerInfo/BeneficialOwnersStep.tsx @@ -55,7 +55,8 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli const beneficialOwners = reimbursementAccount?.achData?.beneficialOwners; const isAnyoneElseUBO = beneficialOwners?.length ? true : (reimbursementAccountDraft?.hasOtherBeneficialOwners ?? false); const beneficialOwnerKeys: string[] = reimbursementAccountDraft?.beneficialOwnerKeys ?? reimbursementAccount?.achData?.beneficialOwnerKeys ?? []; - const beneficialOwnerBeingModifiedID = reimbursementAccountDraft?.ownerBeingModifiedID; + // eslint-disable-next-line rulesdir/no-default-id-values + const beneficialOwnerBeingModifiedID = reimbursementAccountDraft?.ownerBeingModifiedID ?? ''; const isEditingCreatedBeneficialOwner = reimbursementAccountDraft?.isEditingCreatedOwner ?? false; const canAddMoreUBOS = beneficialOwnerKeys.length < (isUserUBO ? MAX_NUMBER_OF_UBOS - 1 : MAX_NUMBER_OF_UBOS); @@ -201,7 +202,7 @@ function BeneficialOwnersStep({onBackButtonPress, onSubmit, currentSubPage, poli return ( setDraftValues(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM, {ownerBeingModifiedID: id})} isEditingCreatedBeneficialOwner={isEditingCreatedBeneficialOwner}