Skip to content

[CDX-310]: added recent searches to autocomplete dropdown#267

Open
niizom wants to merge 6 commits into
mainfrom
cdx-310-ac-ui-feature-recently-searched-terms
Open

[CDX-310]: added recent searches to autocomplete dropdown#267
niizom wants to merge 6 commits into
mainfrom
cdx-310-ac-ui-feature-recently-searched-terms

Conversation

@niizom
Copy link
Copy Markdown

@niizom niizom commented Mar 13, 2026

No description provided.

@niizom niizom requested review from Mudaafi and esezen as code owners March 13, 2026 19:32
Copilot AI review requested due to automatic review settings March 13, 2026 19:32
@constructor-claude-bedrock

This comment was marked as outdated.

This comment was marked as outdated.

@niizom niizom changed the title [CDX-310]: added recent searches to autocomplete dropdown DRAFT: [CDX-310]: added recent searches to autocomplete dropdown Mar 16, 2026
@esezen esezen requested a review from a team March 16, 2026 15:28
constructor-claude-bedrock[bot]

This comment was marked as outdated.

@TarekAlQaddy TarekAlQaddy changed the title DRAFT: [CDX-310]: added recent searches to autocomplete dropdown [CDX-310]: added recent searches to autocomplete dropdown Apr 6, 2026
constructor-claude-bedrock[bot]

This comment was marked as outdated.

constructor-claude-bedrock[bot]

This comment was marked as outdated.

constructor-claude-bedrock[bot]

This comment was marked as outdated.

TarekAlQaddy
TarekAlQaddy previously approved these changes Apr 6, 2026
@esezen esezen requested a review from a team as a code owner April 24, 2026 18:45
constructor-claude-bedrock[bot]

This comment was marked as outdated.

Comment thread src/types.ts

export type Section = AutocompleteSection | RecommendationsSection | CustomSection;
export interface RecentSearchesSection extends RecentSearchesSectionConfiguration {
data: Item[];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be

Suggested change
data: Item[];
data: RecentSearch[];

wdyt @niizom ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Narrowing down this type will require a code refactor which might be time consuming

Copy link
Copy Markdown
Contributor

@esezen esezen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this!

Comment thread src/hooks/useCioAutocomplete.ts Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is a bug here and also affects useRemoveSections hook. When the variant custom_autosuggest_ui_disable_recommendations_in_zero_state is active, it wipes any recentSearches section a customer has configured. A customer who only uses recentSearches (no recommendations) sees nothing under that A/B variant. The same applies to the opening the menu logic here

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment thread src/types.ts
* Transforms a `SearchSuggestion` into the desired URL string to be used when rendering anchor tags
* Transforms a `SearchSuggestion` or `RecentSearch` into the desired URL string
* to be used when rendering anchor tags
* i.e. <a href=getSearchResultsUrl([selected_search_suggestion])>[Search Suggestion]</a>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we update this line as well?

Comment thread src/utils/dataAttributeHelpers.ts Outdated
isInGroupSuggestion,
isRecentSearch,
isRecommendationsSection,
isSearchSuggestion,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment thread src/types.ts

export type Section = AutocompleteSection | RecommendationsSection | CustomSection;
export interface RecentSearchesSection extends RecentSearchesSectionConfiguration {
data: Item[];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
data: Item[];
data: RecentSearch[];

Comment thread src/types.ts
Comment on lines +308 to +313
export type RecentSearch = Partial<ItemBase> &
Pick<ItemBase, 'value' | 'id'> & {
section: 'recent-searches';
ts: number;
data?: Record<string, unknown>;
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can simplify and make this tighter. Wdyt?

Suggested change
export type RecentSearch = Partial<ItemBase> &
Pick<ItemBase, 'value' | 'id'> & {
section: 'recent-searches';
ts: number;
data?: Record<string, unknown>;
};
export type RecentSearch = {
section: 'recent-searches';
value: string;
id: string;
ts: number;
data?: Record<string, unknown>;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I might be missing something by why do we use recentSearches in certain places and recent-searches in others?

recentSearchesResults[displayName] = recentSearchesFromStore
.slice()
.reverse()
.slice(0, numResults || DEFAULT_NUM_RESULTS)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we document the default that we use here in docs and / or in types?

.map(({ term, ts, data }) => ({
ts,
data,
id: `${term}-${ts}`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we add ts here?

constructor-claude-bedrock[bot]

This comment was marked as outdated.

@niizom niizom force-pushed the cdx-310-ac-ui-feature-recently-searched-terms branch from 7ea7df2 to f4bbcdd Compare June 1, 2026 15:30
constructor-claude-bedrock[bot]

This comment was marked as outdated.

@niizom niizom force-pushed the cdx-310-ac-ui-feature-recently-searched-terms branch from f4bbcdd to 8e4944c Compare June 1, 2026 21:01
Copy link
Copy Markdown

@constructor-claude-bedrock constructor-claude-bedrock Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This PR adds a recentSearches section type to the autocomplete dropdown zero state, reading from localStorage and integrating with tracking — the implementation is well-structured overall but has a dead-code bug and several type-safety/mutation concerns worth addressing before merge.

Inline comments: 7 discussions added

Overall Assessment: ⚠️ Needs Work

Comment thread src/hooks/useDownShift.ts
trackAutocompleteSelect(cioClient, selectedItem.value, selectData);

// Track recent searches as Search Suggestions
} else if (selectedItem.section === 'recent-searches') {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical Issue: This else if branch is dead code and will never execute. The outer if at line 41–44 already checks selectedItem?.section === 'recent-searches' and runs trackSearchSubmit + setQuery when true, so control never falls through to this branch. This means trackAutocompleteSelect is never called for recent searches, silently dropping the select-tracking event.

Fix: Move the trackAutocompleteSelect call for recent-searches inside the first if block (alongside trackSearchSubmit), or restructure so both calls execute:

if (
  selectedItem?.section === 'Search Suggestions' ||
  selectedItem?.section === 'recent-searches'
) {
  setQuery(selectedItem.value || '');
  trackSearchSubmit(cioClient, selectedItem.value, { originalQuery: previousQuery });
  if (selectedItem.section === 'recent-searches') {
    trackAutocompleteSelect(cioClient, selectedItem.value, {
      originalQuery: previousQuery,
      section: 'Search Suggestions',
    });
  }
}

});

setRecentSearches(recentSearchesResults);
}, [recentSearchesSections]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important Issue: recentSearchesSections is an array created fresh on every render in useSectionsResults (activeSections.filter(...)), so this dependency will always be a new reference, causing the effect to re-run on every render even when the section config hasn't changed. This creates a performance issue and unnecessary state updates that can cascade into re-renders.

Fix: Memoize activeRecentSearchesSections in useSectionsResults (already done — good), but make sure the upstream activeSections array itself is stable. Alternatively, stabilize the dependency with a deep comparison (e.g., useDeepCompareMemo) or serialize the relevant fields as a primitive dependency:

}, [JSON.stringify(recentSearchesSections)]);

openOnFocus !== false &&
features.featureDisplayZeroStateRecommendations
) {
if (zeroStateActiveSections && openOnFocus !== false && activeSections.length > 0) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important Issue: The previous condition features.featureDisplayZeroStateRecommendations was a deliberate feature flag guard — removing it means the zero state now always opens on focus regardless of this feature flag. If the flag is intended to control all zero state display (not just recommendations), this behavioral change is a regression. If the intent is that recent searches + custom sections should always open (bypassing the flag), the change is correct but should be explicitly documented in a comment.

Comment thread src/utils/beaconUtils.ts
* Stores a recent search
*/
export const storeRecentSearch = (term, suggestionData) => {
export const storeRecentSearch = (term: string, suggestionData) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important Issue: suggestionData remains untyped (any implicitly). Given that StoreRecentSearch was just introduced, the parameter should be typed — at minimum Record<string, unknown> or a dedicated type — to keep the function consistent with the rest of the typed additions in this PR.

const recentSearchesResults: SectionsData = {};

recentSearchesSections.forEach(({ displayName, numResults }) => {
recentSearchesResults[displayName] = recentSearchesFromStore
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: When two recentSearches sections share the same displayName (a user misconfiguration), the second will silently overwrite the first. Consider either (a) deduplicating by displayName with a warning, or (b) keying by a composite key to prevent silent data loss.

{ term: 'blue jeans', ts: Date.now() - 2000 },
{ term: 'white sneakers', ts: Date.now() - 1000 },
];
localStorage.setItem(recentSearchesStorageKey, JSON.stringify(mockRecentSearches));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The localStorage.setItem calls at module-level (lines ~590–595, outside any story play function) will run at import time and pollute localStorage for all stories in this file, not just the recent-searches ones. This can cause cross-story test interference. Move the setup exclusively inside the play functions (which is already done redundantly there), or use a beforeEach/loaders hook instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants