diff --git a/src/components/Search/SearchPageFooter.tsx b/src/components/Search/SearchPageFooter.tsx
index bb7d7b65616b..7f428e162a7f 100644
--- a/src/components/Search/SearchPageFooter.tsx
+++ b/src/components/Search/SearchPageFooter.tsx
@@ -7,13 +7,14 @@ import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import {convertToDisplayString} from '@libs/CurrencyUtils';
-import type {SearchResultsInfo} from '@src/types/onyx/SearchResults';
type SearchPageFooterProps = {
- metadata: SearchResultsInfo;
+ count: number | undefined;
+ total: number | undefined;
+ currency: string | undefined;
};
-function SearchPageFooter({metadata}: SearchPageFooterProps) {
+function SearchPageFooter({count, total, currency}: SearchPageFooterProps) {
const theme = useTheme();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
@@ -26,11 +27,11 @@ function SearchPageFooter({metadata}: SearchPageFooterProps) {
{`${translate('common.expenses')}:`}
- {metadata.count}
+ {count}
{`${translate('common.totalSpend')}:`}
- {convertToDisplayString(metadata.total, metadata.currency)}
+ {convertToDisplayString(total, currency)}
);
diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx
index f78581ee58b2..d11a9ee15123 100644
--- a/src/components/Search/index.tsx
+++ b/src/components/Search/index.tsx
@@ -26,7 +26,7 @@ import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNa
import Performance from '@libs/Performance';
import {getIOUActionForTransactionID, isExportIntegrationAction, isIntegrationMessageAction} from '@libs/ReportActionsUtils';
import {canEditFieldOfMoneyRequest, isArchivedReport} from '@libs/ReportUtils';
-import {buildCannedSearchQuery, buildSearchQueryString} from '@libs/SearchQueryUtils';
+import {buildCannedSearchQuery, buildSearchQueryJSON, buildSearchQueryString} from '@libs/SearchQueryUtils';
import {
getColumnsToShow,
getListItem,
@@ -101,6 +101,8 @@ function mapTransactionItemToSelectedEntry(
reportID: item.reportID,
policyID: item.policyID,
amount: item.modifiedAmount ?? item.amount,
+ convertedAmount: item.convertedAmount,
+ convertedCurrency: item.convertedCurrency,
},
];
}
@@ -178,6 +180,8 @@ function prepareTransactionsList(
reportID: item.reportID,
policyID: item.policyID,
amount: Math.abs(item.modifiedAmount || item.amount),
+ convertedAmount: item.convertedAmount,
+ convertedCurrency: item.convertedCurrency,
},
};
}
@@ -211,6 +215,7 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
const [transactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {canBeMissing: true});
const previousTransactions = usePrevious(transactions);
const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, {canBeMissing: true});
+ const [savedSearches] = useOnyx(ONYXKEYS.SAVED_SEARCHES, {canBeMissing: true});
const [outstandingReportsByPolicyID] = useOnyx(ONYXKEYS.DERIVED.OUTSTANDING_REPORTS_BY_POLICY_ID, {canBeMissing: true});
const [archivedReportsIdSet = new Set()] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, {
@@ -250,13 +255,16 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
const suggestedSearches = useMemo(() => getSuggestedSearches(accountID, defaultCardFeed?.id), [defaultCardFeed?.id, accountID]);
const {type, status, sortBy, sortOrder, hash, similarSearchHash, groupBy} = queryJSON;
- const searchKey = useMemo(() => Object.values(suggestedSearches).find((search) => search.similarSearchHash === similarSearchHash)?.key, [suggestedSearches, similarSearchHash]);
+ const searchKey = useMemo(() => Object.values(suggestedSearches).find((search) => search.similarSearchHash === similarSearchHash)?.key, [suggestedSearches, similarSearchHash]);
const shouldCalculateTotals = useMemo(() => {
if (offset !== 0) {
return false;
}
- if (!searchKey) {
+
+ const savedSearchValues = Object.values(savedSearches ?? {});
+
+ if (!savedSearchValues.length && !searchKey) {
return false;
}
@@ -270,8 +278,20 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CARD,
CONST.SEARCH.SEARCH_KEYS.RECONCILIATION,
];
- return eligibleSearchKeys.includes(searchKey);
- }, [offset, searchKey]);
+
+ if (eligibleSearchKeys.includes(searchKey)) {
+ return true;
+ }
+
+ for (const savedSearch of savedSearchValues) {
+ const searchData = buildSearchQueryJSON(savedSearch.query);
+ if (searchData && searchData.similarSearchHash === similarSearchHash) {
+ return true;
+ }
+ }
+
+ return false;
+ }, [offset, savedSearches, searchKey, similarSearchHash]);
const previousReportActions = usePrevious(reportActions);
const reportActionsArray = useMemo(
@@ -432,6 +452,8 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
reportID: transaction.reportID,
policyID: transaction.policyID,
amount: transaction.modifiedAmount ?? transaction.amount,
+ convertedAmount: transaction.convertedAmount,
+ convertedCurrency: transaction.convertedCurrency,
};
});
});
@@ -461,6 +483,8 @@ function Search({queryJSON, searchResults, onSearchListScroll, contentContainerS
reportID: transaction.reportID,
policyID: transaction.policyID,
amount: transaction.modifiedAmount ?? transaction.amount,
+ convertedAmount: transaction.convertedAmount,
+ convertedCurrency: transaction.convertedCurrency,
};
});
}
diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts
index c695280b25a6..49cb3a44a8fb 100644
--- a/src/components/Search/types.ts
+++ b/src/components/Search/types.ts
@@ -35,6 +35,12 @@ type SelectedTransactionInfo = {
/** The transaction amount */
amount: number;
+
+ /** The converted transaction amount into either group currency, or the active policy currency */
+ convertedAmount: number;
+
+ /** The currency that the converted amount is in */
+ convertedCurrency: string;
};
/** Model of selected transactions */
diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts
index 989a003fed2e..fec2a31fce4e 100644
--- a/src/libs/SearchQueryUtils.ts
+++ b/src/libs/SearchQueryUtils.ts
@@ -302,9 +302,15 @@ function getQueryHashes(query: SearchQueryJSON): {primaryHash: number; recentSea
const filterSet = new Set(orderedQuery);
+ // Certain filters shouldn't affect whether two searchers are similar or not, since they dont
+ // actually filter out results
+ const similarSearchIgnoredFilters = new Set([CONST.SEARCH.SYNTAX_FILTER_KEYS.GROUP_CURRENCY]);
+
query.flatFilters
.map((filter) => {
- filterSet.add(filter.key);
+ if (!similarSearchIgnoredFilters.has(filter.key)) {
+ filterSet.add(filter.key);
+ }
const filters = cloneDeep(filter.filters);
filters.sort((a, b) => customCollator.compare(a.value.toString(), b.value.toString()));
diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts
index 871641787e4f..d94fcd2c0b9f 100644
--- a/src/libs/SearchUIUtils.ts
+++ b/src/libs/SearchUIUtils.ts
@@ -995,6 +995,8 @@ function getTransactionsSections(
hasViolation: transactionItem.hasViolation,
cardID: transactionItem.cardID,
cardName: transactionItem.cardName,
+ convertedAmount: transactionItem.convertedAmount,
+ convertedCurrency: transactionItem.convertedCurrency,
};
transactionsSections.push(transactionSection);
diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx
index 5bc538acdb9a..378198ce4629 100644
--- a/src/pages/Search/SearchPage.tsx
+++ b/src/pages/Search/SearchPage.tsx
@@ -670,6 +670,16 @@ function SearchPage({route}: SearchPageProps) {
}
}, []);
+ const footerData = useMemo(() => {
+ const shouldUseClientTotal = selectedTransactionsKeys.length > 0 && !areAllMatchingItemsSelected;
+
+ const currency = metadata?.currency;
+ const count = shouldUseClientTotal ? selectedTransactionsKeys.length : metadata?.count;
+ const total = shouldUseClientTotal ? Object.values(selectedTransactions).reduce((acc, transaction) => acc - (transaction.convertedAmount ?? 0), 0) : metadata?.total;
+
+ return {count, total, currency};
+ }, [areAllMatchingItemsSelected, metadata?.count, metadata?.currency, metadata?.total, selectedTransactions, selectedTransactionsKeys.length]);
+
if (shouldUseNarrowLayout) {
return (
<>
@@ -680,6 +690,7 @@ function SearchPage({route}: SearchPageProps) {
headerButtonsOptions={headerButtonsOptions}
searchResults={searchResults}
isMobileSelectionModeEnabled={isMobileSelectionModeEnabled}
+ footerData={footerData}
/>
- {shouldShowFooter && }
+ {shouldShowFooter && (
+
+ )}
>;
searchResults?: SearchResults;
isMobileSelectionModeEnabled: boolean;
+ footerData: {
+ count: number | undefined;
+ total: number | undefined;
+ currency: string | undefined;
+ };
};
-function SearchPageNarrow({queryJSON, headerButtonsOptions, searchResults, isMobileSelectionModeEnabled}: SearchPageNarrowProps) {
+function SearchPageNarrow({queryJSON, headerButtonsOptions, searchResults, isMobileSelectionModeEnabled, footerData}: SearchPageNarrowProps) {
const {translate} = useLocalize();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const {windowHeight} = useWindowDimensions();
@@ -142,10 +147,9 @@ function SearchPageNarrow({queryJSON, headerButtonsOptions, searchResults, isMob
);
}
+ const shouldShowFooter = !!footerData?.count;
const isDataLoaded = isSearchDataLoaded(searchResults, queryJSON);
const shouldShowLoadingState = !isOffline && (!isDataLoaded || !!currentSearchResults?.search?.isLoading);
- const metadata = searchResults?.search;
- const shouldShowFooter = !!metadata?.count;
return (
)}
- {shouldShowFooter && }
+ {shouldShowFooter && (
+
+ )}
);
diff --git a/src/types/onyx/SearchResults.ts b/src/types/onyx/SearchResults.ts
index 6e848b757926..1d8523ad40cf 100644
--- a/src/types/onyx/SearchResults.ts
+++ b/src/types/onyx/SearchResults.ts
@@ -428,11 +428,11 @@ type SearchTransaction = {
/** The display name of the purchaser card, if any */
cardName?: string;
- /** The converted amount of the transaction, if a currency conversion is used */
- convertedAmount?: number;
+ /** The converted amount of the transaction, defaults to the active policies currency, or the converted currency if a currency conversion is used */
+ convertedAmount: number;
/** The currency that the converted amount is in */
- convertedCurrency?: string;
+ convertedCurrency: string;
};
/** Model of tasks search result */
diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts
index 069fe26f46ff..94348f9a3d3a 100644
--- a/tests/unit/Search/SearchUIUtilsTest.ts
+++ b/tests/unit/Search/SearchUIUtilsTest.ts
@@ -321,6 +321,8 @@ const searchResults: OnyxTypes.SearchResults = {
errors: undefined,
filename: undefined,
isActionLoading: false,
+ convertedAmount: -5000,
+ convertedCurrency: 'USD',
},
[`transactions_${transactionID2}`]: {
accountID: adminAccountID,
@@ -365,6 +367,8 @@ const searchResults: OnyxTypes.SearchResults = {
errors: undefined,
filename: undefined,
isActionLoading: false,
+ convertedAmount: -5000,
+ convertedCurrency: 'USD',
},
...allViolations,
[`transactions_${transactionID3}`]: {
@@ -410,6 +414,8 @@ const searchResults: OnyxTypes.SearchResults = {
filename: undefined,
isActionLoading: false,
hasViolation: undefined,
+ convertedAmount: -5000,
+ convertedCurrency: 'USD',
},
[`transactions_${transactionID4}`]: {
accountID: adminAccountID,
@@ -454,6 +460,8 @@ const searchResults: OnyxTypes.SearchResults = {
filename: undefined,
isActionLoading: false,
hasViolation: undefined,
+ convertedAmount: -5000,
+ convertedCurrency: 'USD',
},
},
search: {
@@ -692,6 +700,8 @@ const transactionsListItems = [
isActionLoading: false,
hasViolation: false,
violations: [],
+ convertedAmount: -5000,
+ convertedCurrency: 'USD',
},
{
accountID: 18439984,
@@ -763,6 +773,8 @@ const transactionsListItems = [
type: CONST.VIOLATION_TYPES.VIOLATION,
},
],
+ convertedAmount: -5000,
+ convertedCurrency: 'USD',
},
{
accountID: 18439984,
@@ -829,6 +841,8 @@ const transactionsListItems = [
isActionLoading: false,
hasViolation: undefined,
violations: [],
+ convertedAmount: -5000,
+ convertedCurrency: 'USD',
},
{
accountID: 18439984,
@@ -895,6 +909,8 @@ const transactionsListItems = [
isActionLoading: false,
hasViolation: undefined,
violations: [],
+ convertedAmount: -5000,
+ convertedCurrency: 'USD',
},
] as TransactionListItemType[];
@@ -998,6 +1014,8 @@ const transactionReportGroupListItems = [
filename: undefined,
isActionLoading: false,
violations: [],
+ convertedAmount: -5000,
+ convertedCurrency: 'USD',
},
],
type: 'expense',
@@ -1107,6 +1125,8 @@ const transactionReportGroupListItems = [
errors: undefined,
filename: undefined,
isActionLoading: false,
+ convertedAmount: -5000,
+ convertedCurrency: 'USD',
},
],
type: 'expense',
@@ -2275,6 +2295,8 @@ describe('SearchUIUtils', () => {
transactionID: '1805965960759424086',
transactionThreadReportID: '4139222832581831',
transactionType: 'cash',
+ convertedAmount: -5000,
+ convertedCurrency: 'USD',
},
},
search: {
diff --git a/tests/unit/Search/handleActionButtonPressTest.ts b/tests/unit/Search/handleActionButtonPressTest.ts
index 8f3b0004bba1..78e2c92eb7ed 100644
--- a/tests/unit/Search/handleActionButtonPressTest.ts
+++ b/tests/unit/Search/handleActionButtonPressTest.ts
@@ -139,6 +139,8 @@ const mockReportItemWithHold = {
isAmountColumnWide: false,
isTaxAmountColumnWide: false,
shouldAnimateInHighlight: false,
+ convertedAmount: 1200,
+ convertedCurrency: 'USD',
},
{
report: {
@@ -195,6 +197,8 @@ const mockReportItemWithHold = {
isAmountColumnWide: false,
isTaxAmountColumnWide: false,
shouldAnimateInHighlight: false,
+ convertedAmount: 1200,
+ convertedCurrency: 'USD',
},
],
isSelected: false,