DRAFT: [CDX-310]: added recent searches to autocomplete dropdown#267
DRAFT: [CDX-310]: added recent searches to autocomplete dropdown#267
Conversation
Code Review Results✅ StrengthsThe feature is well-structured following established patterns in the codebase — new type guards, a dedicated hook, and proper integration into the section pipeline are clean and consistent. 🚨 Critical Issues
|
There was a problem hiding this comment.
Pull request overview
Adds a new recentSearches section type to the autocomplete system so that previously-submitted queries can be displayed in the dropdown (including section rendering + styling), and wires selection of a recent search to submit tracking.
Changes:
- Introduces
recentSearchesas a first-class section type (types, guards, section result aggregation, rendering behavior). - Adds a new hook (
useGetRecentSearches) to pull recent searches from storage and format them as dropdown items. - Adds styling and selection handling so recent-search items render appropriately and trigger
trackSearchSubmiton click.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/tracking.ts | Types term for trackSearchSubmit; continues persisting recent searches on submit. |
| src/utils/helpers.ts | Allows getActiveSectionsWithData to source data for recentSearches sections by displayName. |
| src/utils/beaconUtils.ts | Adds typings for recent-search helpers (getRecentSearches, storeRecentSearch). |
| src/types.ts | Extends section/type model to include recentSearches and defines RecentSearches shape. |
| src/typeGuards.ts | Adds isRecentSearchesSection guard. |
| src/styles.css | Adds styling for recent-searches section items; minor formatting cleanup. |
| src/hooks/useSections/useSectionsResults.ts | Fetches recent-searches “results” via the new hook and returns them alongside other section results. |
| src/hooks/useSections/index.ts | Merges recent-searches results into the combined sectionsResults. |
| src/hooks/useGetRecentSearches.ts | New hook: reads recent searches from storage and maps to dropdown item shape. |
| src/hooks/useDownShift.ts | Handles selection of recent-search items by setting query + firing trackSearchSubmit. |
| src/hooks/useCioAutocomplete.ts | Ensures section titles / section class naming logic supports recentSearches. |
| src/components/Autocomplete/SectionItemsList/SectionItemsList.tsx | Adds recentSearches handling for section titles. |
| src/components/Autocomplete/AutocompleteResults/AutocompleteResults.tsx | Uses a stable-ish key for recentSearches sections. |
| .gitignore | Ignores .idea directory. |
Comments suppressed due to low confidence (1)
src/utils/beaconUtils.ts:56
getRecentSearchesnow claims to returnRecentSearches[], but the legacy-upgrade path converts string entries into{ term, ts }objects without adatafield. This makes the stored shape inconsistent with the newRecentSearchestype and can lead todatabeing unexpectedly missing at runtime. Consider normalizing upgraded items to includedata: {}(and optionally persisting the upgraded array back to storage so timestamps/ids are stable across calls).
export const getRecentSearches = (): RecentSearches[] => {
const recentSearches = storageGetArray(CONSTANTS.RECENT_SEARCHES_STORAGE_KEY) || [];
// upgrade the array to store timestamps if it isn't already
recentSearches.forEach((item, i) => {
if (typeof item === 'string') {
recentSearches[i] = {
term: item,
ts: Date.now(),
};
}
});
return recentSearches;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * Stores a recent search | ||
| */ | ||
| export const storeRecentSearch = (term, suggestionData) => { | ||
| export const storeRecentSearch = (term: string, suggestionData) => { |
| useEffect(() => { | ||
| if (!recentSearchesSection.length) return; | ||
|
|
||
| const recentSearchesFromStore = getRecentSearches(); | ||
| const recentSearchesResults = {}; | ||
|
|
||
| recentSearchesSection.forEach(({ displayName, numResults }) => { | ||
| recentSearchesResults[displayName] = recentSearchesFromStore | ||
| .slice(0, numResults) | ||
| .map(({ term, ts }) => ({ | ||
| value: term, | ||
| id: ts, | ||
| is_slotted: false, | ||
| labels: {}, | ||
| matched_terms: [], | ||
| section: 'recent-searches', | ||
| })); | ||
| }); | ||
|
|
||
| setRecentSearches(recentSearchesResults); | ||
| }, [recentSearchesSection]); | ||
|
|
| const recentSearchesResults = {}; | ||
|
|
||
| recentSearchesSection.forEach(({ displayName, numResults }) => { | ||
| recentSearchesResults[displayName] = recentSearchesFromStore | ||
| .slice(0, numResults) |
| import { useEffect, useState } from 'react'; | ||
| import { RecentSearchesSectionConfiguration, SectionsData } from '../types'; | ||
| import { getRecentSearches } from '../utils/beaconUtils'; | ||
|
|
||
| const useGetRecentSearches = (recentSearchesSection: RecentSearchesSectionConfiguration[]) => { | ||
| const [recentSearches, setRecentSearches] = useState<SectionsData>({}); | ||
|
|
||
| useEffect(() => { | ||
| if (!recentSearchesSection.length) return; | ||
|
|
||
| const recentSearchesFromStore = getRecentSearches(); | ||
| const recentSearchesResults = {}; | ||
|
|
||
| recentSearchesSection.forEach(({ displayName, numResults }) => { | ||
| recentSearchesResults[displayName] = recentSearchesFromStore | ||
| .slice(0, numResults) | ||
| .map(({ term, ts }) => ({ | ||
| value: term, | ||
| id: ts, | ||
| is_slotted: false, | ||
| labels: {}, | ||
| matched_terms: [], | ||
| section: 'recent-searches', | ||
| })); | ||
| }); | ||
|
|
||
| setRecentSearches(recentSearchesResults); | ||
| }, [recentSearchesSection]); | ||
|
|
||
| return recentSearches; | ||
| }; | ||
|
|
||
| export default useGetRecentSearches; |
| export type RecentSearches = { | ||
| term: string; | ||
| ts: number; | ||
| data: Record<string, unknown>; |
No description provided.