From af250e728b4fef63e5385d374fa33e691c043864 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 6 May 2026 19:26:44 +0500 Subject: [PATCH 1/8] Refactor bulk payment option logic to always show Pay Submenu --- src/hooks/useSearchBulkActions.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts index 4ec0c8d62eb4..ad538aecefbe 100644 --- a/src/hooks/useSearchBulkActions.ts +++ b/src/hooks/useSearchBulkActions.ts @@ -1229,13 +1229,12 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { }, }); } - const {shouldEnableBulkPayOption, isFirstTimePayment} = getPayOption(selectedReports, selectedTransactions, lastPaymentMethods, selectedReportIDs, personalPolicyID); + const {shouldEnableBulkPayOption} = getPayOption(selectedReports, selectedTransactions, lastPaymentMethods, selectedReportIDs, personalPolicyID); const shouldShowPayOption = !isOffline && !isAnyTransactionOnHold && shouldEnableBulkPayOption; if (shouldShowPayOption) { - const hasMultipleBusinessBankAccounts = (businessBankAccountOptions?.length ?? 0) > 1; - const shouldShowPaySubmenu = isFirstTimePayment || (shouldShowBusinessBankAccountOptions && hasMultipleBusinessBankAccounts); + const shouldShowPaySubmenu = !!bulkPayButtonOptions?.length; const payButtonOption = { icon: expensifyIcons.MoneyBag, From 229bd6adaa4aca849bf2f762db10beee0833f37e Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 6 May 2026 19:27:39 +0500 Subject: [PATCH 2/8] Refactor getPayOption to simplify currency and report type checks for bulk payment --- src/libs/actions/Search.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index dfb748fe4570..6215f1ab58cf 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -1326,17 +1326,15 @@ function getPayOption( ? selectedReports.every( (report) => report.allActions.includes(CONST.SEARCH.ACTION_TYPES.PAY) && - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - ((hasLastPaymentMethod && report.policyID) || (getReportType(report.reportID) === getReportType(firstReport?.reportID) && report.policyID === firstReport?.policyID)) && + getReportType(report.reportID) === getReportType(firstReport?.reportID) && + report.currency === firstReport?.currency && shouldShowBulkOptionForRemainingTransactions(selectedTransactions, selectedReportIDs, transactionKeys), ) : transactionKeys.every( (transactionIDKey) => selectedTransactions[transactionIDKey].action === CONST.SEARCH.ACTION_TYPES.PAY && - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - ((hasLastPaymentMethod && selectedTransactions[transactionIDKey].policyID) || - (getReportType(selectedTransactions[transactionIDKey].reportID) === getReportType(firstTransaction?.reportID) && - selectedTransactions[transactionIDKey].policyID === firstTransaction?.policyID)), + getReportType(selectedTransactions[transactionIDKey].reportID) === getReportType(firstTransaction?.reportID) && + selectedTransactions[transactionIDKey].currency === firstTransaction?.currency, ); return { From a885babfa8e9ac3eb55162ebd918794d7efc86a3 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Wed, 6 May 2026 22:56:25 +0500 Subject: [PATCH 3/8] update bulk pay to show pay elsewhere for different currencies Co-authored-by: Copilot --- src/hooks/useSearchBulkActions.ts | 5 ++++- src/libs/actions/Search.ts | 10 +++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts index ad538aecefbe..91835b5d6c3f 100644 --- a/src/hooks/useSearchBulkActions.ts +++ b/src/hooks/useSearchBulkActions.ts @@ -334,13 +334,16 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { }); }, [currentSearchResults?.data, selectedPolicyIDs, selectedReportIDs, selectedTransactionReportIDs, bankAccountList]); + const selectedCurrencies = selectedReports.length > 0 ? selectedReports.map((report) => report.currency) : Object.values(selectedTransactions).map((transaction) => transaction.currency); + const hasMixedCurrencies = new Set(selectedCurrencies).size > 1; + const {bulkPayButtonOptions, businessBankAccountOptions, shouldShowBusinessBankAccountOptions} = useBulkPayOptions({ selectedPolicyID: selectedPolicyIDs.at(0), selectedReportID: selectedTransactionReportIDs.at(0) ?? selectedReportIDs.at(0), isCurrencySupportedWallet: isCurrencySupportedBulkWallet, currency: selectedBulkCurrency, formattedAmount: totalFormattedAmount, - onlyShowPayElsewhere, + onlyShowPayElsewhere: onlyShowPayElsewhere || hasMixedCurrencies, }); const {status, hash} = queryJSON ?? {}; diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index 6215f1ab58cf..9d8a64d55e1d 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -1321,25 +1321,29 @@ function getPayOption( ? selectedReports.every((report) => !!getLastPolicyPaymentMethod(report.policyID, personalPolicyID, lastPaymentMethods)) : transactionKeys.every((transactionIDKey) => !!getLastPolicyPaymentMethod(selectedTransactions[transactionIDKey].policyID, personalPolicyID, lastPaymentMethods)); + const selectedCurrencies = + selectedReports.length > 0 ? selectedReports.map((report) => report.currency) : transactionKeys.map((transactionIDKey) => selectedTransactions[transactionIDKey].currency); + + const hasMixedCurrencies = new Set(selectedCurrencies).size > 1; + const shouldShowBulkPayOption = selectedReports.length > 0 ? selectedReports.every( (report) => report.allActions.includes(CONST.SEARCH.ACTION_TYPES.PAY) && getReportType(report.reportID) === getReportType(firstReport?.reportID) && - report.currency === firstReport?.currency && shouldShowBulkOptionForRemainingTransactions(selectedTransactions, selectedReportIDs, transactionKeys), ) : transactionKeys.every( (transactionIDKey) => selectedTransactions[transactionIDKey].action === CONST.SEARCH.ACTION_TYPES.PAY && - getReportType(selectedTransactions[transactionIDKey].reportID) === getReportType(firstTransaction?.reportID) && - selectedTransactions[transactionIDKey].currency === firstTransaction?.currency, + getReportType(selectedTransactions[transactionIDKey].reportID) === getReportType(firstTransaction?.reportID), ); return { shouldEnableBulkPayOption: shouldShowBulkPayOption, isFirstTimePayment: !hasLastPaymentMethod, + hasMixedCurrencies, }; } From aeb4913c50306ffa074c0a38b821fd5dd3cf0c02 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Thu, 7 May 2026 23:30:03 +0500 Subject: [PATCH 4/8] update bulk pay logic to handle a case if user has selected both report and some transactions --- src/hooks/useSearchBulkActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts index 91835b5d6c3f..2148be952f3e 100644 --- a/src/hooks/useSearchBulkActions.ts +++ b/src/hooks/useSearchBulkActions.ts @@ -334,7 +334,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { }); }, [currentSearchResults?.data, selectedPolicyIDs, selectedReportIDs, selectedTransactionReportIDs, bankAccountList]); - const selectedCurrencies = selectedReports.length > 0 ? selectedReports.map((report) => report.currency) : Object.values(selectedTransactions).map((transaction) => transaction.currency); + const selectedCurrencies = [...selectedReports.map((report) => report.currency), ...Object.values(selectedTransactions).map((transaction) => transaction.currency)].filter(Boolean); const hasMixedCurrencies = new Set(selectedCurrencies).size > 1; const {bulkPayButtonOptions, businessBankAccountOptions, shouldShowBusinessBankAccountOptions} = useBulkPayOptions({ @@ -1234,7 +1234,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { } const {shouldEnableBulkPayOption} = getPayOption(selectedReports, selectedTransactions, lastPaymentMethods, selectedReportIDs, personalPolicyID); - const shouldShowPayOption = !isOffline && !isAnyTransactionOnHold && shouldEnableBulkPayOption; + const shouldShowPayOption = !isOffline && !isAnyTransactionOnHold && shouldEnableBulkPayOption && !!bulkPayButtonOptions?.length; if (shouldShowPayOption) { const shouldShowPaySubmenu = !!bulkPayButtonOptions?.length; From 6edfbb21776c906c69d27573d86903a908f6f81d Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Thu, 7 May 2026 23:30:18 +0500 Subject: [PATCH 5/8] Remove mixed currencies check from getPayOption for bulk payment logic --- src/libs/actions/Search.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index 9d8a64d55e1d..5f058d1ebe9a 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -1321,11 +1321,6 @@ function getPayOption( ? selectedReports.every((report) => !!getLastPolicyPaymentMethod(report.policyID, personalPolicyID, lastPaymentMethods)) : transactionKeys.every((transactionIDKey) => !!getLastPolicyPaymentMethod(selectedTransactions[transactionIDKey].policyID, personalPolicyID, lastPaymentMethods)); - const selectedCurrencies = - selectedReports.length > 0 ? selectedReports.map((report) => report.currency) : transactionKeys.map((transactionIDKey) => selectedTransactions[transactionIDKey].currency); - - const hasMixedCurrencies = new Set(selectedCurrencies).size > 1; - const shouldShowBulkPayOption = selectedReports.length > 0 ? selectedReports.every( @@ -1343,7 +1338,6 @@ function getPayOption( return { shouldEnableBulkPayOption: shouldShowBulkPayOption, isFirstTimePayment: !hasLastPaymentMethod, - hasMixedCurrencies, }; } From 5de3efe7ea52a00955527c4e2c86b49696210dd0 Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Thu, 7 May 2026 23:37:42 +0500 Subject: [PATCH 6/8] Refactor bulkPayButtonOptions logic to prioritize onlyShowPayElsewhere condition --- src/hooks/useBulkPayOptions.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hooks/useBulkPayOptions.ts b/src/hooks/useBulkPayOptions.ts index a5ea40b07f0c..8dc7049f7105 100644 --- a/src/hooks/useBulkPayOptions.ts +++ b/src/hooks/useBulkPayOptions.ts @@ -122,10 +122,10 @@ function useBulkPayOptions({ const personalBankAccountList = formattedPaymentMethods.filter((ba) => (ba.accountData as AccountData)?.type === CONST.BANK_ACCOUNT.TYPE.PERSONAL); let bulkPayButtonOptions; - if (!selectedReportID || !selectedPolicyID) { - bulkPayButtonOptions = undefined; - } else if (onlyShowPayElsewhere) { + if (onlyShowPayElsewhere) { bulkPayButtonOptions = [paymentMethods[CONST.IOU.PAYMENT_TYPE.ELSEWHERE]]; + } else if (!selectedReportID || !selectedPolicyID) { + bulkPayButtonOptions = undefined; } else { bulkPayButtonOptions = []; From 6e386efec267300d3aad675274de634aed70159d Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Mon, 11 May 2026 16:54:09 +0500 Subject: [PATCH 7/8] Rename hasMixedCurrencies to hasMultipleCurrencies for clarity --- src/hooks/useSearchBulkActions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts index 2148be952f3e..9edfedcc2391 100644 --- a/src/hooks/useSearchBulkActions.ts +++ b/src/hooks/useSearchBulkActions.ts @@ -335,7 +335,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { }, [currentSearchResults?.data, selectedPolicyIDs, selectedReportIDs, selectedTransactionReportIDs, bankAccountList]); const selectedCurrencies = [...selectedReports.map((report) => report.currency), ...Object.values(selectedTransactions).map((transaction) => transaction.currency)].filter(Boolean); - const hasMixedCurrencies = new Set(selectedCurrencies).size > 1; + const hasMultipleCurrencies = new Set(selectedCurrencies).size > 1; const {bulkPayButtonOptions, businessBankAccountOptions, shouldShowBusinessBankAccountOptions} = useBulkPayOptions({ selectedPolicyID: selectedPolicyIDs.at(0), @@ -343,7 +343,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { isCurrencySupportedWallet: isCurrencySupportedBulkWallet, currency: selectedBulkCurrency, formattedAmount: totalFormattedAmount, - onlyShowPayElsewhere: onlyShowPayElsewhere || hasMixedCurrencies, + onlyShowPayElsewhere: onlyShowPayElsewhere || hasMultipleCurrencies, }); const {status, hash} = queryJSON ?? {}; From c14d87e4c821866d44a64baec4fbf5181484890e Mon Sep 17 00:00:00 2001 From: Samran Ahmed Date: Fri, 15 May 2026 12:34:49 +0500 Subject: [PATCH 8/8] move multi currencies within onlyShowPayElsewhere logic --- src/hooks/useBulkPayOptions.ts | 6 +++--- src/hooks/useSearchBulkActions.ts | 12 +++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/hooks/useBulkPayOptions.ts b/src/hooks/useBulkPayOptions.ts index 8dc7049f7105..a5ea40b07f0c 100644 --- a/src/hooks/useBulkPayOptions.ts +++ b/src/hooks/useBulkPayOptions.ts @@ -122,10 +122,10 @@ function useBulkPayOptions({ const personalBankAccountList = formattedPaymentMethods.filter((ba) => (ba.accountData as AccountData)?.type === CONST.BANK_ACCOUNT.TYPE.PERSONAL); let bulkPayButtonOptions; - if (onlyShowPayElsewhere) { - bulkPayButtonOptions = [paymentMethods[CONST.IOU.PAYMENT_TYPE.ELSEWHERE]]; - } else if (!selectedReportID || !selectedPolicyID) { + if (!selectedReportID || !selectedPolicyID) { bulkPayButtonOptions = undefined; + } else if (onlyShowPayElsewhere) { + bulkPayButtonOptions = [paymentMethods[CONST.IOU.PAYMENT_TYPE.ELSEWHERE]]; } else { bulkPayButtonOptions = []; diff --git a/src/hooks/useSearchBulkActions.ts b/src/hooks/useSearchBulkActions.ts index 9edfedcc2391..d8614744eea0 100644 --- a/src/hooks/useSearchBulkActions.ts +++ b/src/hooks/useSearchBulkActions.ts @@ -318,6 +318,11 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { const totalFormattedAmount = getTotalFormattedAmount(convertToDisplayString, selectedReports, selectedTransactions, selectedBulkCurrency); const onlyShowPayElsewhere = useMemo(() => { + const selectedCurrencies = [...selectedReports.map((report) => report.currency), ...Object.values(selectedTransactions).map((transaction) => transaction.currency)].filter(Boolean); + if (new Set(selectedCurrencies).size > 1) { + return true; + } + const firstPolicyID = selectedPolicyIDs.at(0); const selectedPolicy = firstPolicyID ? currentSearchResults?.data?.[`${ONYXKEYS.COLLECTION.POLICY}${firstPolicyID}`] : undefined; return (selectedTransactionReportIDs ?? selectedReportIDs).some((reportID) => { @@ -332,10 +337,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { canIOUBePaid(report, chatReport, selectedPolicy, bankAccountList, undefined, true, undefined, invoiceReceiverPolicy) ); }); - }, [currentSearchResults?.data, selectedPolicyIDs, selectedReportIDs, selectedTransactionReportIDs, bankAccountList]); - - const selectedCurrencies = [...selectedReports.map((report) => report.currency), ...Object.values(selectedTransactions).map((transaction) => transaction.currency)].filter(Boolean); - const hasMultipleCurrencies = new Set(selectedCurrencies).size > 1; + }, [currentSearchResults?.data, selectedPolicyIDs, selectedReportIDs, selectedTransactionReportIDs, bankAccountList, selectedReports, selectedTransactions]); const {bulkPayButtonOptions, businessBankAccountOptions, shouldShowBusinessBankAccountOptions} = useBulkPayOptions({ selectedPolicyID: selectedPolicyIDs.at(0), @@ -343,7 +345,7 @@ function useSearchBulkActions({queryJSON}: UseSearchBulkActionsParams) { isCurrencySupportedWallet: isCurrencySupportedBulkWallet, currency: selectedBulkCurrency, formattedAmount: totalFormattedAmount, - onlyShowPayElsewhere: onlyShowPayElsewhere || hasMultipleCurrencies, + onlyShowPayElsewhere, }); const {status, hash} = queryJSON ?? {};