diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index cca81f999da4..1589d67c985a 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -47,6 +47,8 @@ const ROUTES = {
SEARCH_ADVANCED_FILTERS_STATUS: 'search/filters/status',
+ SEARCH_ADVANCED_FILTERS_CURRENCY: 'search/filters/currency',
+
SEARCH_ADVANCED_FILTERS_MERCHANT: 'search/filters/merchant',
SEARCH_ADVANCED_FILTERS_DESCRIPTION: 'search/filters/description',
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index 6848deaab86b..831a058ebbbb 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -35,6 +35,7 @@ const SCREENS = {
ADVANCED_FILTERS_DATE_RHP: 'Search_Advanced_Filters_Date_RHP',
ADVANCED_FILTERS_TYPE_RHP: 'Search_Advanced_Filters_Type_RHP',
ADVANCED_FILTERS_STATUS_RHP: 'Search_Advanced_Filters_Status_RHP',
+ ADVANCED_FILTERS_CURRENCY_RHP: 'Search_Advanced_Filters_Currency_RHP',
ADVANCED_FILTERS_DESCRIPTION_RHP: 'Search_Advanced_Filters_Description_RHP',
ADVANCED_FILTERS_MERCHANT_RHP: 'Search_Advanced_Filters_Merchant_RHP',
ADVANCED_FILTERS_REPORT_ID_RHP: 'Search_Advanced_Filters_ReportID_RHP',
diff --git a/src/components/CurrencySelectionList/index.tsx b/src/components/CurrencySelectionList/index.tsx
index bfe4578afd0f..01a27ff5951a 100644
--- a/src/components/CurrencySelectionList/index.tsx
+++ b/src/components/CurrencySelectionList/index.tsx
@@ -3,18 +3,19 @@ import React, {useMemo, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
import SelectionList from '@components/SelectionList';
import RadioListItem from '@components/SelectionList/RadioListItem';
+import SelectableListItem from '@components/SelectionList/SelectableListItem';
import useLocalize from '@hooks/useLocalize';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import ONYXKEYS from '@src/ONYXKEYS';
import type {CurrencyListItem, CurrencySelectionListOnyxProps, CurrencySelectionListProps} from './types';
-function CurrencySelectionList({searchInputLabel, initiallySelectedCurrencyCode, onSelect, currencyList}: CurrencySelectionListProps) {
+function CurrencySelectionList({searchInputLabel, initiallySelectedCurrencyCode, onSelect, currencyList, selectedCurrencies = [], canSelectMultiple = false}: CurrencySelectionListProps) {
const [searchValue, setSearchValue] = useState('');
const {translate} = useLocalize();
const {sections, headerMessage} = useMemo(() => {
const currencyOptions: CurrencyListItem[] = Object.entries(currencyList ?? {}).map(([currencyCode, currencyInfo]) => {
- const isSelectedCurrency = currencyCode === initiallySelectedCurrencyCode;
+ const isSelectedCurrency = currencyCode === initiallySelectedCurrencyCode || selectedCurrencies.includes(currencyCode);
return {
currencyName: currencyInfo?.name ?? '',
text: `${currencyCode} - ${CurrencyUtils.getCurrencySymbol(currencyCode)}`,
@@ -28,6 +29,16 @@ function CurrencySelectionList({searchInputLabel, initiallySelectedCurrencyCode,
const filteredCurrencies = currencyOptions.filter((currencyOption) => searchRegex.test(currencyOption.text ?? '') || searchRegex.test(currencyOption.currencyName));
const isEmpty = searchValue.trim() && !filteredCurrencies.length;
+ if (canSelectMultiple) {
+ filteredCurrencies.sort((currencyA, currencyB) => {
+ if (currencyA.isSelected === currencyB.isSelected) {
+ return 0;
+ }
+
+ return currencyA.isSelected ? -1 : 1;
+ });
+ }
+
return {
sections: isEmpty
? []
@@ -38,12 +49,12 @@ function CurrencySelectionList({searchInputLabel, initiallySelectedCurrencyCode,
],
headerMessage: isEmpty ? translate('common.noResultsFound') : '',
};
- }, [currencyList, searchValue, translate, initiallySelectedCurrencyCode]);
+ }, [currencyList, searchValue, canSelectMultiple, translate, initiallySelectedCurrencyCode, selectedCurrencies]);
return (
);
}
diff --git a/src/components/CurrencySelectionList/types.ts b/src/components/CurrencySelectionList/types.ts
index eb7cf72d4e1e..9bfc31e10886 100644
--- a/src/components/CurrencySelectionList/types.ts
+++ b/src/components/CurrencySelectionList/types.ts
@@ -21,6 +21,12 @@ type CurrencySelectionListProps = CurrencySelectionListOnyxProps & {
/** Callback to fire when a currency is selected */
onSelect: (item: CurrencyListItem) => void;
+
+ /** The array of selected currencies. This prop should be used when multiple currencies can be selected */
+ selectedCurrencies?: string[];
+
+ /** Whether this is a multi-select list */
+ canSelectMultiple?: boolean;
};
export type {CurrencyListItem, CurrencySelectionListProps, CurrencySelectionListOnyxProps};
diff --git a/src/languages/en.ts b/src/languages/en.ts
index ba3b519f1f20..47c00f7d731e 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -3635,6 +3635,7 @@ export default {
after: (date?: string) => `After ${date ?? ''}`,
},
status: 'Status',
+ currency: 'Currency',
},
},
genericErrorPage: {
diff --git a/src/languages/es.ts b/src/languages/es.ts
index f8f130e8d7b9..690ebd641b54 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -3689,6 +3689,7 @@ export default {
after: (date?: string) => `Después de ${date ?? ''}`,
},
status: 'Estado',
+ currency: 'Divisa',
},
},
genericErrorPage: {
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
index 409896bc68de..5b84fba03a39 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
@@ -514,6 +514,7 @@ const SearchAdvancedFiltersModalStackNavigator = createModalStackNavigator require('../../../../pages/Search/SearchFiltersDatePage').default,
[SCREENS.SEARCH.ADVANCED_FILTERS_TYPE_RHP]: () => require('../../../../pages/Search/SearchFiltersTypePage').default,
[SCREENS.SEARCH.ADVANCED_FILTERS_STATUS_RHP]: () => require('../../../../pages/Search/SearchFiltersStatusPage').default,
+ [SCREENS.SEARCH.ADVANCED_FILTERS_CURRENCY_RHP]: () => require('../../../../pages/Search/SearchFiltersCurrencyPage').default,
[SCREENS.SEARCH.ADVANCED_FILTERS_DESCRIPTION_RHP]: () => require('../../../../pages/Search/SearchFiltersDescriptionPage').default,
[SCREENS.SEARCH.ADVANCED_FILTERS_MERCHANT_RHP]: () => require('../../../../pages/Search/SearchFiltersMerchantPage').default,
[SCREENS.SEARCH.ADVANCED_FILTERS_REPORT_ID_RHP]: () => require('../../../../pages/Search/SearchFiltersReportIDPage').default,
diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts
index 758d471e2f7e..00edd4422b5b 100755
--- a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts
+++ b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts
@@ -42,6 +42,7 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial> =
SCREENS.SEARCH.REPORT_RHP,
SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP,
SCREENS.SEARCH.ADVANCED_FILTERS_RHP,
+ SCREENS.SEARCH.ADVANCED_FILTERS_CURRENCY_RHP,
SCREENS.SEARCH.ADVANCED_FILTERS_DATE_RHP,
SCREENS.SEARCH.ADVANCED_FILTERS_TYPE_RHP,
SCREENS.SEARCH.ADVANCED_FILTERS_STATUS_RHP,
diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts
index 7a306bc5e2ac..87802e1130cd 100644
--- a/src/libs/Navigation/linkingConfig/config.ts
+++ b/src/libs/Navigation/linkingConfig/config.ts
@@ -1017,6 +1017,7 @@ const config: LinkingOptions['config'] = {
[SCREENS.SEARCH.ADVANCED_FILTERS_DATE_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_DATE,
[SCREENS.SEARCH.ADVANCED_FILTERS_TYPE_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_TYPE,
[SCREENS.SEARCH.ADVANCED_FILTERS_STATUS_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_STATUS,
+ [SCREENS.SEARCH.ADVANCED_FILTERS_CURRENCY_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_CURRENCY,
[SCREENS.SEARCH.ADVANCED_FILTERS_MERCHANT_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_MERCHANT,
[SCREENS.SEARCH.ADVANCED_FILTERS_DESCRIPTION_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_DESCRIPTION,
[SCREENS.SEARCH.ADVANCED_FILTERS_REPORT_ID_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_REPORT_ID,
diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts
index 6342e17b19fd..f778cca36f62 100644
--- a/src/libs/SearchUtils.ts
+++ b/src/libs/SearchUtils.ts
@@ -424,6 +424,9 @@ function buildQueryStringFromFilters(filterValues: Partial 0) {
+ return `${CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY}:${filterValue.join(',')}`;
+ }
if (filterKey === INPUT_IDS.MERCHANT && filterValue) {
return `${CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT}:${filterValue as string}`;
}
@@ -502,7 +505,7 @@ function buildFilterString(filterName: string, queryFilters: QueryFilter[]) {
queryFilters.forEach((queryFilter, index) => {
// If the previous queryFilter has the same operator (this rule applies only to eq and neq operators) then append the current value
if ((queryFilter.operator === 'eq' && queryFilters[index - 1]?.operator === 'eq') || (queryFilter.operator === 'neq' && queryFilters[index - 1]?.operator === 'neq')) {
- filterValueString += `,${filterName}:${queryFilter.value}`;
+ filterValueString += `,${sanitizeString(queryFilter.value.toString())}`;
} else {
filterValueString += ` ${filterName}${operatorToSignMap[queryFilter.operator]}${queryFilter.value}`;
}
diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx
index e894bae16a1c..0287f3f6427f 100644
--- a/src/pages/Search/AdvancedSearchFilters.tsx
+++ b/src/pages/Search/AdvancedSearchFilters.tsx
@@ -5,6 +5,7 @@ import {useOnyx} from 'react-native-onyx';
import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
import type {LocaleContextProps} from '@components/LocaleContextProvider';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import ScrollView from '@components/ScrollView';
import type {AdvancedFiltersKeys} from '@components/Search/types';
import useLocalize from '@hooks/useLocalize';
import useSingleExecution from '@hooks/useSingleExecution';
@@ -37,9 +38,13 @@ function getFilterDisplayTitle(filters: Partial, fiel
return dateValue;
}
- if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY && filters[fieldName]) {
- const categories = filters[fieldName] ?? [];
- return categories.join(', ');
+ if ((fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY || fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY) && filters[fieldName]) {
+ const filterArray = filters[fieldName] ?? [];
+ return filterArray.join(', ');
+ }
+
+ if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.DESCRIPTION) {
+ return filters[fieldName];
}
if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID && filters[fieldName]) {
const cards = filters[fieldName] ?? [];
@@ -89,6 +94,11 @@ function AdvancedSearchFilters() {
description: 'common.date' as const,
route: ROUTES.SEARCH_ADVANCED_FILTERS_DATE,
},
+ {
+ title: getFilterDisplayTitle(searchAdvancedFilters, CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY, translate),
+ description: 'common.currency' as const,
+ route: ROUTES.SEARCH_ADVANCED_FILTERS_CURRENCY,
+ },
{
title: getFilterDisplayTitle(searchAdvancedFilters, CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT, translate),
description: 'common.merchant' as const,
@@ -131,7 +141,7 @@ function AdvancedSearchFilters() {
};
return (
-
+
{advancedFilters.map((item) => {
const onPress = singleExecution(waitForNavigate(() => Navigation.navigate(item.route)));
@@ -151,11 +161,11 @@ function AdvancedSearchFilters() {
-
+
);
}
diff --git a/src/pages/Search/SearchAdvancedFiltersPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage.tsx
index 9d4864bce8eb..e24d2411226b 100644
--- a/src/pages/Search/SearchAdvancedFiltersPage.tsx
+++ b/src/pages/Search/SearchAdvancedFiltersPage.tsx
@@ -15,6 +15,7 @@ function SearchAdvancedFiltersPage() {
testID={SearchAdvancedFiltersPage.displayName}
shouldShowOfflineIndicatorInWideScreen
offlineIndicatorStyle={styles.mtAuto}
+ includeSafeAreaPaddingBottom={false}
>
diff --git a/src/pages/Search/SearchFiltersCategoryPage.tsx b/src/pages/Search/SearchFiltersCategoryPage.tsx
index 29a149482c81..8105bde2745c 100644
--- a/src/pages/Search/SearchFiltersCategoryPage.tsx
+++ b/src/pages/Search/SearchFiltersCategoryPage.tsx
@@ -126,6 +126,7 @@ function SearchFiltersCategoryPage() {
testID={SearchFiltersCategoryPage.displayName}
shouldShowOfflineIndicatorInWideScreen
offlineIndicatorStyle={styles.mtAuto}
+ includeSafeAreaPaddingBottom={false}
>
-
+
(searchAdvancedFiltersForm?.currency ?? []);
+
+ const handleOnSelectOption = (option: CurrencyListItem) => {
+ if (selectedCurrencies.includes(option.currencyCode)) {
+ setSelectedCurrencies(selectedCurrencies.filter((currency) => currency !== option.currencyCode));
+ return;
+ }
+
+ setSelectedCurrencies([option.currencyCode, ...selectedCurrencies]);
+ };
+
+ const handleOnSubmit = () => {
+ SearchActions.updateAdvancedFilters({...searchAdvancedFiltersForm, currency: selectedCurrencies});
+ Navigation.goBack(ROUTES.SEARCH_ADVANCED_FILTERS);
+ };
+
+ return (
+
+ {({didScreenTransitionEnd}) => (
+
+
+ {
+ if (!didScreenTransitionEnd) {
+ return;
+ }
+ handleOnSelectOption(option);
+ }}
+ />
+
+
+ )}
+
+ );
+}
+
+SearchFiltersCurrencyPage.displayName = 'SearchFiltersCurrencyPage';
+
+export default SearchFiltersCurrencyPage;
diff --git a/src/pages/Search/SearchFiltersDatePage.tsx b/src/pages/Search/SearchFiltersDatePage.tsx
index 3cc19a501198..4bc95aa21351 100644
--- a/src/pages/Search/SearchFiltersDatePage.tsx
+++ b/src/pages/Search/SearchFiltersDatePage.tsx
@@ -34,6 +34,7 @@ function SearchFiltersDatePage() {
testID={SearchFiltersDatePage.displayName}
shouldShowOfflineIndicatorInWideScreen
offlineIndicatorStyle={styles.mtAuto}
+ includeSafeAreaPaddingBottom={false}
>
-
+
-
+
-
+
{({hovered}) => (
-
+
-
-
- {menuTitle}
-
-
+
+ {menuTitle}
+