Skip to content

Commit 5c3092c

Browse files
authored
Merge pull request Expensify#83074 from Expensify/claude-fixTodoSortEmptyResults
Fix To-do search results disappearing when sort is clicked
2 parents 4eb171c + e4097bb commit 5c3092c

11 files changed

Lines changed: 68 additions & 11 deletions

src/components/Search/SearchContext.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const defaultSearchInfo: SearchResultsInfo = {
3232

3333
const defaultSearchContextData: SearchContextData = {
3434
currentSearchHash: -1,
35+
currentRecentSearchHash: -1,
3536
currentSearchKey: undefined,
3637
currentSearchQueryJSON: undefined,
3738
currentSearchResults: undefined,
@@ -81,10 +82,10 @@ function SearchContextProvider({children}: ChildrenProps) {
8182
const todoSearchResultsData = useTodos();
8283

8384
const currentSearchKey = searchContextData.currentSearchKey;
84-
const currentSearchHash = searchContextData.currentSearchHash;
85+
const currentRecentSearchHash = searchContextData.currentRecentSearchHash;
8586
const {accountID} = useCurrentUserPersonalDetails();
8687
const suggestedSearches = useMemo(() => getSuggestedSearches(accountID), [accountID]);
87-
const shouldUseLiveData = !!currentSearchKey && isTodoSearch(currentSearchHash, suggestedSearches);
88+
const shouldUseLiveData = !!currentSearchKey && isTodoSearch(currentRecentSearchHash, suggestedSearches);
8889

8990
// If viewing a to-do search, use live data from useTodos, otherwise return the snapshot data
9091
// We do this so that we can show the counters for the to-do search results without visiting the specific to-do page, e.g. show `Approve [3]` while viewing the `Submit` to-do search.
@@ -109,15 +110,16 @@ function SearchContextProvider({children}: ChildrenProps) {
109110
return snapshotSearchResults ?? undefined;
110111
}, [shouldUseLiveData, currentSearchKey, todoSearchResultsData, snapshotSearchResults]);
111112

112-
const setCurrentSearchHashAndKey = useCallback((searchHash: number, searchKey: SearchKey | undefined) => {
113+
const setCurrentSearchHashAndKey = useCallback((searchHash: number, recentHash: number, searchKey: SearchKey | undefined) => {
113114
setSearchContextData((prevState) => {
114-
if (searchHash === prevState.currentSearchHash && searchKey === prevState.currentSearchKey) {
115+
if (searchHash === prevState.currentSearchHash && recentHash === prevState.currentRecentSearchHash && searchKey === prevState.currentSearchKey) {
115116
return prevState;
116117
}
117118

118119
return {
119120
...prevState,
120121
currentSearchHash: searchHash,
122+
currentRecentSearchHash: recentHash,
121123
currentSearchKey: searchKey,
122124
};
123125
});

src/components/Search/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ function Search({
212212
searchRequestResponseStatusCode,
213213
onDEWModalOpen,
214214
}: SearchProps) {
215-
const {type, status, sortBy, sortOrder, hash, similarSearchHash, groupBy, view} = queryJSON;
215+
const {type, status, sortBy, sortOrder, hash, recentSearchHash, similarSearchHash, groupBy, view} = queryJSON;
216216

217217
const {isOffline} = useNetwork();
218218
const prevIsOffline = usePrevious(isOffline);
@@ -276,7 +276,7 @@ function Search({
276276

277277
const {defaultCardFeed} = useCardFeedsForDisplay();
278278
const suggestedSearches = useMemo(() => getSuggestedSearches(accountID, defaultCardFeed?.id), [defaultCardFeed?.id, accountID]);
279-
const searchKey = useMemo(() => Object.values(suggestedSearches).find((search) => search.similarSearchHash === similarSearchHash)?.key, [suggestedSearches, similarSearchHash]);
279+
const searchKey = useMemo(() => Object.values(suggestedSearches).find((search) => search.recentSearchHash === recentSearchHash)?.key, [suggestedSearches, recentSearchHash]);
280280
const searchDataType = useMemo(() => (shouldUseLiveData ? CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT : searchResults?.search?.type), [shouldUseLiveData, searchResults?.search?.type]);
281281
const shouldCalculateTotals = useSearchShouldCalculateTotals(searchKey, hash, offset === 0);
282282

@@ -307,9 +307,9 @@ function Search({
307307

308308
const clearTransactionsAndSetHashAndKey = useCallback(() => {
309309
clearSelectedTransactions(hash);
310-
setCurrentSearchHashAndKey(hash, searchKey);
310+
setCurrentSearchHashAndKey(hash, recentSearchHash, searchKey);
311311
setCurrentSearchQueryJSON(queryJSON);
312-
}, [hash, searchKey, clearSelectedTransactions, setCurrentSearchHashAndKey, setCurrentSearchQueryJSON, queryJSON]);
312+
}, [hash, recentSearchHash, searchKey, clearSelectedTransactions, setCurrentSearchHashAndKey, setCurrentSearchQueryJSON, queryJSON]);
313313

314314
useFocusEffect(clearTransactionsAndSetHashAndKey);
315315

src/components/Search/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ type SearchCustomColumnIds =
153153

154154
type SearchContextData = {
155155
currentSearchHash: number;
156+
currentRecentSearchHash: number;
156157
currentSearchKey: SearchKey | undefined;
157158
currentSearchQueryJSON: SearchQueryJSON | undefined;
158159
currentSearchResults: SearchResults | undefined;
@@ -168,7 +169,7 @@ type SearchContextProps = SearchContextData & {
168169
currentSearchResults: SearchResults | undefined;
169170
/** Whether we're on a main to-do search and should use live Onyx data instead of snapshots */
170171
shouldUseLiveData: boolean;
171-
setCurrentSearchHashAndKey: (hash: number, key: SearchKey | undefined) => void;
172+
setCurrentSearchHashAndKey: (hash: number, recentHash: number, key: SearchKey | undefined) => void;
172173
setCurrentSearchQueryJSON: (searchQueryJSON: SearchQueryJSON | undefined) => void;
173174
/** If you want to set `selectedTransactionIDs`, pass an array as the first argument, object/record otherwise */
174175
setSelectedTransactions: {

src/libs/SearchUIUtils.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ type SearchTypeMenuItem = {
444444
searchQueryJSON: SearchQueryJSON | undefined;
445445
hash: number;
446446
similarSearchHash: number;
447+
recentSearchHash: number;
447448
badgeText?: string;
448449
emptyState?: {
449450
title: TranslationPaths;
@@ -527,6 +528,9 @@ function createTopSearchMenuItem(
527528
get similarSearchHash() {
528529
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
529530
},
531+
get recentSearchHash() {
532+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
533+
},
530534
};
531535
}
532536

@@ -565,6 +569,9 @@ function getSuggestedSearches(
565569
get similarSearchHash() {
566570
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
567571
},
572+
get recentSearchHash() {
573+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
574+
},
568575
},
569576
[CONST.SEARCH.SEARCH_KEYS.REPORTS]: {
570577
key: CONST.SEARCH.SEARCH_KEYS.REPORTS,
@@ -581,6 +588,9 @@ function getSuggestedSearches(
581588
get similarSearchHash() {
582589
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
583590
},
591+
get recentSearchHash() {
592+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
593+
},
584594
},
585595
[CONST.SEARCH.SEARCH_KEYS.CHATS]: {
586596
key: CONST.SEARCH.SEARCH_KEYS.CHATS,
@@ -597,6 +607,9 @@ function getSuggestedSearches(
597607
get similarSearchHash() {
598608
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
599609
},
610+
get recentSearchHash() {
611+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
612+
},
600613
},
601614
[CONST.SEARCH.SEARCH_KEYS.SUBMIT]: {
602615
key: CONST.SEARCH.SEARCH_KEYS.SUBMIT,
@@ -617,6 +630,9 @@ function getSuggestedSearches(
617630
get similarSearchHash() {
618631
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
619632
},
633+
get recentSearchHash() {
634+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
635+
},
620636
},
621637
[CONST.SEARCH.SEARCH_KEYS.APPROVE]: {
622638
key: CONST.SEARCH.SEARCH_KEYS.APPROVE,
@@ -637,6 +653,9 @@ function getSuggestedSearches(
637653
get similarSearchHash() {
638654
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
639655
},
656+
get recentSearchHash() {
657+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
658+
},
640659
},
641660
[CONST.SEARCH.SEARCH_KEYS.PAY]: {
642661
key: CONST.SEARCH.SEARCH_KEYS.PAY,
@@ -658,6 +677,9 @@ function getSuggestedSearches(
658677
get similarSearchHash() {
659678
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
660679
},
680+
get recentSearchHash() {
681+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
682+
},
661683
},
662684
[CONST.SEARCH.SEARCH_KEYS.EXPORT]: {
663685
key: CONST.SEARCH.SEARCH_KEYS.EXPORT,
@@ -679,6 +701,9 @@ function getSuggestedSearches(
679701
get similarSearchHash() {
680702
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
681703
},
704+
get recentSearchHash() {
705+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
706+
},
682707
},
683708
[CONST.SEARCH.SEARCH_KEYS.STATEMENTS]: {
684709
key: CONST.SEARCH.SEARCH_KEYS.STATEMENTS,
@@ -700,6 +725,9 @@ function getSuggestedSearches(
700725
get similarSearchHash() {
701726
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
702727
},
728+
get recentSearchHash() {
729+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
730+
},
703731
},
704732
[CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CASH]: {
705733
key: CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CASH,
@@ -721,6 +749,9 @@ function getSuggestedSearches(
721749
get similarSearchHash() {
722750
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
723751
},
752+
get recentSearchHash() {
753+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
754+
},
724755
},
725756
[CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CARD]: {
726757
key: CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CARD,
@@ -742,6 +773,9 @@ function getSuggestedSearches(
742773
get similarSearchHash() {
743774
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
744775
},
776+
get recentSearchHash() {
777+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
778+
},
745779
},
746780
[CONST.SEARCH.SEARCH_KEYS.RECONCILIATION]: {
747781
key: CONST.SEARCH.SEARCH_KEYS.RECONCILIATION,
@@ -763,6 +797,9 @@ function getSuggestedSearches(
763797
get similarSearchHash() {
764798
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
765799
},
800+
get recentSearchHash() {
801+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
802+
},
766803
},
767804
[CONST.SEARCH.SEARCH_KEYS.TOP_SPENDERS]: {
768805
key: CONST.SEARCH.SEARCH_KEYS.TOP_SPENDERS,
@@ -796,6 +833,9 @@ function getSuggestedSearches(
796833
get similarSearchHash() {
797834
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
798835
},
836+
get recentSearchHash() {
837+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
838+
},
799839
},
800840
[CONST.SEARCH.SEARCH_KEYS.TOP_CATEGORIES]: createTopSearchMenuItem(
801841
CONST.SEARCH.SEARCH_KEYS.TOP_CATEGORIES,
@@ -838,6 +878,9 @@ function getSuggestedSearches(
838878
get similarSearchHash() {
839879
return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID;
840880
},
881+
get recentSearchHash() {
882+
return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID;
883+
},
841884
},
842885
};
843886
}
@@ -3432,9 +3475,9 @@ function isCorrectSearchUserName(displayName?: string) {
34323475
return displayName && displayName.toUpperCase() !== CONST.REPORT.OWNER_EMAIL_FAKE;
34333476
}
34343477

3435-
function isTodoSearch(hash: number, suggestedSearches: Record<string, SearchTypeMenuItem>) {
3478+
function isTodoSearch(recentSearchHash: number, suggestedSearches: Record<string, SearchTypeMenuItem>) {
34363479
const TODO_KEYS: SearchKey[] = [CONST.SEARCH.SEARCH_KEYS.SUBMIT, CONST.SEARCH.SEARCH_KEYS.APPROVE, CONST.SEARCH.SEARCH_KEYS.PAY, CONST.SEARCH.SEARCH_KEYS.EXPORT];
3437-
const matchedSearchKey = Object.values(suggestedSearches).find((search) => search.hash === hash)?.key;
3480+
const matchedSearchKey = Object.values(suggestedSearches).find((search) => search.recentSearchHash === recentSearchHash)?.key;
34383481
return !!matchedSearchKey && TODO_KEYS.includes(matchedSearchKey);
34393482
}
34403483

tests/ui/CategoryListItemHeaderTest.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction<typ
2323
// Mock search context with all required SearchContextProps fields
2424
const mockSearchContext = {
2525
currentSearchHash: 12345,
26+
currentRecentSearchHash: 12345,
2627
currentSearchKey: undefined,
2728
currentSearchQueryJSON: undefined,
2829
currentSearchResults: undefined,

tests/ui/MerchantListItemHeaderTest.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction<typ
2323
// Mock search context with all required SearchContextProps fields
2424
const mockSearchContext = {
2525
currentSearchHash: 12345,
26+
currentRecentSearchHash: 12345,
2627
currentSearchKey: undefined,
2728
currentSearchQueryJSON: undefined,
2829
currentSearchResults: undefined,

tests/ui/MonthListItemHeaderTest.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction<typ
2323
// Mock search context with all required SearchContextProps fields
2424
const mockSearchContext = {
2525
currentSearchHash: 12345,
26+
currentRecentSearchHash: 12345,
2627
currentSearchKey: undefined,
2728
currentSearchQueryJSON: undefined,
2829
currentSearchResults: undefined,

tests/ui/ReportListItemHeaderTest.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jest.mock('@components/AvatarWithDisplayName.tsx');
2121
// Mock search context
2222
const mockSearchContext = {
2323
currentSearchHash: 12345,
24+
currentRecentSearchHash: 12345,
2425
selectedReports: {},
2526
selectedTransactionIDs: [],
2627
selectedTransactions: {},

tests/ui/WeekListItemHeaderTest.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction<typ
2323
// Mock search context with all required SearchContextProps fields
2424
const mockSearchContext = {
2525
currentSearchHash: 12345,
26+
currentRecentSearchHash: 12345,
2627
currentSearchKey: undefined,
2728
currentSearchQueryJSON: undefined,
2829
currentSearchResults: undefined,

tests/ui/YearListItemHeaderTest.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction<typ
2323
// Mock search context with all required SearchContextProps fields
2424
const mockSearchContext = {
2525
currentSearchHash: 12345,
26+
currentRecentSearchHash: 12345,
2627
currentSearchKey: undefined,
2728
currentSearchQueryJSON: undefined,
2829
currentSearchResults: undefined,

0 commit comments

Comments
 (0)