diff --git a/src/components/Search/SearchContext.tsx b/src/components/Search/SearchContext.tsx index f571b9370e687..8d0bf92772402 100644 --- a/src/components/Search/SearchContext.tsx +++ b/src/components/Search/SearchContext.tsx @@ -32,6 +32,7 @@ const defaultSearchInfo: SearchResultsInfo = { const defaultSearchContextData: SearchContextData = { currentSearchHash: -1, + currentRecentSearchHash: -1, currentSearchKey: undefined, currentSearchQueryJSON: undefined, currentSearchResults: undefined, @@ -81,10 +82,10 @@ function SearchContextProvider({children}: ChildrenProps) { const todoSearchResultsData = useTodos(); const currentSearchKey = searchContextData.currentSearchKey; - const currentSearchHash = searchContextData.currentSearchHash; + const currentRecentSearchHash = searchContextData.currentRecentSearchHash; const {accountID} = useCurrentUserPersonalDetails(); const suggestedSearches = useMemo(() => getSuggestedSearches(accountID), [accountID]); - const shouldUseLiveData = !!currentSearchKey && isTodoSearch(currentSearchHash, suggestedSearches); + const shouldUseLiveData = !!currentSearchKey && isTodoSearch(currentRecentSearchHash, suggestedSearches); // If viewing a to-do search, use live data from useTodos, otherwise return the snapshot data // 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) { return snapshotSearchResults ?? undefined; }, [shouldUseLiveData, currentSearchKey, todoSearchResultsData, snapshotSearchResults]); - const setCurrentSearchHashAndKey = useCallback((searchHash: number, searchKey: SearchKey | undefined) => { + const setCurrentSearchHashAndKey = useCallback((searchHash: number, recentHash: number, searchKey: SearchKey | undefined) => { setSearchContextData((prevState) => { - if (searchHash === prevState.currentSearchHash && searchKey === prevState.currentSearchKey) { + if (searchHash === prevState.currentSearchHash && recentHash === prevState.currentRecentSearchHash && searchKey === prevState.currentSearchKey) { return prevState; } return { ...prevState, currentSearchHash: searchHash, + currentRecentSearchHash: recentHash, currentSearchKey: searchKey, }; }); diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 876c8b137cc6a..d94a694ef89f9 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -213,7 +213,7 @@ function Search({ searchRequestResponseStatusCode, onDEWModalOpen, }: SearchProps) { - const {type, status, sortBy, sortOrder, hash, similarSearchHash, groupBy, view} = queryJSON; + const {type, status, sortBy, sortOrder, hash, recentSearchHash, similarSearchHash, groupBy, view} = queryJSON; const {isOffline} = useNetwork(); const prevIsOffline = usePrevious(isOffline); @@ -276,7 +276,7 @@ function Search({ const {defaultCardFeed} = useCardFeedsForDisplay(); const suggestedSearches = useMemo(() => getSuggestedSearches(accountID, defaultCardFeed?.id), [defaultCardFeed?.id, accountID]); - const searchKey = useMemo(() => Object.values(suggestedSearches).find((search) => search.similarSearchHash === similarSearchHash)?.key, [suggestedSearches, similarSearchHash]); + const searchKey = useMemo(() => Object.values(suggestedSearches).find((search) => search.recentSearchHash === recentSearchHash)?.key, [suggestedSearches, recentSearchHash]); const searchDataType = useMemo(() => (shouldUseLiveData ? CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT : searchResults?.search?.type), [shouldUseLiveData, searchResults?.search?.type]); const shouldCalculateTotals = useSearchShouldCalculateTotals(searchKey, hash, offset === 0); @@ -307,9 +307,9 @@ function Search({ const clearTransactionsAndSetHashAndKey = useCallback(() => { clearSelectedTransactions(hash); - setCurrentSearchHashAndKey(hash, searchKey); + setCurrentSearchHashAndKey(hash, recentSearchHash, searchKey); setCurrentSearchQueryJSON(queryJSON); - }, [hash, searchKey, clearSelectedTransactions, setCurrentSearchHashAndKey, setCurrentSearchQueryJSON, queryJSON]); + }, [hash, recentSearchHash, searchKey, clearSelectedTransactions, setCurrentSearchHashAndKey, setCurrentSearchQueryJSON, queryJSON]); useFocusEffect(clearTransactionsAndSetHashAndKey); diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index e671df62f8d50..011a6d7942601 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -153,6 +153,7 @@ type SearchCustomColumnIds = type SearchContextData = { currentSearchHash: number; + currentRecentSearchHash: number; currentSearchKey: SearchKey | undefined; currentSearchQueryJSON: SearchQueryJSON | undefined; currentSearchResults: SearchResults | undefined; @@ -168,7 +169,7 @@ type SearchContextProps = SearchContextData & { currentSearchResults: SearchResults | undefined; /** Whether we're on a main to-do search and should use live Onyx data instead of snapshots */ shouldUseLiveData: boolean; - setCurrentSearchHashAndKey: (hash: number, key: SearchKey | undefined) => void; + setCurrentSearchHashAndKey: (hash: number, recentHash: number, key: SearchKey | undefined) => void; setCurrentSearchQueryJSON: (searchQueryJSON: SearchQueryJSON | undefined) => void; /** If you want to set `selectedTransactionIDs`, pass an array as the first argument, object/record otherwise */ setSelectedTransactions: { diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts index 6733d90689bad..b766f9a013d2f 100644 --- a/src/libs/SearchUIUtils.ts +++ b/src/libs/SearchUIUtils.ts @@ -445,6 +445,7 @@ type SearchTypeMenuItem = { searchQueryJSON: SearchQueryJSON | undefined; hash: number; similarSearchHash: number; + recentSearchHash: number; badgeText?: string; emptyState?: { title: TranslationPaths; @@ -528,6 +529,9 @@ function createTopSearchMenuItem( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }; } @@ -566,6 +570,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, [CONST.SEARCH.SEARCH_KEYS.REPORTS]: { key: CONST.SEARCH.SEARCH_KEYS.REPORTS, @@ -582,6 +589,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, [CONST.SEARCH.SEARCH_KEYS.CHATS]: { key: CONST.SEARCH.SEARCH_KEYS.CHATS, @@ -598,6 +608,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, [CONST.SEARCH.SEARCH_KEYS.SUBMIT]: { key: CONST.SEARCH.SEARCH_KEYS.SUBMIT, @@ -618,6 +631,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, [CONST.SEARCH.SEARCH_KEYS.APPROVE]: { key: CONST.SEARCH.SEARCH_KEYS.APPROVE, @@ -638,6 +654,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, [CONST.SEARCH.SEARCH_KEYS.PAY]: { key: CONST.SEARCH.SEARCH_KEYS.PAY, @@ -659,6 +678,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, [CONST.SEARCH.SEARCH_KEYS.EXPORT]: { key: CONST.SEARCH.SEARCH_KEYS.EXPORT, @@ -680,6 +702,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, [CONST.SEARCH.SEARCH_KEYS.STATEMENTS]: { key: CONST.SEARCH.SEARCH_KEYS.STATEMENTS, @@ -701,6 +726,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, [CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CASH]: { key: CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CASH, @@ -722,6 +750,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, [CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CARD]: { key: CONST.SEARCH.SEARCH_KEYS.UNAPPROVED_CARD, @@ -743,6 +774,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, [CONST.SEARCH.SEARCH_KEYS.RECONCILIATION]: { key: CONST.SEARCH.SEARCH_KEYS.RECONCILIATION, @@ -764,6 +798,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, [CONST.SEARCH.SEARCH_KEYS.TOP_SPENDERS]: { key: CONST.SEARCH.SEARCH_KEYS.TOP_SPENDERS, @@ -797,6 +834,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, [CONST.SEARCH.SEARCH_KEYS.TOP_CATEGORIES]: createTopSearchMenuItem( CONST.SEARCH.SEARCH_KEYS.TOP_CATEGORIES, @@ -839,6 +879,9 @@ function getSuggestedSearches( get similarSearchHash() { return this.searchQueryJSON?.similarSearchHash ?? CONST.DEFAULT_NUMBER_ID; }, + get recentSearchHash() { + return this.searchQueryJSON?.recentSearchHash ?? CONST.DEFAULT_NUMBER_ID; + }, }, }; } @@ -3411,9 +3454,9 @@ function isCorrectSearchUserName(displayName?: string) { return displayName && displayName.toUpperCase() !== CONST.REPORT.OWNER_EMAIL_FAKE; } -function isTodoSearch(hash: number, suggestedSearches: Record) { +function isTodoSearch(recentSearchHash: number, suggestedSearches: Record) { const TODO_KEYS: SearchKey[] = [CONST.SEARCH.SEARCH_KEYS.SUBMIT, CONST.SEARCH.SEARCH_KEYS.APPROVE, CONST.SEARCH.SEARCH_KEYS.PAY, CONST.SEARCH.SEARCH_KEYS.EXPORT]; - const matchedSearchKey = Object.values(suggestedSearches).find((search) => search.hash === hash)?.key; + const matchedSearchKey = Object.values(suggestedSearches).find((search) => search.recentSearchHash === recentSearchHash)?.key; return !!matchedSearchKey && TODO_KEYS.includes(matchedSearchKey); } diff --git a/tests/ui/CategoryListItemHeaderTest.tsx b/tests/ui/CategoryListItemHeaderTest.tsx index 1657eb6aa23d0..6832cd8113c66 100644 --- a/tests/ui/CategoryListItemHeaderTest.tsx +++ b/tests/ui/CategoryListItemHeaderTest.tsx @@ -23,6 +23,7 @@ const mockedUseResponsiveLayout = useResponsiveLayout as jest.MockedFunction