diff --git a/src/ROUTES.ts b/src/ROUTES.ts index fed1194852e3..f07e469188b0 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -162,6 +162,10 @@ const ROUTES = { return `bank-account/enter-signer-info?policyID=${policyID}&bankAccountID=${bankAccountID}&isCompleted=${isCompleted}` as const; }, }, + BANK_ACCOUNT_CONNECT_EXISTING_BUSINESS_BANK_ACCOUNT: { + route: 'bank-account/connect-existing-business-bank-account', + getRoute: (policyID: string) => `bank-account/connect-existing-business-bank-account?policyID=${policyID}` as const, + }, PUBLIC_CONSOLE_DEBUG: { route: 'troubleshoot/console', @@ -1550,10 +1554,6 @@ const ROUTES = { return `workspaces/${policyID}/workflows` as const; }, }, - WORKSPACE_WORKFLOWS_CONNECT_EXISTING_BANK_ACCOUNT: { - route: 'workspaces/:policyID/workflows/connect-account', - getRoute: (policyID: string) => `workspaces/${policyID}/workflows/connect-account` as const, - }, WORKSPACE_WORKFLOWS_APPROVALS_NEW: { route: 'workspaces/:policyID/workflows/approvals/new', getRoute: (policyID: string) => `workspaces/${policyID}/workflows/approvals/new` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index b4baa0ef4ab9..d5ede296b728 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -623,7 +623,6 @@ const SCREENS = { WORKFLOWS_APPROVALS_APPROVER: 'Workspace_Workflows_Approvals_Approver', WORKFLOWS_AUTO_REPORTING_FREQUENCY: 'Workspace_Workflows_Auto_Reporting_Frequency', WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET: 'Workspace_Workflows_Auto_Reporting_Monthly_Offset', - WORKFLOWS_CONNECT_EXISTING_BANK_ACCOUNT: 'Workspace_Workflows_Connect_Existing_Bank_Account', DESCRIPTION: 'Workspace_Overview_Description', SHARE: 'Workspace_Overview_Share', NAME: 'Workspace_Overview_Name', @@ -740,6 +739,7 @@ const SCREENS = { ENABLE_PAYMENTS_ROOT: 'EnablePayments_Root', ADD_PERSONAL_BANK_ACCOUNT_ROOT: 'AddPersonalBankAccount_Root', REIMBURSEMENT_ACCOUNT_ROOT: 'Reimbursement_Account_Root', + CONNECT_EXISTING_BUSINESS_BANK_ACCOUNT_ROOT: 'Connect_Existing_Business_Bank_Account_Root', WALLET_STATEMENT_ROOT: 'WalletStatement_Root', SIGN_IN_ROOT: 'SignIn_Root', DETAILS_ROOT: 'Details_Root', diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx index e70c03a74377..03c9538d7de1 100644 --- a/src/components/KYCWall/BaseKYCWall.tsx +++ b/src/components/KYCWall/BaseKYCWall.tsx @@ -12,9 +12,12 @@ import getClickedTargetLocation from '@libs/getClickedTargetLocation'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import {hasExpensifyPaymentMethod} from '@libs/PaymentUtils'; +import {hasInProgressVBBA} from '@libs/ReimbursementAccountUtils'; import {getBankAccountRoute, isExpenseReport as isExpenseReportReportUtils, isIOUReport} from '@libs/ReportUtils'; +import {getEligibleExistingBusinessBankAccounts} from '@libs/WorkflowUtils'; import {kycWallRef} from '@userActions/PaymentMethods'; import {createWorkspaceFromIOUPayment} from '@userActions/Policy/Policy'; +import {navigateToBankAccountRoute} from '@userActions/ReimbursementAccount'; import {setKYCWallSource} from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -56,6 +59,7 @@ function KYCWall({ const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {canBeMissing: true}); const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, {canBeMissing: true}); const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); + const [reimbursementAccountDraft] = useOnyx(ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT, {canBeMissing: true}); const {formatPhoneNumber} = useLocalize(); @@ -108,6 +112,11 @@ function KYCWall({ setPositionAddPaymentMenu(position); }, [getAnchorPosition]); + const canLinkExistingBusinessBankAccount = useCallback( + (policy?: Policy) => policy !== undefined && getEligibleExistingBusinessBankAccounts(bankAccountList, policy.outputCurrency).length > 0, + [bankAccountList], + ); + const selectPaymentMethod = useCallback( (paymentMethod?: PaymentMethod, policy?: Policy) => { if (paymentMethod) { @@ -153,11 +162,36 @@ function KYCWall({ Navigation.navigate(ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute(policyID)); return; } + + // If user has a setup in progress we do not show them the option to connect existing account + const isNonUSDWorkspace = policy?.outputCurrency !== CONST.CURRENCY.USD; + if (policy !== undefined && hasInProgressVBBA(reimbursementAccount?.achData, isNonUSDWorkspace, reimbursementAccountDraft?.country ?? '')) { + navigateToBankAccountRoute(policy.id); + return; + } + + if (policy !== undefined && canLinkExistingBusinessBankAccount(policy)) { + Navigation.navigate(ROUTES.BANK_ACCOUNT_CONNECT_EXISTING_BUSINESS_BANK_ACCOUNT.getRoute(policy?.id)); + return; + } + const bankAccountRoute = addBankAccountRoute ?? getBankAccountRoute(chatReport); Navigation.navigate(bankAccountRoute); } }, - [addBankAccountRoute, addDebitCardRoute, chatReport, iouReport, onSelectPaymentMethod, formatPhoneNumber, lastPaymentMethod, policies], + [ + onSelectPaymentMethod, + iouReport, + addDebitCardRoute, + reimbursementAccount?.achData, + reimbursementAccountDraft?.country, + canLinkExistingBusinessBankAccount, + addBankAccountRoute, + chatReport, + policies, + formatPhoneNumber, + lastPaymentMethod, + ], ); /** diff --git a/src/components/SettlementButton/index.tsx b/src/components/SettlementButton/index.tsx index b0d22daa0bb7..22de67d57c90 100644 --- a/src/components/SettlementButton/index.tsx +++ b/src/components/SettlementButton/index.tsx @@ -33,6 +33,7 @@ import { import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; import {setPersonalBankAccountContinueKYCOnSuccess} from '@userActions/BankAccounts'; import {approveMoneyRequest} from '@userActions/IOU'; +import {getPaymentMethods} from '@userActions/PaymentMethods'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -131,6 +132,13 @@ function SettlementButton({ const formattedPaymentMethods = formatPaymentMethods(bankAccountList ?? {}, fundList ?? {}, styles); const hasIntentToPay = ((formattedPaymentMethods.length === 1 && isIOUReport(iouReport)) || !!policy?.achAccount) && !lastPaymentMethod; + useEffect(() => { + if (isOffline) { + return; + } + getPaymentMethods(); + }, [isOffline]); + useEffect(() => { if (isLoadingLastPaymentMethod) { return; @@ -428,7 +436,9 @@ function SettlementButton({ return lastPaymentPolicy.name; } - const bankAccountToDisplay = hasIntentToPay ? (formattedPaymentMethods.at(0) as BankAccount) : bankAccount; + const bankAccountToDisplay = hasIntentToPay + ? ((formattedPaymentMethods.find((method) => method.methodID === policy?.achAccount?.bankAccountID) ?? formattedPaymentMethods.at(0)) as BankAccount) + : bankAccount; if (lastPaymentMethod === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || (hasIntentToPay && isInvoiceReportUtil(iouReport))) { if (!personalBankAccountList.length) { return; @@ -446,6 +456,12 @@ function SettlementButton({ return; } + if (bankAccountToDisplay?.accountData?.accountNumber) { + return translate('paymentMethodList.bankAccountLastFour', { + lastFour: bankAccountToDisplay.accountData.accountNumber.slice(-4), + }); + } + return translate('paymentMethodList.bankAccountLastFour', {lastFour: bankAccountToDisplay?.accountData?.accountNumber?.slice(-4)}); } @@ -468,8 +484,7 @@ function SettlementButton({ const isPaymentMethod = Object.values(CONST.PAYMENT_METHODS).includes(selectedOption as PaymentMethod); const shouldSelectPaymentMethod = (isPaymentMethod ?? lastPaymentPolicy ?? !isEmpty(latestBankItem)) && !shouldShowApproveButton && !shouldHidePaymentOptions; - const selectedPolicy = activeAdminPolicies.find((activePolicy) => activePolicy.id === selectedOption); - + const selectedPolicy = activeAdminPolicies.find((activePolicy) => activePolicy.id === policyIDKey); if (!!selectedPolicy || shouldSelectPaymentMethod) { selectPaymentMethod(event, triggerKYCFlow, selectedOption as PaymentMethod, selectedPolicy); return; diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 46bbfe11fd52..cbc6722e0a30 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -501,8 +501,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/accounting/qbd/import/QuickbooksDesktopCustomersDisplayedAsPage').default, [SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_DESKTOP_ITEMS]: () => require('../../../../pages/workspace/accounting/qbd/import/QuickbooksDesktopItemsPage').default, - [SCREENS.WORKSPACE.WORKFLOWS_CONNECT_EXISTING_BANK_ACCOUNT]: () => - require('../../../../pages/workspace/workflows/WorkspaceWorkflowsConnectExistingBankAccountPage').default, + [SCREENS.CONNECT_EXISTING_BUSINESS_BANK_ACCOUNT_ROOT]: () => require('@pages/workspace/ConnectExistingBusinessBankAccountPage').default, [SCREENS.REIMBURSEMENT_ACCOUNT]: () => require('../../../../pages/ReimbursementAccount/ReimbursementAccountPage').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/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts index 84d4419c99af..53beabac307e 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts @@ -33,7 +33,6 @@ const WORKSPACE_TO_RHP: Partial['config'] = { [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: { path: ROUTES.WORKSPACE_EDIT_REPORT_FIELDS_INITIAL_VALUE.route, }, - [SCREENS.WORKSPACE.WORKFLOWS_CONNECT_EXISTING_BANK_ACCOUNT]: { - path: ROUTES.WORKSPACE_WORKFLOWS_CONNECT_EXISTING_BANK_ACCOUNT.route, + [SCREENS.CONNECT_EXISTING_BUSINESS_BANK_ACCOUNT_ROOT]: { + path: ROUTES.BANK_ACCOUNT_CONNECT_EXISTING_BUSINESS_BANK_ACCOUNT.route, exact: true, }, [SCREENS.REIMBURSEMENT_ACCOUNT]: { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index c431b82e8eed..46d5926adc17 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1698,6 +1698,12 @@ type ReimbursementAccountEnterSignerInfoNavigatorParamList = { }; }; +type ConnectExistingBankAccountNavigatorParamList = { + [SCREENS.CONNECT_EXISTING_BUSINESS_BANK_ACCOUNT_ROOT]: { + policyID: string; + }; +}; + type WalletStatementNavigatorParamList = { [SCREENS.WALLET_STATEMENT_ROOT]: { /** The statement year and month as one string, i.e. 202110 */ @@ -1989,9 +1995,6 @@ type WorkspaceSplitNavigatorParamList = { [SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET]: { policyID: string; }; - [SCREENS.WORKSPACE.WORKFLOWS_CONNECT_EXISTING_BANK_ACCOUNT]: { - policyID: string; - }; [SCREENS.WORKSPACE.INVOICES]: { policyID: string; }; @@ -2435,6 +2438,7 @@ export type { ReferralDetailsNavigatorParamList, ReimbursementAccountNavigatorParamList, ReimbursementAccountEnterSignerInfoNavigatorParamList, + ConnectExistingBankAccountNavigatorParamList, NewReportWorkspaceSelectionNavigatorParamList, ReportDescriptionNavigatorParamList, ReportDetailsNavigatorParamList, diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index f09d45c21bf1..a85620bff5b3 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -95,6 +95,9 @@ type PaymentMethodListProps = { /** Type of payment method to filter by */ filterType?: ValueOf; + /* Currency of payment method to filter by */ + filterCurrency?: string; + /** Whether to show the default badge for the payment method */ shouldHideDefaultBadge?: boolean; }; @@ -185,6 +188,7 @@ function PaymentMethodList({ onAddBankAccountPress = () => {}, itemIconRight, filterType, + filterCurrency, shouldHideDefaultBadge = false, }: PaymentMethodListProps) { const styles = useThemeStyles(); @@ -322,8 +326,12 @@ function PaymentMethodList({ ); } - if (filterType) { - combinedPaymentMethods = combinedPaymentMethods.filter((paymentMethod) => (paymentMethod as BankAccount).accountData?.type === filterType); + if (filterType ?? filterCurrency) { + combinedPaymentMethods = combinedPaymentMethods.filter((paymentMethod) => { + const account = paymentMethod as BankAccount; + + return (!!filterType && account.accountData?.type === filterType) || (!!filterCurrency && account.bankCurrency === filterCurrency); + }); } combinedPaymentMethods = combinedPaymentMethods.map((paymentMethod) => { @@ -362,6 +370,7 @@ function PaymentMethodList({ styles, isOffline, filterType, + filterCurrency, isLoadingCardList, cardList, illustrations, diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsConnectExistingBankAccountPage.tsx b/src/pages/workspace/ConnectExistingBusinessBankAccountPage.tsx similarity index 77% rename from src/pages/workspace/workflows/WorkspaceWorkflowsConnectExistingBankAccountPage.tsx rename to src/pages/workspace/ConnectExistingBusinessBankAccountPage.tsx index c04453d2bdee..ca2948917548 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsConnectExistingBankAccountPage.tsx +++ b/src/pages/workspace/ConnectExistingBusinessBankAccountPage.tsx @@ -10,46 +10,50 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@navigation/Navigation'; import type {PlatformStackScreenProps} from '@navigation/PlatformStackNavigation/types'; -import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; +import type {ConnectExistingBankAccountNavigatorParamList} from '@navigation/types'; import PaymentMethodList from '@pages/settings/Wallet/PaymentMethodList'; import type {PaymentMethodPressHandlerParams} from '@pages/settings/Wallet/WalletPage/types'; import {setWorkspaceReimbursement} from '@userActions/Policy/Policy'; import {navigateToBankAccountRoute} from '@userActions/ReimbursementAccount'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -type WorkspaceWorkflowsConnectExistingBankAccountPageProps = PlatformStackScreenProps; +type ConnectExistingBusinessBankAccountPageProps = PlatformStackScreenProps; -function WorkspaceWorkflowsConnectExistingBankAccountPage({route}: WorkspaceWorkflowsConnectExistingBankAccountPageProps) { +function ConnectExistingBusinessBankAccountPage({route}: ConnectExistingBusinessBankAccountPageProps) { const policyID = route.params?.policyID; const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {canBeMissing: false}); const policyName = policy?.name ?? ''; + const policyCurrency = policy?.outputCurrency ?? ''; const {shouldUseNarrowLayout} = useResponsiveLayout(); const styles = useThemeStyles(); const {translate} = useLocalize(); const handleAddBankAccountPress = () => { - navigateToBankAccountRoute(route.params.policyID, ROUTES.WORKSPACE_WORKFLOWS.getRoute(route.params.policyID)); + navigateToBankAccountRoute(policyID); }; const handleItemPress = ({methodID}: PaymentMethodPressHandlerParams) => { + if (policyID === undefined) { + return; + } + const newReimburserEmail = policy?.achAccount?.reimburser ?? policy?.owner ?? ''; setWorkspaceReimbursement({ - policyID: route.params.policyID, + policyID, reimbursementChoice: CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES, bankAccountID: methodID ?? CONST.DEFAULT_NUMBER_ID, reimburserEmail: newReimburserEmail, }); - Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.goBack(ROUTES.WORKSPACE_WORKFLOWS.getRoute(policyID))); + Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.closeRHPFlow()); }; return ( @@ -72,6 +77,6 @@ function WorkspaceWorkflowsConnectExistingBankAccountPage({route}: WorkspaceWork ); } -WorkspaceWorkflowsConnectExistingBankAccountPage.displayName = 'WorkspaceWorkflowsConnectExistingBankAccountPage'; +ConnectExistingBusinessBankAccountPage.displayName = 'ConnectExistingBusinessBankAccountPage'; -export default WorkspaceWorkflowsConnectExistingBankAccountPage; +export default ConnectExistingBusinessBankAccountPage; diff --git a/src/pages/workspace/WorkspaceOverviewCurrencyPage.tsx b/src/pages/workspace/WorkspaceOverviewCurrencyPage.tsx index 8c2e7acf2c72..bf25beba9619 100644 --- a/src/pages/workspace/WorkspaceOverviewCurrencyPage.tsx +++ b/src/pages/workspace/WorkspaceOverviewCurrencyPage.tsx @@ -51,7 +51,7 @@ function WorkspaceOverviewCurrencyPage({policy}: WorkspaceOverviewCurrencyPagePr if (isCurrencySupportedForGlobalReimbursement(item.currencyCode as CurrencyType, isBetaEnabled(CONST.BETAS.GLOBAL_REIMBURSEMENTS_ON_ND))) { const hasValidExistingAccounts = getEligibleExistingBusinessBankAccounts(bankAccountList, item.currencyCode).length > 0; if (hasValidExistingAccounts) { - Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_CONNECT_EXISTING_BANK_ACCOUNT.getRoute(policy.id)); + Navigation.navigate(ROUTES.BANK_ACCOUNT_CONNECT_EXISTING_BUSINESS_BANK_ACCOUNT.getRoute(policy.id)); return; } navigateToBankAccountRoute(policy.id, ROUTES.WORKSPACE_WORKFLOWS.getRoute(policy.id), {forceReplace: true}); diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx index c5ec3e27a50d..b299f7bd030c 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx @@ -128,7 +128,7 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { updateGeneralSettings(policy.id, policy.name, CONST.CURRENCY.USD); const hasValidExistingUSDAccounts = getEligibleExistingBusinessBankAccounts(bankAccountList, CONST.CURRENCY.USD).length > 0; if (hasValidExistingUSDAccounts) { - Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_CONNECT_EXISTING_BANK_ACCOUNT.getRoute(route.params.policyID)); + Navigation.navigate(ROUTES.BANK_ACCOUNT_CONNECT_EXISTING_BUSINESS_BANK_ACCOUNT.getRoute(route.params.policyID)); } else { navigateToBankAccountRoute(route.params.policyID, ROUTES.WORKSPACE_WORKFLOWS.getRoute(route.params.policyID)); } @@ -308,7 +308,7 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { } if (!shouldShowBankAccount && hasValidExistingAccounts && !shouldShowContinueModal) { - Navigation.navigate(ROUTES.WORKSPACE_WORKFLOWS_CONNECT_EXISTING_BANK_ACCOUNT.getRoute(route.params.policyID)); + Navigation.navigate(ROUTES.BANK_ACCOUNT_CONNECT_EXISTING_BUSINESS_BANK_ACCOUNT.getRoute(route.params.policyID)); return; }