Skip to content

Commit b0db743

Browse files
authored
Merge pull request #50866 from software-mansion-labs/kicu/50787-search-utils
[No QA] Split SearchUtils into two files
2 parents e40ad30 + b1d816d commit b0db743

29 files changed

+796
-662
lines changed

src/components/Search/SearchContext.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, {useCallback, useContext, useMemo, useState} from 'react';
22
import type {ReportActionListItemType, ReportListItemType, TransactionListItemType} from '@components/SelectionList/types';
3-
import * as SearchUtils from '@libs/SearchUtils';
3+
import * as SearchUIUtils from '@libs/SearchUIUtils';
44
import type ChildrenProps from '@src/types/utils/ChildrenProps';
55
import type {SearchContext, SelectedTransactions} from './types';
66

@@ -23,8 +23,8 @@ function getReportsFromSelectedTransactions(data: TransactionListItemType[] | Re
2323
return (data ?? [])
2424
.filter(
2525
(item) =>
26-
!SearchUtils.isTransactionListItemType(item) &&
27-
!SearchUtils.isReportActionListItemType(item) &&
26+
!SearchUIUtils.isTransactionListItemType(item) &&
27+
!SearchUIUtils.isReportActionListItemType(item) &&
2828
item.reportID &&
2929
item?.transactions?.every((transaction: {keyForList: string | number}) => selectedTransactions[transaction.keyForList]?.isSelected),
3030
)

src/components/Search/SearchPageHeader.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import * as SearchActions from '@libs/actions/Search';
2323
import Log from '@libs/Log';
2424
import Navigation from '@libs/Navigation/Navigation';
2525
import {getAllTaxRates} from '@libs/PolicyUtils';
26-
import * as SearchUtils from '@libs/SearchUtils';
26+
import * as SearchQueryUtils from '@libs/SearchQueryUtils';
2727
import SearchSelectedNarrow from '@pages/Search/SearchSelectedNarrow';
2828
import variables from '@styles/variables';
2929
import CONST from '@src/CONST';
@@ -138,8 +138,8 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) {
138138
const [isDownloadErrorModalVisible, setIsDownloadErrorModalVisible] = useState(false);
139139

140140
const {status, type} = queryJSON;
141-
const isCannedQuery = SearchUtils.isCannedSearchQuery(queryJSON);
142-
const headerText = isCannedQuery ? translate(getHeaderContent(type).titleText) : SearchUtils.getSearchHeaderTitle(queryJSON, personalDetails, cardList, reports, taxRates);
141+
const isCannedQuery = SearchQueryUtils.isCannedSearchQuery(queryJSON);
142+
const headerText = isCannedQuery ? translate(getHeaderContent(type).titleText) : SearchQueryUtils.buildUserReadableQueryString(queryJSON, personalDetails, cardList, reports, taxRates);
143143
const [inputValue, setInputValue] = useState(headerText);
144144

145145
useEffect(() => {
@@ -329,7 +329,7 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) {
329329
}
330330

331331
const onPress = () => {
332-
const filterFormValues = SearchUtils.buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList, personalDetails, cardList, reports, taxRates);
332+
const filterFormValues = SearchQueryUtils.buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList, personalDetails, cardList, reports, taxRates);
333333
SearchActions.updateAdvancedFilters(filterFormValues);
334334

335335
Navigation.navigate(ROUTES.SEARCH_ADVANCED_FILTERS);
@@ -339,10 +339,10 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) {
339339
if (!inputValue) {
340340
return;
341341
}
342-
const inputQueryJSON = SearchUtils.buildSearchQueryJSON(inputValue);
342+
const inputQueryJSON = SearchQueryUtils.buildSearchQueryJSON(inputValue);
343343
if (inputQueryJSON) {
344-
const standardizedQuery = SearchUtils.standardizeQueryJSON(inputQueryJSON, cardList, taxRates);
345-
const query = SearchUtils.buildSearchQueryString(standardizedQuery);
344+
const standardizedQuery = SearchQueryUtils.standardizeQueryJSON(inputQueryJSON, cardList, taxRates);
345+
const query = SearchQueryUtils.buildSearchQueryString(standardizedQuery);
346346
SearchActions.clearAllFilters();
347347
Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query}));
348348
} else {

src/components/Search/SearchRouter/SearchRouter.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import Log from '@libs/Log';
1616
import * as OptionsListUtils from '@libs/OptionsListUtils';
1717
import {getAllTaxRates} from '@libs/PolicyUtils';
1818
import type {OptionData} from '@libs/ReportUtils';
19-
import * as SearchUtils from '@libs/SearchUtils';
19+
import * as SearchQueryUtils from '@libs/SearchQueryUtils';
2020
import Navigation from '@navigation/Navigation';
2121
import variables from '@styles/variables';
2222
import * as Report from '@userActions/Report';
@@ -116,7 +116,7 @@ function SearchRouter({onRouterClose}: SearchRouterProps) {
116116
return;
117117
}
118118
listRef.current?.updateAndScrollToFocusedIndex(0);
119-
const queryJSON = SearchUtils.buildSearchQueryJSON(userQuery);
119+
const queryJSON = SearchQueryUtils.buildSearchQueryJSON(userQuery);
120120

121121
if (queryJSON) {
122122
setUserSearchQuery(queryJSON);
@@ -147,8 +147,8 @@ function SearchRouter({onRouterClose}: SearchRouterProps) {
147147
return;
148148
}
149149
onRouterClose();
150-
const standardizedQuery = SearchUtils.standardizeQueryJSON(query, cardList, taxRates);
151-
const queryString = SearchUtils.buildSearchQueryString(standardizedQuery);
150+
const standardizedQuery = SearchQueryUtils.standardizeQueryJSON(query, cardList, taxRates);
151+
const queryString = SearchQueryUtils.buildSearchQueryString(standardizedQuery);
152152
Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query: queryString}));
153153
clearUserQuery();
154154
},
@@ -180,7 +180,7 @@ function SearchRouter({onRouterClose}: SearchRouterProps) {
180180
isFullWidth={shouldUseNarrowLayout}
181181
updateSearch={onSearchChange}
182182
onSubmit={() => {
183-
onSearchSubmit(SearchUtils.buildSearchQueryJSON(textInputValue));
183+
onSearchSubmit(SearchQueryUtils.buildSearchQueryJSON(textInputValue));
184184
}}
185185
routerListRef={listRef}
186186
shouldShowOfflineMessage

src/components/Search/SearchRouter/SearchRouterList.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import Navigation from '@libs/Navigation/Navigation';
1616
import Performance from '@libs/Performance';
1717
import {getAllTaxRates} from '@libs/PolicyUtils';
1818
import type {OptionData} from '@libs/ReportUtils';
19-
import * as SearchUtils from '@libs/SearchUtils';
19+
import * as SearchQueryUtils from '@libs/SearchQueryUtils';
2020
import * as Report from '@userActions/Report';
2121
import Timing from '@userActions/Timing';
2222
import CONST from '@src/CONST';
@@ -55,6 +55,10 @@ const setPerformanceTimersEnd = () => {
5555
Performance.markEnd(CONST.TIMING.SEARCH_ROUTER_RENDER);
5656
};
5757

58+
function getContextualSearchQuery(reportID: string) {
59+
return `${CONST.SEARCH.SYNTAX_ROOT_KEYS.TYPE}:${CONST.SEARCH.DATA_TYPES.CHAT} in:${reportID}`;
60+
}
61+
5862
function isSearchQueryItem(item: OptionData | SearchQueryItem): item is SearchQueryItem {
5963
if ('singleIcon' in item && item.singleIcon && 'query' in item && item.query) {
6064
return true;
@@ -120,7 +124,7 @@ function SearchRouterList(
120124
{
121125
text: `${translate('search.searchIn')} ${reportForContextualSearch.text ?? reportForContextualSearch.alternateText}`,
122126
singleIcon: Expensicons.MagnifyingGlass,
123-
query: SearchUtils.getContextualSuggestionQuery(reportForContextualSearch.reportID),
127+
query: getContextualSearchQuery(reportForContextualSearch.reportID),
124128
itemStyle: styles.activeComponentBG,
125129
keyForList: 'contextualSearch',
126130
isContextualSearchItem: true,
@@ -130,9 +134,9 @@ function SearchRouterList(
130134
}
131135

132136
const recentSearchesData = recentSearches?.map(({query, timestamp}) => {
133-
const searchQueryJSON = SearchUtils.buildSearchQueryJSON(query);
137+
const searchQueryJSON = SearchQueryUtils.buildSearchQueryJSON(query);
134138
return {
135-
text: searchQueryJSON ? SearchUtils.getSearchHeaderTitle(searchQueryJSON, personalDetails, cardList, reports, taxRates) : query,
139+
text: searchQueryJSON ? SearchQueryUtils.buildUserReadableQueryString(searchQueryJSON, personalDetails, cardList, reports, taxRates) : query,
136140
singleIcon: Expensicons.History,
137141
query,
138142
keyForList: timestamp,
@@ -159,7 +163,7 @@ function SearchRouterList(
159163
if (!item?.query) {
160164
return;
161165
}
162-
onSearchSubmit(SearchUtils.buildSearchQueryJSON(item?.query));
166+
onSearchSubmit(SearchQueryUtils.buildSearchQueryJSON(item?.query));
163167
}
164168

165169
// Handle selection of "Recent chat"

src/components/Search/SearchStatusBar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import useStyleUtils from '@hooks/useStyleUtils';
1111
import useTheme from '@hooks/useTheme';
1212
import useThemeStyles from '@hooks/useThemeStyles';
1313
import Navigation from '@libs/Navigation/Navigation';
14-
import * as SearchUtils from '@libs/SearchUtils';
14+
import * as SearchQueryUtils from '@libs/SearchQueryUtils';
1515
import CONST from '@src/CONST';
1616
import type {TranslationPaths} from '@src/languages/types';
1717
import type {SearchDataTypes} from '@src/types/onyx/SearchResults';
@@ -177,7 +177,7 @@ function SearchStatusBar({queryJSON, onStatusChange}: SearchStatusBarProps) {
177177
{options.map((item, index) => {
178178
const onPress = singleExecution(() => {
179179
onStatusChange?.();
180-
const query = SearchUtils.buildSearchQueryString({...queryJSON, status: item.status});
180+
const query = SearchQueryUtils.buildSearchQueryString({...queryJSON, status: item.status});
181181
Navigation.setParams({q: query});
182182
});
183183
const isActive = queryJSON.status === item.status;

src/components/Search/index.tsx

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import Log from '@libs/Log';
2323
import memoize from '@libs/memoize';
2424
import isSearchTopmostCentralPane from '@libs/Navigation/isSearchTopmostCentralPane';
2525
import * as ReportUtils from '@libs/ReportUtils';
26-
import * as SearchUtils from '@libs/SearchUtils';
26+
import * as SearchQueryUtils from '@libs/SearchQueryUtils';
27+
import * as SearchUIUtils from '@libs/SearchUIUtils';
2728
import Navigation from '@navigation/Navigation';
2829
import type {AuthScreensParamList} from '@navigation/types';
2930
import EmptySearchView from '@pages/Search/EmptySearchView';
@@ -61,11 +62,11 @@ function mapToItemWithSelectionInfo(
6162
canSelectMultiple: boolean,
6263
shouldAnimateInHighlight: boolean,
6364
) {
64-
if (SearchUtils.isReportActionListItemType(item)) {
65+
if (SearchUIUtils.isReportActionListItemType(item)) {
6566
return item;
6667
}
6768

68-
return SearchUtils.isTransactionListItemType(item)
69+
return SearchUIUtils.isTransactionListItemType(item)
6970
? mapToTransactionItemWithSelectionInfo(item, selectedTransactions, canSelectMultiple, shouldAnimateInHighlight)
7071
: {
7172
...item,
@@ -143,7 +144,7 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr
143144

144145
const getItemHeight = useCallback(
145146
(item: TransactionListItemType | ReportListItemType | ReportActionListItemType) => {
146-
if (SearchUtils.isTransactionListItemType(item) || SearchUtils.isReportActionListItemType(item)) {
147+
if (SearchUIUtils.isTransactionListItemType(item) || SearchUIUtils.isReportActionListItemType(item)) {
147148
return isLargeScreenWidth ? variables.optionRowHeight + listItemPadding : transactionItemMobileHeight + listItemPadding;
148149
}
149150

@@ -190,9 +191,9 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr
190191
const isDataLoaded = searchResults?.data !== undefined && searchResults?.search?.type === type && searchResults?.search?.status === status;
191192
const shouldShowLoadingState = !isOffline && !isDataLoaded;
192193
const shouldShowLoadingMoreItems = !shouldShowLoadingState && searchResults?.search?.isLoading && searchResults?.search?.offset > 0;
193-
const isSearchResultsEmpty = !searchResults?.data || SearchUtils.isSearchResultsEmpty(searchResults);
194+
const isSearchResultsEmpty = !searchResults?.data || SearchUIUtils.isSearchResultsEmpty(searchResults);
194195
const prevIsSearchResultEmpty = usePrevious(isSearchResultsEmpty);
195-
const data = searchResults === undefined ? [] : SearchUtils.getSections(type, status, searchResults.data, searchResults.search);
196+
const data = searchResults === undefined ? [] : SearchUIUtils.getSections(type, status, searchResults.data, searchResults.search);
196197

197198
useEffect(() => {
198199
/** We only want to display the skeleton for the status filters the first time we load them for a specific data type */
@@ -275,8 +276,8 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr
275276
return <FullPageOfflineBlockingView>{null}</FullPageOfflineBlockingView>;
276277
}
277278

278-
const ListItem = SearchUtils.getListItem(type, status);
279-
const sortedData = SearchUtils.getSortedSections(type, status, data, sortBy, sortOrder);
279+
const ListItem = SearchUIUtils.getListItem(type, status);
280+
const sortedData = SearchUIUtils.getSortedSections(type, status, data, sortBy, sortOrder);
280281
const sortedSelectedData = sortedData.map((item) => {
281282
const baseKey = `${ONYXKEYS.COLLECTION.TRANSACTION}${(item as TransactionListItemType).transactionID}`;
282283
// Check if the base key matches the newSearchResultKey (TransactionListItemType)
@@ -303,10 +304,10 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr
303304
}
304305

305306
const toggleTransaction = (item: TransactionListItemType | ReportListItemType | ReportActionListItemType) => {
306-
if (SearchUtils.isReportActionListItemType(item)) {
307+
if (SearchUIUtils.isReportActionListItemType(item)) {
307308
return;
308309
}
309-
if (SearchUtils.isTransactionListItemType(item)) {
310+
if (SearchUIUtils.isTransactionListItemType(item)) {
310311
if (!item.keyForList) {
311312
return;
312313
}
@@ -337,21 +338,21 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr
337338

338339
const openReport = (item: TransactionListItemType | ReportListItemType | ReportActionListItemType) => {
339340
const isFromSelfDM = item.reportID === CONST.REPORT.UNREPORTED_REPORTID;
340-
let reportID = SearchUtils.isTransactionListItemType(item) && (!item.isFromOneTransactionReport || isFromSelfDM) ? item.transactionThreadReportID : item.reportID;
341+
let reportID = SearchUIUtils.isTransactionListItemType(item) && (!item.isFromOneTransactionReport || isFromSelfDM) ? item.transactionThreadReportID : item.reportID;
341342

342343
if (!reportID) {
343344
return;
344345
}
345346

346347
// If we're trying to open a legacy transaction without a transaction thread, let's create the thread and navigate the user
347-
if (SearchUtils.isTransactionListItemType(item) && reportID === '0' && item.moneyRequestReportActionID) {
348+
if (SearchUIUtils.isTransactionListItemType(item) && reportID === '0' && item.moneyRequestReportActionID) {
348349
reportID = ReportUtils.generateReportID();
349350
SearchActions.createTransactionThread(hash, item.transactionID, reportID, item.moneyRequestReportActionID);
350351
}
351352

352353
const backTo = Navigation.getActiveRoute();
353354

354-
if (SearchUtils.isReportActionListItemType(item)) {
355+
if (SearchUIUtils.isReportActionListItemType(item)) {
355356
const reportActionID = item.reportActionID;
356357
Navigation.navigate(ROUTES.SEARCH_REPORT.getRoute({reportID, reportActionID, backTo}));
357358
return;
@@ -387,11 +388,11 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr
387388
};
388389

389390
const onSortPress = (column: SearchColumnType, order: SortOrder) => {
390-
const newQuery = SearchUtils.buildSearchQueryString({...queryJSON, sortBy: column, sortOrder: order});
391+
const newQuery = SearchQueryUtils.buildSearchQueryString({...queryJSON, sortBy: column, sortOrder: order});
391392
navigation.setParams({q: newQuery});
392393
};
393394

394-
const shouldShowYear = SearchUtils.shouldShowYear(searchResults?.data);
395+
const shouldShowYear = SearchUIUtils.shouldShowYear(searchResults?.data);
395396
const shouldShowSorting = sortableSearchStatuses.includes(status);
396397

397398
return (
@@ -416,7 +417,7 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr
416417
)
417418
}
418419
isSelected={(item) =>
419-
status !== CONST.SEARCH.STATUS.EXPENSE.ALL && SearchUtils.isReportListItemType(item)
420+
status !== CONST.SEARCH.STATUS.EXPENSE.ALL && SearchUIUtils.isReportListItemType(item)
420421
? item.transactions.some((transaction) => selectedTransactions[transaction.keyForList]?.isSelected)
421422
: !!item.isSelected
422423
}

src/components/SelectionList/BaseSelectionList.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import useSingleExecution from '@hooks/useSingleExecution';
2424
import useThemeStyles from '@hooks/useThemeStyles';
2525
import getSectionsWithIndexOffset from '@libs/getSectionsWithIndexOffset';
2626
import Log from '@libs/Log';
27-
import * as SearchUtils from '@libs/SearchUtils';
27+
import * as SearchUIUtils from '@libs/SearchUIUtils';
2828
import variables from '@styles/variables';
2929
import CONST from '@src/CONST';
3030
import {isEmptyObject} from '@src/types/utils/EmptyObject';
@@ -438,7 +438,7 @@ function BaseSelectionList<TItem extends ListItem>(
438438
const showTooltip = shouldShowTooltips && normalizedIndex < 10;
439439

440440
const handleOnCheckboxPress = () => {
441-
if (SearchUtils.isReportListItemType(item)) {
441+
if (SearchUIUtils.isReportListItemType(item)) {
442442
return onCheckboxPress;
443443
}
444444
return onCheckboxPress ? () => onCheckboxPress(item) : undefined;

src/components/SelectionList/Search/ExpenseItemHeaderNarrow.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {PressableWithFeedback} from '@components/Pressable';
77
import useStyleUtils from '@hooks/useStyleUtils';
88
import useTheme from '@hooks/useTheme';
99
import useThemeStyles from '@hooks/useThemeStyles';
10-
import * as SearchUtils from '@libs/SearchUtils';
10+
import * as SearchUIUtils from '@libs/SearchUIUtils';
1111
import variables from '@styles/variables';
1212
import CONST from '@src/CONST';
1313
import type {SearchPersonalDetails, SearchTransactionAction} from '@src/types/onyx/SearchResults';
@@ -50,7 +50,7 @@ function ExpenseItemHeaderNarrow({
5050
const theme = useTheme();
5151

5252
// It might happen that we are missing display names for `From` or `To`, we only display arrow icon if both names exist
53-
const shouldDisplayArrowIcon = SearchUtils.isCorrectSearchUserName(participantFromDisplayName) && SearchUtils.isCorrectSearchUserName(participantToDisplayName);
53+
const shouldDisplayArrowIcon = SearchUIUtils.isCorrectSearchUserName(participantFromDisplayName) && SearchUIUtils.isCorrectSearchUserName(participantToDisplayName);
5454

5555
return (
5656
<View style={[styles.flex1, styles.flexRow, styles.alignItemsCenter, styles.justifyContentBetween, styles.mb3, styles.gap2, containerStyle]}>

src/components/SelectionList/Search/ReportListItem.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ function ReportListItem<TItem extends ListItem>({
110110
const participantFrom = reportItem.from;
111111
const participantTo = reportItem.to;
112112

113-
// These values should come as part of the item via SearchUtils.getSections() but ReportListItem is not yet 100% handled
113+
// These values should come as part of the item via SearchUIUtils.getSections() but ReportListItem is not yet 100% handled
114114
// This will be simplified in future once sorting of ReportListItem is done
115115
const participantFromDisplayName = participantFrom?.displayName ?? participantFrom?.login ?? '';
116116
const participantToDisplayName = participantTo?.displayName ?? participantTo?.login ?? '';

src/components/SelectionList/Search/UserInfoCell.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Avatar from '@components/Avatar';
44
import Text from '@components/Text';
55
import useResponsiveLayout from '@hooks/useResponsiveLayout';
66
import useThemeStyles from '@hooks/useThemeStyles';
7-
import * as SearchUtils from '@libs/SearchUtils';
7+
import * as SearchUIUtils from '@libs/SearchUIUtils';
88
import CONST from '@src/CONST';
99
import type {SearchPersonalDetails} from '@src/types/onyx/SearchResults';
1010

@@ -18,7 +18,7 @@ function UserInfoCell({participant, displayName}: UserInfoCellProps) {
1818
const {isLargeScreenWidth} = useResponsiveLayout();
1919
const avatarURL = participant?.avatar;
2020

21-
if (!SearchUtils.isCorrectSearchUserName(displayName)) {
21+
if (!SearchUIUtils.isCorrectSearchUserName(displayName)) {
2222
return null;
2323
}
2424

0 commit comments

Comments
 (0)