diff --git a/src/libs/actions/ReimbursementAccount/resetNonUSDBankAccount.ts b/src/libs/actions/ReimbursementAccount/resetNonUSDBankAccount.ts index f4145d0631e0..2921f6229155 100644 --- a/src/libs/actions/ReimbursementAccount/resetNonUSDBankAccount.ts +++ b/src/libs/actions/ReimbursementAccount/resetNonUSDBankAccount.ts @@ -38,7 +38,11 @@ function resetNonUSDBankAccount(policyID: string | undefined, achAccount: OnyxEn const isPreviousLastUsedPaymentMethodVBBA = lastUsedPaymentMethod?.lastUsed?.name === CONST.IOU.PAYMENT_TYPE.VBBA; const onyxData: OnyxData< - typeof ONYXKEYS.NVP_LAST_PAYMENT_METHOD | typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT | typeof ONYXKEYS.COLLECTION.POLICY | typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT + | typeof ONYXKEYS.NVP_LAST_PAYMENT_METHOD + | typeof ONYXKEYS.REIMBURSEMENT_ACCOUNT + | typeof ONYXKEYS.COLLECTION.POLICY + | typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT + | typeof ONYXKEYS.BANK_ACCOUNT_LIST > = { optimisticData: [ { @@ -51,6 +55,11 @@ function resetNonUSDBankAccount(policyID: string | undefined, achAccount: OnyxEn achData: null, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.BANK_ACCOUNT_LIST, + value: {[bankAccountID]: {pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE}}, + }, ], successData: [ { @@ -63,6 +72,11 @@ function resetNonUSDBankAccount(policyID: string | undefined, achAccount: OnyxEn key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, value: CONST.REIMBURSEMENT_ACCOUNT.DEFAULT_DATA, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.BANK_ACCOUNT_LIST, + value: {[bankAccountID]: null}, + }, ], failureData: [ { @@ -70,6 +84,11 @@ function resetNonUSDBankAccount(policyID: string | undefined, achAccount: OnyxEn key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, value: {isLoading: false, pendingAction: null}, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.BANK_ACCOUNT_LIST, + value: {[bankAccountID]: {pendingAction: null}}, + }, ], }; diff --git a/src/libs/actions/ReimbursementAccount/resetUSDBankAccount.ts b/src/libs/actions/ReimbursementAccount/resetUSDBankAccount.ts index ce33a5b144cc..15d5e13f43f4 100644 --- a/src/libs/actions/ReimbursementAccount/resetUSDBankAccount.ts +++ b/src/libs/actions/ReimbursementAccount/resetUSDBankAccount.ts @@ -38,6 +38,7 @@ function resetUSDBankAccount( | typeof ONYXKEYS.RAM_ONLY_PLAID_LINK_TOKEN | typeof ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT | typeof ONYXKEYS.NVP_LAST_PAYMENT_METHOD + | typeof ONYXKEYS.BANK_ACCOUNT_LIST > = { optimisticData: [ { @@ -57,6 +58,11 @@ function resetUSDBankAccount( achAccount: null, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.BANK_ACCOUNT_LIST, + value: {[bankAccountID]: {pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE}}, + }, ], successData: [ { @@ -128,6 +134,11 @@ function resetUSDBankAccount( [INPUT_IDS.AMOUNT3]: '', }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.BANK_ACCOUNT_LIST, + value: {[bankAccountID]: null}, + }, ], failureData: [ { @@ -142,6 +153,11 @@ function resetUSDBankAccount( achAccount, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.BANK_ACCOUNT_LIST, + value: {[bankAccountID]: {pendingAction: null}}, + }, ], }; diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx index 4e13e60f3a2d..44ea160f28c2 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx @@ -322,6 +322,8 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { const isBusinessBankAccountLocked = state === CONST.BANK_ACCOUNT.STATE.LOCKED; const shouldShowBankAccount = (!!isBankAccountFullySetup || !!bankAccountConnectedToWorkspace) && policy?.reimbursementChoice !== CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_NO; + const bankAccountPendingAction = bankAccountConnectedToWorkspace?.pendingAction; + const isBankAccountPendingDelete = bankAccountPendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; const bankIcon = getBankIcon({bankName: bankName as BankName, isCard: false, styles}); @@ -526,7 +528,7 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { subMenuItems: ( <> {shouldShowBankAccount ? ( - <> + {translate('workflowsPayerPage.paymentAccount')} @@ -561,6 +563,8 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { iconHeight={bankIcon.iconHeight ?? bankIcon.iconSize} iconWidth={bankIcon.iconWidth ?? bankIcon.iconSize} iconStyles={bankIcon.iconStyles} + titleStyle={isBankAccountPendingDelete ? styles.offlineFeedbackDeleted : undefined} + descriptionTextStyle={isBankAccountPendingDelete ? styles.offlineFeedbackDeleted : undefined} disabled={isOffline || !isPolicyAdmin} badgeText={getBadgeText(accountData?.state)} sentryLabel={CONST.SENTRY_LABEL.WORKSPACE.WORKFLOWS.BANK_ACCOUNT} @@ -572,7 +576,7 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { wrapperStyle={[styles.sectionMenuItemTopDescription, styles.mt3, styles.mbn3]} brickRoadIndicator={hasReimburserError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} /> - + ) : ( { }), ); }); + + it('should optimistically mark bank account as pending deletion', async () => { + (fetch as MockFetch)?.pause?.(); + const achAccount: ACHAccount = { + bankAccountID, + addressName: 'Test Address', + bankName: 'Test Bank', + reimburser: TEST_EMAIL, + accountNumber: '1234567890', + routingNumber: '123456789', + }; + await Onyx.set(ONYXKEYS.BANK_ACCOUNT_LIST, { + [bankAccountID]: {bankCurrency: 'USD', bankCountry: 'US'}, + }); + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {achAccount}); + resetUSDBankAccount(bankAccountID, session, policyID, achAccount); + + await waitForBatchedUpdates(); + return new Promise((resolve) => { + const connection = Onyx.connect({ + key: ONYXKEYS.BANK_ACCOUNT_LIST, + callback: (bankAccountList) => { + Onyx.disconnect(connection); + expect(bankAccountList?.[bankAccountID]?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); + resolve(); + }, + }); + }); + }); + + it('should remove bank account from list on success', async () => { + const achAccount: ACHAccount = { + bankAccountID, + addressName: 'Test Address', + bankName: 'Test Bank', + reimburser: TEST_EMAIL, + accountNumber: '1234567890', + routingNumber: '123456789', + }; + await Onyx.set(ONYXKEYS.BANK_ACCOUNT_LIST, { + [bankAccountID]: {bankCurrency: 'USD', bankCountry: 'US'}, + }); + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {achAccount}); + resetUSDBankAccount(bankAccountID, session, policyID, achAccount); + + await waitForBatchedUpdates(); + return new Promise((resolve) => { + const connection = Onyx.connect({ + key: ONYXKEYS.BANK_ACCOUNT_LIST, + callback: (bankAccountList) => { + Onyx.disconnect(connection); + expect(bankAccountList?.[bankAccountID]).toBeUndefined(); + resolve(); + }, + }); + }); + }); + }); + + describe('resetNonUSDBankAccount', () => { + afterEach(() => { + mockFetch?.resume?.(); + }); + + it('should optimistically mark bank account as pending deletion', async () => { + (fetch as MockFetch)?.pause?.(); + const achAccount: ACHAccount = { + bankAccountID, + addressName: 'Test Address', + bankName: 'Test Bank', + reimburser: TEST_EMAIL, + accountNumber: '1234567890', + routingNumber: '123456789', + }; + await Onyx.set(ONYXKEYS.BANK_ACCOUNT_LIST, { + [bankAccountID]: {bankCurrency: 'CAD', bankCountry: 'CA'}, + }); + resetNonUSDBankAccount(policyID, achAccount, bankAccountID); + + await waitForBatchedUpdates(); + return new Promise((resolve) => { + const connection = Onyx.connect({ + key: ONYXKEYS.BANK_ACCOUNT_LIST, + callback: (bankAccountList) => { + Onyx.disconnect(connection); + expect(bankAccountList?.[bankAccountID]?.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE); + resolve(); + }, + }); + }); + }); + + it('should remove bank account from list on success', async () => { + const achAccount: ACHAccount = { + bankAccountID, + addressName: 'Test Address', + bankName: 'Test Bank', + reimburser: TEST_EMAIL, + accountNumber: '1234567890', + routingNumber: '123456789', + }; + await Onyx.set(ONYXKEYS.BANK_ACCOUNT_LIST, { + [bankAccountID]: {bankCurrency: 'CAD', bankCountry: 'CA'}, + }); + resetNonUSDBankAccount(policyID, achAccount, bankAccountID); + + await waitForBatchedUpdates(); + return new Promise((resolve) => { + const connection = Onyx.connect({ + key: ONYXKEYS.BANK_ACCOUNT_LIST, + callback: (bankAccountList) => { + Onyx.disconnect(connection); + expect(bankAccountList?.[bankAccountID]).toBeUndefined(); + resolve(); + }, + }); + }); + }); + + it('should clear policy achAccount optimistically', async () => { + (fetch as MockFetch)?.pause?.(); + const achAccount: ACHAccount = { + bankAccountID, + addressName: 'Test Address', + bankName: 'Test Bank', + reimburser: TEST_EMAIL, + accountNumber: '1234567890', + routingNumber: '123456789', + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {achAccount}); + resetNonUSDBankAccount(policyID, achAccount, bankAccountID); + + await waitForBatchedUpdates(); + return new Promise((resolve) => { + const connection = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (policy) => { + Onyx.disconnect(connection); + expect(policy?.achAccount).toBeUndefined(); + resolve(); + }, + }); + }); + }); + + it('should reset locally without API call when no bankAccountID', async () => { + const achAccount: ACHAccount = { + bankAccountID: 0, + addressName: 'Test Address', + bankName: 'Test Bank', + reimburser: TEST_EMAIL, + accountNumber: '1234567890', + routingNumber: '123456789', + }; + await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {achAccount}); + resetNonUSDBankAccount(policyID, achAccount); + + await waitForBatchedUpdates(); + return new Promise((resolve) => { + const connection = Onyx.connect({ + key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, + callback: (reimbursementAccount) => { + Onyx.disconnect(connection); + expect(reimbursementAccount).toEqual(CONST.REIMBURSEMENT_ACCOUNT.DEFAULT_DATA); + resolve(); + }, + }); + }); + }); }); });