From f97ef141cad23cd71b4caddaeca88db012ae8b06 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 16 Dec 2025 15:56:28 +0700 Subject: [PATCH 1/4] Refactor ConfirmModal usage to useConfirmModal in Search pages --- src/pages/Search/SearchPage.tsx | 191 ++++++++++++----------------- src/pages/iou/SplitExpensePage.tsx | 44 ++++--- 2 files changed, 107 insertions(+), 128 deletions(-) diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 19709ee3f08d..0667b629a2dc 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -4,7 +4,6 @@ import {InteractionManager, View} from 'react-native'; import Animated from 'react-native-reanimated'; import type {ValueOf} from 'type-fest'; import type {DropdownOption} from '@components/ButtonWithDropdownMenu/types'; -import ConfirmModal from '@components/ConfirmModal'; import DecisionModal from '@components/DecisionModal'; import DragAndDropConsumer from '@components/DragAndDrop/Consumer'; import DragAndDropProvider from '@components/DragAndDrop/Provider'; @@ -12,6 +11,7 @@ import DropZoneUI from '@components/DropZone/DropZoneUI'; import HoldOrRejectEducationalModal from '@components/HoldOrRejectEducationalModal'; import HoldSubmitterEducationalModal from '@components/HoldSubmitterEducationalModal'; import type {PaymentMethodType} from '@components/KYCWall/types'; +import {ModalActions} from '@components/Modal/Global/ModalContext'; import type {PopoverMenuItem} from '@components/PopoverMenu'; import {ScrollOffsetContext} from '@components/ScrollOffsetContextProvider'; import {useSearchContext} from '@components/Search/SearchContext'; @@ -20,6 +20,7 @@ import type {PaymentData, SearchParams} from '@components/Search/types'; import {usePlaybackContext} from '@components/VideoPlayerContexts/PlaybackContext'; import useAllTransactions from '@hooks/useAllTransactions'; import useBulkPayOptions from '@hooks/useBulkPayOptions'; +import useConfirmModal from '@hooks/useConfirmModal'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useFilesValidation from '@hooks/useFilesValidation'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; @@ -118,11 +119,8 @@ function SearchPage({route}: SearchPageProps) { const [csvExportLayouts] = useOnyx(ONYXKEYS.NVP_CSV_EXPORT_LAYOUTS, {canBeMissing: true}); const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false); const [isDownloadErrorModalVisible, setIsDownloadErrorModalVisible] = useState(false); - const [isDeleteExpensesConfirmModalVisible, setIsDeleteExpensesConfirmModalVisible] = useState(false); - const [isDownloadExportModalVisible, setIsDownloadExportModalVisible] = useState(false); - const [isExportWithTemplateModalVisible, setIsExportWithTemplateModalVisible] = useState(false); const [searchRequestResponseStatusCode, setSearchRequestResponseStatusCode] = useState(null); - const [isDEWModalVisible, setIsDEWModalVisible] = useState(false); + const {showConfirmModal} = useConfirmModal(); const [isHoldEducationalModalVisible, setIsHoldEducationalModalVisible] = useState(false); const [rejectModalAction, setRejectModalAction] = useState { + if (result.action !== ModalActions.CONFIRM) { + return; + } + clearSelectedTransactions(undefined, true); + }); }, - [queryJSON, selectedTransactionsKeys, areAllMatchingItemsSelected, selectedTransactionReportIDs], + [queryJSON, selectedTransactionsKeys, areAllMatchingItemsSelected, selectedTransactionReportIDs, showConfirmModal, translate, clearSelectedTransactions], ); const onBulkPaySelected = useCallback( @@ -374,7 +382,28 @@ function SearchPage({route}: SearchPageProps) { } if (areAllMatchingItemsSelected) { - setIsDownloadExportModalVisible(true); + if (!status || !hash) { + return; + } + showConfirmModal({ + title: translate('search.exportSearchResults.title'), + prompt: translate('search.exportSearchResults.description'), + confirmText: translate('search.exportSearchResults.title'), + cancelText: translate('common.cancel'), + }).then((result) => { + if (result.action !== ModalActions.CONFIRM) { + return; + } + const reportIDList = selectedReports?.filter((report) => !!report).map((report) => report.reportID) ?? []; + queueExportSearchItemsToCSV({ + query: status, + jsonQuery: JSON.stringify(queryJSON), + reportIDList, + transactionIDList: selectedTransactionsKeys, + }); + selectAllMatchingItems(false); + clearSelectedTransactions(); + }); return; } @@ -473,7 +502,17 @@ function SearchPage({route}: SearchPageProps) { }); if (hasDEWPolicy) { - setIsDEWModalVisible(true); + showConfirmModal({ + title: translate('customApprovalWorkflow.title'), + prompt: translate('customApprovalWorkflow.description'), + confirmText: translate('customApprovalWorkflow.goToExpensifyClassic'), + shouldShowCancelButton: false, + }).then((result) => { + if (result.action !== ModalActions.CONFIRM) { + return; + } + openOldDotLink(CONST.OLDDOT_URLS.INBOX); + }); return; } @@ -705,7 +744,24 @@ function SearchPage({route}: SearchPageProps) { // Use InteractionManager to ensure this runs after the dropdown modal closes // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { - setIsDeleteExpensesConfirmModalVisible(true); + showConfirmModal({ + title: translate('iou.deleteExpense', {count: selectedTransactionsKeys.length}), + prompt: translate('iou.deleteConfirmation', {count: selectedTransactionsKeys.length}), + confirmText: translate('common.delete'), + cancelText: translate('common.cancel'), + danger: true, + }).then((result) => { + if (result.action !== ModalActions.CONFIRM) { + return; + } + // Translations copy for delete modal depends on amount of selected items, + // We need to wait for modal to fully disappear before clearing them to avoid translation flicker between singular vs plural + // eslint-disable-next-line @typescript-eslint/no-deprecated + InteractionManager.runAfterInteractions(() => { + deleteMoneyRequestOnSearch(hash, selectedTransactionsKeys); + clearSelectedTransactions(); + }); + }); }); }, }); @@ -735,7 +791,18 @@ function SearchPage({route}: SearchPageProps) { status, hash, selectedTransactions, - expensifyIcons, + expensifyIcons.Table, + expensifyIcons.Export, + expensifyIcons.ArrowRight, + expensifyIcons.ThumbsUp, + expensifyIcons.ThumbsDown, + expensifyIcons.Send, + expensifyIcons.MoneyBag, + expensifyIcons.Stopwatch, + expensifyIcons.DocumentMerge, + expensifyIcons.ArrowSplit, + expensifyIcons.Trashcan, + expensifyIcons.Exclamation, translate, areAllMatchingItemsSelected, isOffline, @@ -759,28 +826,13 @@ function SearchPage({route}: SearchPageProps) { allReports, currentSearchResults?.data, theme.icon, + showConfirmModal, + selectAllMatchingItems, styles.colorMuted, styles.fontWeightNormal, styles.textWrap, ]); - const handleDeleteExpenses = () => { - if (selectedTransactionsKeys.length === 0 || !hash) { - return; - } - - setIsDeleteExpensesConfirmModalVisible(false); - - // Translations copy for delete modal depends on amount of selected items, - // We need to wait for modal to fully disappear before clearing them to avoid translation flicker between singular vs plural - - // eslint-disable-next-line @typescript-eslint/no-deprecated - InteractionManager.runAfterInteractions(() => { - deleteMoneyRequestOnSearch(hash, selectedTransactionsKeys); - clearSelectedTransactions(); - }); - }; - const saveFileAndInitMoneyRequest = (files: FileObject[]) => { const initialTransaction = initMoneyRequest({ isFromGlobalCreate: true, @@ -853,24 +905,6 @@ function SearchPage({route}: SearchPageProps) { validateFiles(files, Array.from(e.dataTransfer?.items ?? [])); }; - const createExportAll = useCallback(() => { - if (selectedTransactionsKeys.length === 0 || status == null || !hash) { - return []; - } - - setIsDownloadExportModalVisible(false); - const reportIDList = selectedReports?.filter((report) => !!report).map((report) => report.reportID) ?? []; - queueExportSearchItemsToCSV({ - query: status, - jsonQuery: JSON.stringify(queryJSON), - reportIDList, - transactionIDList: selectedTransactionsKeys, - }); - selectAllMatchingItems(false); - clearSelectedTransactions(); - }, [selectedTransactionsKeys, status, hash, selectedReports, queryJSON, selectAllMatchingItems, clearSelectedTransactions]); - - const isPossibleToShowDownloadExportModal = !shouldUseNarrowLayout && isDownloadExportModalVisible && !!createExportAll && !!setIsDownloadExportModalVisible; const {resetVideoPlayerData} = usePlaybackContext(); const [isSorting, setIsSorting] = useState(false); @@ -949,10 +983,6 @@ function SearchPage({route}: SearchPageProps) { [saveScrollOffset, route], ); - const handleDeleteExpensesCancel = useCallback(() => { - setIsDeleteExpensesConfirmModalVisible(false); - }, [setIsDeleteExpensesConfirmModalVisible]); - const handleOfflineModalClose = useCallback(() => { setIsOfflineModalVisible(false); }, [setIsOfflineModalVisible]); @@ -961,28 +991,6 @@ function SearchPage({route}: SearchPageProps) { setIsDownloadErrorModalVisible(false); }, [setIsDownloadErrorModalVisible]); - const handleExportWithTemplateConfirm = useCallback(() => { - setIsExportWithTemplateModalVisible(false); - clearSelectedTransactions(undefined, true); - }, [setIsExportWithTemplateModalVisible, clearSelectedTransactions]); - - const handleExportWithTemplateCancel = useCallback(() => { - setIsExportWithTemplateModalVisible(false); - }, [setIsExportWithTemplateModalVisible]); - - const handleDEWModalConfirm = useCallback(() => { - setIsDEWModalVisible(false); - openOldDotLink(CONST.OLDDOT_URLS.INBOX); - }, [setIsDEWModalVisible]); - - const handleDEWModalCancel = useCallback(() => { - setIsDEWModalVisible(false); - }, [setIsDEWModalVisible]); - - const handleDownloadExportModalCancel = useCallback(() => { - setIsDownloadExportModalVisible?.(false); - }, [setIsDownloadExportModalVisible]); - const dismissModalAndUpdateUseHold = useCallback(() => { setIsHoldEducationalModalVisible(false); setNameValuePair(ONYXKEYS.NVP_DISMISSED_HOLD_USE_EXPLANATION, true, false, !isOffline); @@ -1059,16 +1067,6 @@ function SearchPage({route}: SearchPageProps) { {(!shouldUseNarrowLayout || isMobileSelectionModeEnabled) && ( - - - - {isPossibleToShowDownloadExportModal && ( - - )} {!!rejectModalAction && ( (''); const searchContext = useSearchContext(); @@ -313,20 +314,33 @@ function SplitExpensePage({route}: SplitExpensePageProps) { {shouldShowMakeSplitsEven && ( )} ); - }, [onAddSplitExpense, onMakeSplitsEven, translate, childTransactions.length, shouldUseNarrowLayout, styles.w100, styles.ph4, styles.flexColumn, styles.mt1, styles.mb3]); + }, [ + onAddSplitExpense, + onMakeSplitsEven, + translate, + childTransactions.length, + shouldUseNarrowLayout, + styles.w100, + styles.ph4, + styles.flexColumn, + styles.mt1, + styles.mb3, + expensifyIcons.Plus, + expensifyIcons.ArrowsLeftRight, + ]); const footerContent = useMemo(() => { const shouldShowWarningMessage = sumOfSplitExpenses < transactionDetailsAmount; @@ -396,7 +410,12 @@ function SplitExpensePage({route}: SplitExpensePageProps) { )} onSelectRow={(item) => { if (!item.isEditable) { - setCannotBeEditedModalVisible(true); + showConfirmModal({ + title: translate('iou.splitExpenseCannotBeEditedModalTitle'), + prompt: translate('iou.splitExpenseCannotBeEditedModalDescription'), + confirmText: translate('common.buttonConfirm'), + shouldShowCancelButton: false, + }); return; } Keyboard.dismiss(); @@ -419,15 +438,6 @@ function SplitExpensePage({route}: SplitExpensePageProps) { removeClippedSubviews={false} /> - setCannotBeEditedModalVisible(false)} - onCancel={() => setCannotBeEditedModalVisible(false)} - confirmText={translate('common.buttonConfirm')} - isVisible={cannotBeEditedModalVisible} - shouldShowCancelButton={false} - /> ); From 8217c19b6daa67e82ef5507d39fda5cda3721837 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 18 Dec 2025 14:48:35 +0700 Subject: [PATCH 2/4] fix export modal --- src/pages/Search/SearchPage.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 3f4d80336b20..751658aaf7bf 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -412,9 +412,6 @@ function SearchPage({route}: SearchPageProps) { } if (areAllMatchingItemsSelected) { - if (!status || !hash) { - return; - } showConfirmModal({ title: translate('search.exportSearchResults.title'), prompt: translate('search.exportSearchResults.description'), @@ -424,6 +421,9 @@ function SearchPage({route}: SearchPageProps) { if (result.action !== ModalActions.CONFIRM) { return; } + if (selectedTransactionsKeys.length === 0 || status == null || !hash) { + return; + } const reportIDList = selectedReports?.filter((report) => !!report).map((report) => report.reportID) ?? []; queueExportSearchItemsToCSV({ query: status, From 5db06c11aede5dab87610b294fa77e78fbd4b61b Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 8 Jan 2026 14:25:23 +0700 Subject: [PATCH 3/4] fix ts check --- src/pages/Search/SearchPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 416bb6b33315..3e2a29811718 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -474,7 +474,7 @@ function SearchPage({route}: SearchPageProps) { if (selectedTransactionsKeys.length === 0 || status == null || !hash) { return; } - const reportIDList = selectedReports?.filter((report) => !!report).map((report) => report.reportID) ?? []; + const reportIDList = selectedReports?.map((report) => report?.reportID).filter((reportID) => reportID !== undefined) ?? []; queueExportSearchItemsToCSV({ query: status, jsonQuery: JSON.stringify(queryJSON), From 912e81c0673c7e5c5fdf9b923078ce495ffd8f18 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Sat, 10 Jan 2026 20:39:10 +0700 Subject: [PATCH 4/4] use async await --- src/pages/Search/SearchPage.tsx | 302 ++++++++++++++++++-------------- 1 file changed, 174 insertions(+), 128 deletions(-) diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 8dcb878dca73..08214f0d5b1f 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -240,7 +240,7 @@ function SearchPage({route}: SearchPageProps) { const selectedTransactionsKeys = Object.keys(selectedTransactions ?? {}); const beginExportWithTemplate = useCallback( - (templateName: string, templateType: string, policyID: string | undefined) => { + async (templateName: string, templateType: string, policyID: string | undefined) => { // If the user has selected a large number of items, we'll use the queryJSON to search for the reportIDs and transactionIDs necessary for the export if (areAllMatchingItemsSelected) { queueExportSearchWithTemplate({ @@ -263,17 +263,16 @@ function SearchPage({route}: SearchPageProps) { }); } - showConfirmModal({ + const result = await showConfirmModal({ title: translate('export.exportInProgress'), prompt: translate('export.conciergeWillSend'), confirmText: translate('common.buttonConfirm'), shouldShowCancelButton: false, - }).then((result) => { - if (result.action !== ModalActions.CONFIRM) { - return; - } - clearSelectedTransactions(undefined, true); }); + if (result.action !== ModalActions.CONFIRM) { + return; + } + clearSelectedTransactions(undefined, true); }, [queryJSON, selectedTransactionsKeys, areAllMatchingItemsSelected, selectedTransactionReportIDs, showConfirmModal, translate, clearSelectedTransactions], ); @@ -284,6 +283,165 @@ function SearchPage({route}: SearchPageProps) { .map((policy) => policy.id); }, [policies]); + const handleBasicExport = useCallback(async () => { + if (isOffline) { + setIsOfflineModalVisible(true); + return; + } + + if (status === null || status === undefined) { + return; + } + + if (areAllMatchingItemsSelected) { + const result = await showConfirmModal({ + title: translate('search.exportSearchResults.title'), + prompt: translate('search.exportSearchResults.description'), + confirmText: translate('search.exportSearchResults.title'), + cancelText: translate('common.cancel'), + }); + if (result.action !== ModalActions.CONFIRM) { + return; + } + if (selectedTransactionsKeys.length === 0 || status == null || !hash) { + return; + } + const reportIDList = selectedReports?.map((report) => report?.reportID).filter((reportID) => reportID !== undefined) ?? []; + queueExportSearchItemsToCSV({ + query: status, + jsonQuery: JSON.stringify(queryJSON), + reportIDList, + transactionIDList: selectedTransactionsKeys, + }); + selectAllMatchingItems(false); + clearSelectedTransactions(); + return; + } + + exportSearchItemsToCSV( + { + query: status, + jsonQuery: JSON.stringify(queryJSON), + reportIDList: selectedReports?.map((report) => report?.reportID).filter((reportID) => reportID !== undefined) ?? [], + transactionIDList: selectedTransactionsKeys, + }, + () => { + setIsDownloadErrorModalVisible(true); + }, + translate, + ); + clearSelectedTransactions(undefined, true); + }, [ + isOffline, + areAllMatchingItemsSelected, + showConfirmModal, + translate, + selectedTransactionsKeys, + status, + hash, + selectedReports, + queryJSON, + selectAllMatchingItems, + clearSelectedTransactions, + setIsDownloadErrorModalVisible, + ]); + + const handleApproveWithDEWCheck = useCallback(async () => { + if (isOffline) { + setIsOfflineModalVisible(true); + return; + } + + if (!hash) { + return; + } + + if (isDelegateAccessRestricted) { + showDelegateNoAccessModal(); + return; + } + + // Check if any of the selected items have DEW enabled + const selectedPolicyIDList = selectedReports.length + ? selectedReports.map((report) => report.policyID) + : Object.values(selectedTransactions).map((transaction) => transaction.policyID); + const hasDEWPolicy = selectedPolicyIDList.some((policyID) => { + const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]; + return hasDynamicExternalWorkflow(policy); + }); + + if (hasDEWPolicy && !isDEWBetaEnabled) { + const result = await showConfirmModal({ + title: translate('customApprovalWorkflow.title'), + prompt: translate('customApprovalWorkflow.description'), + confirmText: translate('customApprovalWorkflow.goToExpensifyClassic'), + shouldShowCancelButton: false, + }); + if (result.action !== ModalActions.CONFIRM) { + return; + } + openOldDotLink(CONST.OLDDOT_URLS.INBOX); + return; + } + + const reportIDList = !selectedReports.length + ? Object.values(selectedTransactions).map((transaction) => transaction.reportID) + : (selectedReports?.filter((report) => !!report).map((report) => report.reportID) ?? []); + approveMoneyRequestOnSearch( + hash, + reportIDList.filter((reportID) => reportID !== undefined), + ); + // eslint-disable-next-line @typescript-eslint/no-deprecated + InteractionManager.runAfterInteractions(() => { + clearSelectedTransactions(); + }); + }, [ + isOffline, + isDelegateAccessRestricted, + showDelegateNoAccessModal, + selectedReports, + selectedTransactions, + policies, + isDEWBetaEnabled, + showConfirmModal, + translate, + hash, + clearSelectedTransactions, + ]); + + const handleDeleteSelectedTransactions = useCallback(async () => { + if (isOffline) { + setIsOfflineModalVisible(true); + return; + } + + if (!hash) { + return; + } + + // Use InteractionManager to ensure this runs after the dropdown modal closes + // eslint-disable-next-line @typescript-eslint/no-deprecated + InteractionManager.runAfterInteractions(async () => { + const result = await showConfirmModal({ + title: translate('iou.deleteExpense', {count: selectedTransactionsKeys.length}), + prompt: translate('iou.deleteConfirmation', {count: selectedTransactionsKeys.length}), + confirmText: translate('common.delete'), + cancelText: translate('common.cancel'), + danger: true, + }); + if (result.action !== ModalActions.CONFIRM) { + return; + } + // Translations copy for delete modal depends on amount of selected items, + // We need to wait for modal to fully disappear before clearing them to avoid translation flicker between singular vs plural + // eslint-disable-next-line @typescript-eslint/no-deprecated + InteractionManager.runAfterInteractions(() => { + deleteMoneyRequestOnSearch(hash, selectedTransactionsKeys); + clearSelectedTransactions(); + }); + }); + }, [isOffline, showConfirmModal, translate, selectedTransactionsKeys, hash, clearSelectedTransactions]); + const onBulkPaySelected = useCallback( (paymentMethod?: PaymentMethodType, additionalData?: Record) => { if (!hash) { @@ -449,6 +607,7 @@ function SearchPage({route}: SearchPageProps) { const options: Array> = []; const isAnyTransactionOnHold = Object.values(selectedTransactions).some((transaction) => transaction.isHeld); + // Gets the list of options for the export sub-menu // Gets the list of options for the export sub-menu const getExportOptions = () => { // We provide the basic and expense level export options by default @@ -457,50 +616,7 @@ function SearchPage({route}: SearchPageProps) { text: translate('export.basicExport'), icon: expensifyIcons.Table, onSelected: () => { - if (isOffline) { - setIsOfflineModalVisible(true); - return; - } - - if (areAllMatchingItemsSelected) { - showConfirmModal({ - title: translate('search.exportSearchResults.title'), - prompt: translate('search.exportSearchResults.description'), - confirmText: translate('search.exportSearchResults.title'), - cancelText: translate('common.cancel'), - }).then((result) => { - if (result.action !== ModalActions.CONFIRM) { - return; - } - if (selectedTransactionsKeys.length === 0 || status == null || !hash) { - return; - } - const reportIDList = selectedReports?.map((report) => report?.reportID).filter((reportID) => reportID !== undefined) ?? []; - queueExportSearchItemsToCSV({ - query: status, - jsonQuery: JSON.stringify(queryJSON), - reportIDList, - transactionIDList: selectedTransactionsKeys, - }); - selectAllMatchingItems(false); - clearSelectedTransactions(); - }); - return; - } - - exportSearchItemsToCSV( - { - query: status, - jsonQuery: JSON.stringify(queryJSON), - reportIDList: selectedReports?.map((report) => report?.reportID).filter((reportID) => reportID !== undefined) ?? [], - transactionIDList: selectedTransactionsKeys, - }, - () => { - setIsDownloadErrorModalVisible(true); - }, - translate, - ); - clearSelectedTransactions(undefined, true); + handleBasicExport(); }, shouldCloseModalOnSelect: true, shouldCallAfterModalHide: true, @@ -571,51 +687,7 @@ function SearchPage({route}: SearchPageProps) { value: CONST.SEARCH.BULK_ACTION_TYPES.APPROVE, shouldCloseModalOnSelect: true, onSelected: () => { - if (isOffline) { - setIsOfflineModalVisible(true); - return; - } - - if (isDelegateAccessRestricted) { - showDelegateNoAccessModal(); - return; - } - - // Check if any of the selected items have DEW enabled - const selectedPolicyIDList = selectedReports.length - ? selectedReports.map((report) => report.policyID) - : Object.values(selectedTransactions).map((transaction) => transaction.policyID); - const hasDEWPolicy = selectedPolicyIDList.some((policyID) => { - const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]; - return hasDynamicExternalWorkflow(policy); - }); - - if (hasDEWPolicy && !isDEWBetaEnabled) { - showConfirmModal({ - title: translate('customApprovalWorkflow.title'), - prompt: translate('customApprovalWorkflow.description'), - confirmText: translate('customApprovalWorkflow.goToExpensifyClassic'), - shouldShowCancelButton: false, - }).then((result) => { - if (result.action !== ModalActions.CONFIRM) { - return; - } - openOldDotLink(CONST.OLDDOT_URLS.INBOX); - }); - return; - } - - const reportIDList = !selectedReports.length - ? Object.values(selectedTransactions).map((transaction) => transaction.reportID) - : (selectedReports?.filter((report) => !!report).map((report) => report.reportID) ?? []); - approveMoneyRequestOnSearch( - hash, - reportIDList.filter((reportID) => reportID !== undefined), - ); - // eslint-disable-next-line @typescript-eslint/no-deprecated - InteractionManager.runAfterInteractions(() => { - clearSelectedTransactions(); - }); + handleApproveWithDEWCheck(); }, }); } @@ -854,33 +926,7 @@ function SearchPage({route}: SearchPageProps) { value: CONST.SEARCH.BULK_ACTION_TYPES.DELETE, shouldCloseModalOnSelect: true, onSelected: () => { - if (isOffline) { - setIsOfflineModalVisible(true); - return; - } - - // Use InteractionManager to ensure this runs after the dropdown modal closes - // eslint-disable-next-line @typescript-eslint/no-deprecated - InteractionManager.runAfterInteractions(() => { - showConfirmModal({ - title: translate('iou.deleteExpense', {count: selectedTransactionsKeys.length}), - prompt: translate('iou.deleteConfirmation', {count: selectedTransactionsKeys.length}), - confirmText: translate('common.delete'), - cancelText: translate('common.cancel'), - danger: true, - }).then((result) => { - if (result.action !== ModalActions.CONFIRM) { - return; - } - // Translations copy for delete modal depends on amount of selected items, - // We need to wait for modal to fully disappear before clearing them to avoid translation flicker between singular vs plural - // eslint-disable-next-line @typescript-eslint/no-deprecated - InteractionManager.runAfterInteractions(() => { - deleteMoneyRequestOnSearch(hash, selectedTransactionsKeys); - clearSelectedTransactions(); - }); - }); - }); + handleDeleteSelectedTransactions(); }, }); } @@ -919,7 +965,7 @@ function SearchPage({route}: SearchPageProps) { lastPaymentMethods, selectedReportIDs, allTransactions, - queryJSON, + queryJSON?.type, selectedPolicyIDs, policies, integrationsExportTemplates, @@ -928,12 +974,12 @@ function SearchPage({route}: SearchPageProps) { beginExportWithTemplate, bulkPayButtonOptions, onBulkPaySelected, + handleBasicExport, + handleApproveWithDEWCheck, + handleDeleteSelectedTransactions, allReports, theme.icon, - showConfirmModal, - selectAllMatchingItems, styles.colorMuted, - isDEWBetaEnabled, styles.fontWeightNormal, styles.textWrap, expensifyIcons.ArrowCollapse, @@ -956,7 +1002,7 @@ function SearchPage({route}: SearchPageProps) { currentSearchResults?.data, isDelegateAccessRestricted, showDelegateNoAccessModal, - currentUserPersonalDetails?.accountID, + currentUserPersonalDetails.accountID, personalPolicyID, ]);