From 11819fafebc87f51a7bd190e8340efd277dab4fd Mon Sep 17 00:00:00 2001
From: Wojciech Boman <wojciechboman@gmail.com>
Date: Wed, 10 Jul 2024 11:38:16 +0200
Subject: [PATCH 1/8] Display ConfirmModal before deleting expenses

---
 .../Search/SearchListWithHeader.tsx           | 28 +++++++++++++++++++
 src/components/Search/SearchPageHeader.tsx    | 14 ++++------
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/src/components/Search/SearchListWithHeader.tsx b/src/components/Search/SearchListWithHeader.tsx
index 48d9a2b4ae3a..546d7a6e59b1 100644
--- a/src/components/Search/SearchListWithHeader.tsx
+++ b/src/components/Search/SearchListWithHeader.tsx
@@ -1,7 +1,10 @@
 import type {ForwardedRef} from 'react';
 import React, {forwardRef, useEffect, useMemo, useState} from 'react';
+import ConfirmModal from '@components/ConfirmModal';
 import SelectionList from '@components/SelectionList';
 import type {BaseSelectionListProps, ReportListItemType, SelectionListHandle, TransactionListItemType} from '@components/SelectionList/types';
+import useLocalize from '@hooks/useLocalize';
+import * as SearchActions from '@libs/actions/Search';
 import * as SearchUtils from '@libs/SearchUtils';
 import CONST from '@src/CONST';
 import type {SearchDataTypes, SearchQuery} from '@src/types/onyx/SearchResults';
@@ -34,10 +37,24 @@ function mapToItemWithSelectionInfo(item: TransactionListItemType | ReportListIt
 }
 
 function SearchListWithHeader({ListItem, onSelectRow, query, hash, data, searchType, ...props}: SearchListWithHeaderProps, ref: ForwardedRef<SelectionListHandle>) {
+    const {translate} = useLocalize();
     const [selectedItems, setSelectedItems] = useState<SelectedTransactions>({});
+    const [deleteExpensesConfirmModalVisible, setDeleteExpensesConfirmModalVisible] = useState(false);
 
     const clearSelectedItems = () => setSelectedItems({});
 
+    const handleDeleteExpenses = () => {
+        const itemsToDelete = Object.keys(selectedItems).filter((id) => selectedItems[id].canDelete);
+
+        if (itemsToDelete.length === 0) {
+            return;
+        }
+
+        clearSelectedItems();
+        setDeleteExpensesConfirmModalVisible(false);
+        SearchActions.deleteMoneyRequestOnSearch(hash, itemsToDelete);
+    };
+
     useEffect(() => {
         clearSelectedItems();
     }, [hash]);
@@ -104,6 +121,7 @@ function SearchListWithHeader({ListItem, onSelectRow, query, hash, data, searchT
                 clearSelectedItems={clearSelectedItems}
                 query={query}
                 hash={hash}
+                setDeleteModalVisible={setDeleteExpensesConfirmModalVisible}
             />
             <SelectionList<ReportListItemType | TransactionListItemType>
                 // eslint-disable-next-line react/jsx-props-no-spreading
@@ -115,6 +133,16 @@ function SearchListWithHeader({ListItem, onSelectRow, query, hash, data, searchT
                 onCheckboxPress={toggleTransaction}
                 onSelectAll={toggleAllTransactions}
             />
+            <ConfirmModal
+                isVisible={deleteExpensesConfirmModalVisible}
+                onConfirm={handleDeleteExpenses}
+                onCancel={() => setDeleteExpensesConfirmModalVisible(false)}
+                title={translate('iou.deleteExpense')}
+                prompt={translate('iou.deleteConfirmation')}
+                confirmText={translate('common.delete')}
+                cancelText={translate('common.cancel')}
+                danger
+            />
         </>
     );
 }
diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx
index 8d42f9e6da36..b2a513cc7ffd 100644
--- a/src/components/Search/SearchPageHeader.tsx
+++ b/src/components/Search/SearchPageHeader.tsx
@@ -22,11 +22,12 @@ type SearchHeaderProps = {
     selectedItems?: SelectedTransactions;
     clearSelectedItems?: () => void;
     hash: number;
+    setDeleteModalVisible: (isVisible: boolean) => void;
 };
 
 type SearchHeaderOptionValue = DeepValueOf<typeof CONST.SEARCH.BULK_ACTION_TYPES> | undefined;
 
-function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems}: SearchHeaderProps) {
+function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems, setDeleteModalVisible}: SearchHeaderProps) {
     const {translate} = useLocalize();
     const theme = useTheme();
     const styles = useThemeStyles();
@@ -47,17 +48,12 @@ function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems}:
             return null;
         }
 
-        const itemsToDelete = selectedItemsKeys.filter((id) => selectedItems[id].canDelete);
-
-        if (itemsToDelete.length > 0) {
+        if (selectedItemsKeys.some((id) => selectedItems[id].canDelete)) {
             options.push({
                 icon: Expensicons.Trashcan,
                 text: translate('search.bulkActions.delete'),
                 value: CONST.SEARCH.BULK_ACTION_TYPES.DELETE,
-                onSelected: () => {
-                    clearSelectedItems?.();
-                    SearchActions.deleteMoneyRequestOnSearch(hash, itemsToDelete);
-                },
+                onSelected: () => setDeleteModalVisible(true),
             });
         }
 
@@ -119,7 +115,7 @@ function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems}:
                 isDisabled={isOffline}
             />
         );
-    }, [clearSelectedItems, hash, isOffline, selectedItems, styles.colorMuted, styles.fontWeightNormal, theme.icon, translate]);
+    }, [clearSelectedItems, hash, isOffline, selectedItems, setDeleteModalVisible, styles.colorMuted, styles.fontWeightNormal, theme.icon, translate]);
 
     if (isSmallScreenWidth) {
         return null;

From a0e10cb382ffd68f84863ef4229c93864e7809e3 Mon Sep 17 00:00:00 2001
From: Wojciech Boman <wojciechboman@gmail.com>
Date: Thu, 11 Jul 2024 11:55:34 +0200
Subject: [PATCH 2/8] Add selectedItemsToDelete to SearchListWithHeader

---
 .../Search/SearchListWithHeader.tsx           | 21 +++++++++++++------
 src/components/Search/SearchPageHeader.tsx    | 12 ++++++-----
 2 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/src/components/Search/SearchListWithHeader.tsx b/src/components/Search/SearchListWithHeader.tsx
index 546d7a6e59b1..0e5096c78634 100644
--- a/src/components/Search/SearchListWithHeader.tsx
+++ b/src/components/Search/SearchListWithHeader.tsx
@@ -39,20 +39,29 @@ function mapToItemWithSelectionInfo(item: TransactionListItemType | ReportListIt
 function SearchListWithHeader({ListItem, onSelectRow, query, hash, data, searchType, ...props}: SearchListWithHeaderProps, ref: ForwardedRef<SelectionListHandle>) {
     const {translate} = useLocalize();
     const [selectedItems, setSelectedItems] = useState<SelectedTransactions>({});
+    const [selectedItemsToDelete, setSelectedItemsToDelete] = useState<string[]>([]);
     const [deleteExpensesConfirmModalVisible, setDeleteExpensesConfirmModalVisible] = useState(false);
 
+    const handleOnSelectDeleteOption = (itemsToDelete: string[]) => {
+        setSelectedItemsToDelete(itemsToDelete);
+        setDeleteExpensesConfirmModalVisible(true);
+    };
+
+    const handleOnCancelConfirmModal = () => {
+        setSelectedItemsToDelete([]);
+        setDeleteExpensesConfirmModalVisible(false);
+    };
+
     const clearSelectedItems = () => setSelectedItems({});
 
     const handleDeleteExpenses = () => {
-        const itemsToDelete = Object.keys(selectedItems).filter((id) => selectedItems[id].canDelete);
-
-        if (itemsToDelete.length === 0) {
+        if (selectedItemsToDelete.length === 0) {
             return;
         }
 
         clearSelectedItems();
         setDeleteExpensesConfirmModalVisible(false);
-        SearchActions.deleteMoneyRequestOnSearch(hash, itemsToDelete);
+        SearchActions.deleteMoneyRequestOnSearch(hash, selectedItemsToDelete);
     };
 
     useEffect(() => {
@@ -121,7 +130,7 @@ function SearchListWithHeader({ListItem, onSelectRow, query, hash, data, searchT
                 clearSelectedItems={clearSelectedItems}
                 query={query}
                 hash={hash}
-                setDeleteModalVisible={setDeleteExpensesConfirmModalVisible}
+                onSelectDeleteOption={handleOnSelectDeleteOption}
             />
             <SelectionList<ReportListItemType | TransactionListItemType>
                 // eslint-disable-next-line react/jsx-props-no-spreading
@@ -136,7 +145,7 @@ function SearchListWithHeader({ListItem, onSelectRow, query, hash, data, searchT
             <ConfirmModal
                 isVisible={deleteExpensesConfirmModalVisible}
                 onConfirm={handleDeleteExpenses}
-                onCancel={() => setDeleteExpensesConfirmModalVisible(false)}
+                onCancel={handleOnCancelConfirmModal}
                 title={translate('iou.deleteExpense')}
                 prompt={translate('iou.deleteConfirmation')}
                 confirmText={translate('common.delete')}
diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx
index b2a513cc7ffd..655211be0037 100644
--- a/src/components/Search/SearchPageHeader.tsx
+++ b/src/components/Search/SearchPageHeader.tsx
@@ -22,12 +22,12 @@ type SearchHeaderProps = {
     selectedItems?: SelectedTransactions;
     clearSelectedItems?: () => void;
     hash: number;
-    setDeleteModalVisible: (isVisible: boolean) => void;
+    onSelectDeleteOption: (itemsToDelete: string[]) => void;
 };
 
 type SearchHeaderOptionValue = DeepValueOf<typeof CONST.SEARCH.BULK_ACTION_TYPES> | undefined;
 
-function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems, setDeleteModalVisible}: SearchHeaderProps) {
+function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems, onSelectDeleteOption}: SearchHeaderProps) {
     const {translate} = useLocalize();
     const theme = useTheme();
     const styles = useThemeStyles();
@@ -48,12 +48,14 @@ function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems,
             return null;
         }
 
-        if (selectedItemsKeys.some((id) => selectedItems[id].canDelete)) {
+        const itemsToDelete = Object.keys(selectedItems ?? {}).filter((id) => selectedItems[id].canDelete);
+
+        if (itemsToDelete.length > 0) {
             options.push({
                 icon: Expensicons.Trashcan,
                 text: translate('search.bulkActions.delete'),
                 value: CONST.SEARCH.BULK_ACTION_TYPES.DELETE,
-                onSelected: () => setDeleteModalVisible(true),
+                onSelected: () => onSelectDeleteOption(itemsToDelete),
             });
         }
 
@@ -115,7 +117,7 @@ function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems,
                 isDisabled={isOffline}
             />
         );
-    }, [clearSelectedItems, hash, isOffline, selectedItems, setDeleteModalVisible, styles.colorMuted, styles.fontWeightNormal, theme.icon, translate]);
+    }, [clearSelectedItems, hash, isOffline, onSelectDeleteOption, selectedItems, styles.colorMuted, styles.fontWeightNormal, theme.icon, translate]);
 
     if (isSmallScreenWidth) {
         return null;

From e684ada92e1a79736f3fb2168b12962c51ce4830 Mon Sep 17 00:00:00 2001
From: Wojciech Boman <wojciechboman@gmail.com>
Date: Thu, 11 Jul 2024 15:09:36 +0200
Subject: [PATCH 3/8] Add shouldCloseModalOnSelect to DropdownOption

---
 .../ButtonWithDropdownMenu/types.ts           |  1 +
 .../Search/SearchListWithHeader.tsx           | 15 ++++++++++--
 src/components/Search/SearchPageHeader.tsx    | 23 ++++++++++++-------
 src/pages/Search/SearchSelectedNarrow.tsx     |  7 +++++-
 4 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/src/components/ButtonWithDropdownMenu/types.ts b/src/components/ButtonWithDropdownMenu/types.ts
index d1eedd560694..59621a8dd58c 100644
--- a/src/components/ButtonWithDropdownMenu/types.ts
+++ b/src/components/ButtonWithDropdownMenu/types.ts
@@ -27,6 +27,7 @@ type DropdownOption<TValueType> = {
     interactive?: boolean;
     numberOfLinesTitle?: number;
     titleStyle?: ViewStyle;
+    shouldCloseModalOnSelect?: boolean;
 };
 
 type ButtonWithDropdownMenuProps<TValueType> = {
diff --git a/src/components/Search/SearchListWithHeader.tsx b/src/components/Search/SearchListWithHeader.tsx
index f7802b2578e9..d038d2a625a6 100644
--- a/src/components/Search/SearchListWithHeader.tsx
+++ b/src/components/Search/SearchListWithHeader.tsx
@@ -1,5 +1,6 @@
 import type {ForwardedRef} from 'react';
 import React, {forwardRef, useCallback, useEffect, useMemo, useState} from 'react';
+import ConfirmModal from '@components/ConfirmModal';
 import * as Expensicons from '@components/Icon/Expensicons';
 import MenuItem from '@components/MenuItem';
 import Modal from '@components/Modal';
@@ -7,6 +8,7 @@ import SelectionList from '@components/SelectionList';
 import type {BaseSelectionListProps, ReportListItemType, SelectionListHandle, TransactionListItemType} from '@components/SelectionList/types';
 import useLocalize from '@hooks/useLocalize';
 import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as SearchActions from '@libs/actions/Search';
 import * as SearchUtils from '@libs/SearchUtils';
 import CONST from '@src/CONST';
 import type {SearchDataTypes, SearchQuery} from '@src/types/onyx/SearchResults';
@@ -71,7 +73,7 @@ function SearchListWithHeader(
 
         clearSelectedItems();
         setDeleteExpensesConfirmModalVisible(false);
-        // SearchActions.deleteMoneyRequestOnSearch(hash, selectedItemsToDelete);
+        SearchActions.deleteMoneyRequestOnSearch(hash, selectedItemsToDelete);
     };
 
     useEffect(() => {
@@ -189,7 +191,16 @@ function SearchListWithHeader(
                 onSelectAll={toggleAllTransactions}
                 isMobileSelectionModeActive={isMobileSelectionModeActive}
             />
-
+            <ConfirmModal
+                isVisible={deleteExpensesConfirmModalVisible}
+                onConfirm={handleDeleteExpenses}
+                onCancel={handleOnCancelConfirmModal}
+                title={translate('iou.deleteExpense')}
+                prompt={translate('iou.deleteConfirmation')}
+                confirmText={translate('common.delete')}
+                cancelText={translate('common.cancel')}
+                danger
+            />
             <Modal
                 isVisible={isModalVisible}
                 type={CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED}
diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx
index 2c784414f17c..72d608213291 100644
--- a/src/components/Search/SearchPageHeader.tsx
+++ b/src/components/Search/SearchPageHeader.tsx
@@ -59,13 +59,8 @@ function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems,
                 icon: Expensicons.Trashcan,
                 text: translate('search.bulkActions.delete'),
                 value: CONST.SEARCH.BULK_ACTION_TYPES.DELETE,
-                onSelected: () => {
-                    clearSelectedItems?.();
-                    if (isMobileSelectionModeActive) {
-                        setIsMobileSelectionModeActive?.(false);
-                    }
-                    SearchActions.deleteMoneyRequestOnSearch(hash, itemsToDelete);
-                },
+                shouldCloseModalOnSelect: true,
+                onSelected: () => onSelectDeleteOption(itemsToDelete),
             });
         }
 
@@ -122,7 +117,19 @@ function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems,
         }
 
         return options;
-    }, [clearSelectedItems, hash, selectedItems, selectedItemsKeys, styles, theme, translate, isMobileSelectionModeActive, setIsMobileSelectionModeActive]);
+    }, [
+        selectedItemsKeys,
+        selectedItems,
+        translate,
+        onSelectDeleteOption,
+        clearSelectedItems,
+        isMobileSelectionModeActive,
+        hash,
+        setIsMobileSelectionModeActive,
+        theme.icon,
+        styles.colorMuted,
+        styles.fontWeightNormal,
+    ]);
 
     if (isSmallScreenWidth) {
         if (isMobileSelectionModeActive) {
diff --git a/src/pages/Search/SearchSelectedNarrow.tsx b/src/pages/Search/SearchSelectedNarrow.tsx
index b90142ff5873..11b0e376c77b 100644
--- a/src/pages/Search/SearchSelectedNarrow.tsx
+++ b/src/pages/Search/SearchSelectedNarrow.tsx
@@ -43,7 +43,12 @@ function SearchSelectedNarrow({options, itemsLength}: SearchSelectedNarrowProps)
                     <MenuItem
                         title={option.text}
                         icon={option.icon}
-                        onPress={option.onSelected}
+                        onPress={() => {
+                            if (option?.shouldCloseModalOnSelect) {
+                                closeMenu();
+                            }
+                            option?.onSelected?.();
+                        }}
                         key={option.value}
                     />
                 ))}

From 488e7a14841bce977b75e2387e5b16cc6f65b91a Mon Sep 17 00:00:00 2001
From: Wojciech Boman <wojciechboman@gmail.com>
Date: Thu, 11 Jul 2024 15:55:42 +0200
Subject: [PATCH 4/8] Add translations for deleting multiple expenses

---
 src/components/Search/SearchListWithHeader.tsx | 4 ++--
 src/languages/en.ts                            | 5 +++--
 src/languages/es.ts                            | 6 ++++--
 src/languages/types.ts                         | 5 +++++
 4 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/src/components/Search/SearchListWithHeader.tsx b/src/components/Search/SearchListWithHeader.tsx
index d038d2a625a6..283b68bf17af 100644
--- a/src/components/Search/SearchListWithHeader.tsx
+++ b/src/components/Search/SearchListWithHeader.tsx
@@ -195,8 +195,8 @@ function SearchListWithHeader(
                 isVisible={deleteExpensesConfirmModalVisible}
                 onConfirm={handleDeleteExpenses}
                 onCancel={handleOnCancelConfirmModal}
-                title={translate('iou.deleteExpense')}
-                prompt={translate('iou.deleteConfirmation')}
+                title={translate('iou.deleteExpense', {count: selectedItemsToDelete.length})}
+                prompt={translate('iou.deleteConfirmation', {count: selectedItemsToDelete.length})}
                 confirmText={translate('common.delete')}
                 cancelText={translate('common.cancel')}
                 danger
diff --git a/src/languages/en.ts b/src/languages/en.ts
index a0ec026f79e4..e3e7ac8349dc 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -24,6 +24,7 @@ import type {
     DelegateSubmitParams,
     DeleteActionParams,
     DeleteConfirmationParams,
+    DeleteExpenseParams,
     DidSplitAmountMessageParams,
     DistanceRateOperationsParams,
     EditActionParams,
@@ -702,8 +703,8 @@ export default {
             `${count} ${Str.pluralize('expense', 'expenses', count)}${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}${
                 pendingReceipts > 0 ? `, ${pendingReceipts} pending` : ''
             }`,
-        deleteExpense: 'Delete expense',
-        deleteConfirmation: 'Are you sure that you want to delete this expense?',
+        deleteExpense: ({count}: DeleteExpenseParams = {count: 1}) => `Delete ${Str.pluralize('expense', 'expenses', count)}`,
+        deleteConfirmation: ({count}: DeleteExpenseParams = {count: 1}) => `Are you sure that you want to delete ${Str.pluralize('this expense', 'these expenses', count)}?`,
         settledExpensify: 'Paid',
         settledElsewhere: 'Paid elsewhere',
         individual: 'Individual',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index a1c1b75d4c86..7b346a89b55a 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -22,6 +22,7 @@ import type {
     DelegateSubmitParams,
     DeleteActionParams,
     DeleteConfirmationParams,
+    DeleteExpenseParams,
     DidSplitAmountMessageParams,
     DistanceRateOperationsParams,
     EditActionParams,
@@ -695,8 +696,9 @@ export default {
             `${count} ${Str.pluralize('gasto', 'gastos', count)}${scanningReceipts > 0 ? `, ${scanningReceipts} escaneando` : ''}${
                 pendingReceipts > 0 ? `, ${pendingReceipts} pendiente` : ''
             }`,
-        deleteExpense: 'Eliminar gasto',
-        deleteConfirmation: '¿Estás seguro de que quieres eliminar esta solicitud?',
+
+        deleteExpense: ({count}: DeleteExpenseParams = {count: 1}) => `Eliminar ${Str.pluralize('gasto', 'gastos', count)}`,
+        deleteConfirmation: ({count}: DeleteExpenseParams = {count: 1}) => `¿Estás seguro de que quieres eliminar ${Str.pluralize('esta solicitud', 'estas solicitudes', count)}?`,
         settledExpensify: 'Pagado',
         settledElsewhere: 'Pagado de otra forma',
         individual: 'Individual',
diff --git a/src/languages/types.ts b/src/languages/types.ts
index 78a711fe8282..872ac5e41694 100644
--- a/src/languages/types.ts
+++ b/src/languages/types.ts
@@ -341,6 +341,10 @@ type RemoveMembersWarningPrompt = {
     ownerName: string;
 };
 
+type DeleteExpenseParams = {
+    count: number;
+};
+
 export type {
     AddressLineParams,
     AdminCanceledRequestParams,
@@ -460,4 +464,5 @@ export type {
     StripePaidParams,
     UnapprovedParams,
     RemoveMembersWarningPrompt,
+    DeleteExpenseParams,
 };

From acf7bd4079e5a46141d7435bb2ecda83f333df1e Mon Sep 17 00:00:00 2001
From: Wojciech Boman <wojciechboman@gmail.com>
Date: Thu, 11 Jul 2024 16:19:32 +0200
Subject: [PATCH 5/8] Fix TS in SearchPageHeader

---
 src/components/Search/SearchPageHeader.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx
index 72d608213291..3779b217436c 100644
--- a/src/components/Search/SearchPageHeader.tsx
+++ b/src/components/Search/SearchPageHeader.tsx
@@ -23,7 +23,7 @@ type SearchHeaderProps = {
     selectedItems?: SelectedTransactions;
     clearSelectedItems?: () => void;
     hash: number;
-    onSelectDeleteOption: (itemsToDelete: string[]) => void;
+    onSelectDeleteOption?: (itemsToDelete: string[]) => void;
     isMobileSelectionModeActive?: boolean;
     setIsMobileSelectionModeActive?: (isMobileSelectionModeActive: boolean) => void;
 };
@@ -60,7 +60,7 @@ function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems,
                 text: translate('search.bulkActions.delete'),
                 value: CONST.SEARCH.BULK_ACTION_TYPES.DELETE,
                 shouldCloseModalOnSelect: true,
-                onSelected: () => onSelectDeleteOption(itemsToDelete),
+                onSelected: () => onSelectDeleteOption?.(itemsToDelete),
             });
         }
 

From 5df8ba63b51cf8be7a1cd0cf7a75673ed623cc3d Mon Sep 17 00:00:00 2001
From: Wojciech Boman <wojciechboman@gmail.com>
Date: Thu, 11 Jul 2024 16:22:17 +0200
Subject: [PATCH 6/8] Rename SearchHeaderProps to SearchPageHeaderProps

---
 src/components/Search/SearchPageHeader.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx
index 3779b217436c..9bfa78849800 100644
--- a/src/components/Search/SearchPageHeader.tsx
+++ b/src/components/Search/SearchPageHeader.tsx
@@ -18,7 +18,7 @@ import type DeepValueOf from '@src/types/utils/DeepValueOf';
 import type IconAsset from '@src/types/utils/IconAsset';
 import type {SelectedTransactions} from './types';
 
-type SearchHeaderProps = {
+type SearchPageHeaderProps = {
     query: SearchQuery;
     selectedItems?: SelectedTransactions;
     clearSelectedItems?: () => void;
@@ -30,7 +30,7 @@ type SearchHeaderProps = {
 
 type SearchHeaderOptionValue = DeepValueOf<typeof CONST.SEARCH.BULK_ACTION_TYPES> | undefined;
 
-function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems, onSelectDeleteOption, isMobileSelectionModeActive, setIsMobileSelectionModeActive}: SearchHeaderProps) {
+function SearchPageHeader({query, selectedItems = {}, hash, clearSelectedItems, onSelectDeleteOption, isMobileSelectionModeActive, setIsMobileSelectionModeActive}: SearchPageHeaderProps) {
     const {translate} = useLocalize();
     const theme = useTheme();
     const styles = useThemeStyles();

From 4c7775ca19a9bc1c1516172a2faa13893f429c7c Mon Sep 17 00:00:00 2001
From: Wojciech Boman <wojciechboman@gmail.com>
Date: Fri, 12 Jul 2024 10:09:43 +0200
Subject: [PATCH 7/8] Fix displaying delete modal on iOS

---
 src/pages/Search/SearchSelectedNarrow.tsx | 34 +++++++++++++++++------
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/src/pages/Search/SearchSelectedNarrow.tsx b/src/pages/Search/SearchSelectedNarrow.tsx
index 11b0e376c77b..4de6ee1eef57 100644
--- a/src/pages/Search/SearchSelectedNarrow.tsx
+++ b/src/pages/Search/SearchSelectedNarrow.tsx
@@ -15,6 +15,7 @@ type SearchSelectedNarrowProps = {options: Array<DropdownOption<SearchHeaderOpti
 function SearchSelectedNarrow({options, itemsLength}: SearchSelectedNarrowProps) {
     const styles = useThemeStyles();
     const {translate} = useLocalize();
+    const selectedOptionIndexRef = useRef(-1);
 
     const [isModalVisible, setIsModalVisible] = useState(false);
     const buttonRef = useRef<View>(null);
@@ -22,6 +23,27 @@ function SearchSelectedNarrow({options, itemsLength}: SearchSelectedNarrowProps)
     const openMenu = () => setIsModalVisible(true);
     const closeMenu = () => setIsModalVisible(false);
 
+    const handleOnModalHide = () => {
+        if (selectedOptionIndexRef.current === -1) {
+            return;
+        }
+        options[selectedOptionIndexRef.current]?.onSelected?.();
+    };
+
+    const handleOnMenuItemPress = (option: DropdownOption<SearchHeaderOptionValue>, index: number) => {
+        if (option?.shouldCloseModalOnSelect) {
+            selectedOptionIndexRef.current = index;
+            closeMenu();
+            return;
+        }
+        option?.onSelected?.();
+    };
+
+    const handleOnCloseMenu = () => {
+        selectedOptionIndexRef.current = -1;
+        closeMenu();
+    };
+
     return (
         <View style={[styles.pb4]}>
             <Button
@@ -37,18 +59,14 @@ function SearchSelectedNarrow({options, itemsLength}: SearchSelectedNarrowProps)
             <Modal
                 isVisible={isModalVisible}
                 type={CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED}
-                onClose={closeMenu}
+                onClose={handleOnCloseMenu}
+                onModalHide={handleOnModalHide}
             >
-                {options.map((option) => (
+                {options.map((option, index) => (
                     <MenuItem
                         title={option.text}
                         icon={option.icon}
-                        onPress={() => {
-                            if (option?.shouldCloseModalOnSelect) {
-                                closeMenu();
-                            }
-                            option?.onSelected?.();
-                        }}
+                        onPress={() => handleOnMenuItemPress(option, index)}
                         key={option.value}
                     />
                 ))}

From 97a916a564782c04ade121179c012dce525f1d30 Mon Sep 17 00:00:00 2001
From: Wojciech Boman <wojciechboman@gmail.com>
Date: Fri, 12 Jul 2024 10:16:57 +0200
Subject: [PATCH 8/8] Rename DeleteExpenseParams to
 DeleteExpenseTranslationParams

---
 src/languages/en.ts    | 6 +++---
 src/languages/es.ts    | 6 +++---
 src/languages/types.ts | 4 ++--
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/languages/en.ts b/src/languages/en.ts
index e3e7ac8349dc..f127fa434145 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -24,7 +24,7 @@ import type {
     DelegateSubmitParams,
     DeleteActionParams,
     DeleteConfirmationParams,
-    DeleteExpenseParams,
+    DeleteExpenseTranslationParams,
     DidSplitAmountMessageParams,
     DistanceRateOperationsParams,
     EditActionParams,
@@ -703,8 +703,8 @@ export default {
             `${count} ${Str.pluralize('expense', 'expenses', count)}${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}${
                 pendingReceipts > 0 ? `, ${pendingReceipts} pending` : ''
             }`,
-        deleteExpense: ({count}: DeleteExpenseParams = {count: 1}) => `Delete ${Str.pluralize('expense', 'expenses', count)}`,
-        deleteConfirmation: ({count}: DeleteExpenseParams = {count: 1}) => `Are you sure that you want to delete ${Str.pluralize('this expense', 'these expenses', count)}?`,
+        deleteExpense: ({count}: DeleteExpenseTranslationParams = {count: 1}) => `Delete ${Str.pluralize('expense', 'expenses', count)}`,
+        deleteConfirmation: ({count}: DeleteExpenseTranslationParams = {count: 1}) => `Are you sure that you want to delete ${Str.pluralize('this expense', 'these expenses', count)}?`,
         settledExpensify: 'Paid',
         settledElsewhere: 'Paid elsewhere',
         individual: 'Individual',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 7b346a89b55a..a4ce53f1fe05 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -22,7 +22,7 @@ import type {
     DelegateSubmitParams,
     DeleteActionParams,
     DeleteConfirmationParams,
-    DeleteExpenseParams,
+    DeleteExpenseTranslationParams,
     DidSplitAmountMessageParams,
     DistanceRateOperationsParams,
     EditActionParams,
@@ -697,8 +697,8 @@ export default {
                 pendingReceipts > 0 ? `, ${pendingReceipts} pendiente` : ''
             }`,
 
-        deleteExpense: ({count}: DeleteExpenseParams = {count: 1}) => `Eliminar ${Str.pluralize('gasto', 'gastos', count)}`,
-        deleteConfirmation: ({count}: DeleteExpenseParams = {count: 1}) => `¿Estás seguro de que quieres eliminar ${Str.pluralize('esta solicitud', 'estas solicitudes', count)}?`,
+        deleteExpense: ({count}: DeleteExpenseTranslationParams = {count: 1}) => `Eliminar ${Str.pluralize('gasto', 'gastos', count)}`,
+        deleteConfirmation: ({count}: DeleteExpenseTranslationParams = {count: 1}) => `¿Estás seguro de que quieres eliminar ${Str.pluralize('esta solicitud', 'estas solicitudes', count)}?`,
         settledExpensify: 'Pagado',
         settledElsewhere: 'Pagado de otra forma',
         individual: 'Individual',
diff --git a/src/languages/types.ts b/src/languages/types.ts
index 872ac5e41694..ae21a804f06f 100644
--- a/src/languages/types.ts
+++ b/src/languages/types.ts
@@ -341,7 +341,7 @@ type RemoveMembersWarningPrompt = {
     ownerName: string;
 };
 
-type DeleteExpenseParams = {
+type DeleteExpenseTranslationParams = {
     count: number;
 };
 
@@ -464,5 +464,5 @@ export type {
     StripePaidParams,
     UnapprovedParams,
     RemoveMembersWarningPrompt,
-    DeleteExpenseParams,
+    DeleteExpenseTranslationParams,
 };
