diff --git a/.changeset/swift-cycles-happen.md b/.changeset/swift-cycles-happen.md new file mode 100644 index 00000000000..cea8d80baf0 --- /dev/null +++ b/.changeset/swift-cycles-happen.md @@ -0,0 +1,5 @@ +--- +'polaris.shopify.com': patch +--- + +Added search tracking using google analytics diff --git a/polaris.shopify.com/src/components/GlobalSearch/GlobalSearch.tsx b/polaris.shopify.com/src/components/GlobalSearch/GlobalSearch.tsx index 3a491d64007..9c2f258bc43 100644 --- a/polaris.shopify.com/src/components/GlobalSearch/GlobalSearch.tsx +++ b/polaris.shopify.com/src/components/GlobalSearch/GlobalSearch.tsx @@ -43,6 +43,22 @@ function scrollToTop() { overflowEl?.scrollTo({top: 0, behavior: 'smooth'}); } +function captureSearchEvent( + searchTerm: string, + resultRank: number, + selectedResult?: string, +) { + const eventParams = { + searchTerm, + resultRank, + selectedResult, + }; + + if (searchTerm) { + window.gtag('event', 'customSearch', eventParams); + } +} + function scrollIntoView() { const overflowEl = document.querySelector(`.${styles.ResultsInner}`); const highlightedEl = document.querySelector( @@ -152,6 +168,7 @@ function GlobalSearch() { if (resultsInRenderedOrder.length > 0) { setIsOpen(false); const url = resultsInRenderedOrder[currentResultIndex].url; + captureSearchEvent(searchTerm, currentResultIndex + 1, url); router.push(url); } break; @@ -171,7 +188,14 @@ function GlobalSearch() { Search / - setIsOpen(false)}> + { + setIsOpen(false); + // on close we want to capture that no search result was selected + captureSearchEvent(searchTerm, 0); + }} + >
@@ -213,6 +237,8 @@ function GlobalSearch() { )}
@@ -226,9 +252,13 @@ function GlobalSearch() { function SearchResults({ searchResults, currentItemId, + searchTerm, + resultsInRenderedOrder, }: { searchResults: GroupedSearchResults; currentItemId: string; + searchTerm?: string; + resultsInRenderedOrder: SearchResults; }) { return ( <> @@ -243,6 +273,12 @@ function SearchResults({ if (!meta.foundations) return null; const {title, description, icon, category} = meta.foundations; + const resultIndex = resultsInRenderedOrder.findIndex( + (r) => { + return r.id === id; + }, + ); + const rank = resultIndex + 1; // zero-indexed return ( + searchTerm && + captureSearchEvent(searchTerm, rank, url) + } renderPreview={() => ( { if (!meta.patterns) return null; const {title, description, previewImg} = meta.patterns; + const resultIndex = resultsInRenderedOrder.findIndex( + (r) => { + return r.id === id; + }, + ); + const rank = resultIndex + 1; return ( + searchTerm && + captureSearchEvent(searchTerm, rank, url) + } renderPreview={() => ( { if (!meta.components) return null; const {title, description, status, group} = meta.components; + const resultIndex = resultsInRenderedOrder.findIndex( + (r) => { + return r.id === id; + }, + ); + const rank = resultIndex + 1; return ( + searchTerm && + captureSearchEvent(searchTerm, rank, url) + } renderPreview={() => ( )} @@ -342,12 +402,24 @@ function SearchResults({ {results.map(({id, meta}) => { if (!meta.tokens) return null; const {token, category} = meta.tokens; + const resultIndex = resultsInRenderedOrder.findIndex( + (r) => { + return r.id === id; + }, + ); + const rank = resultIndex + 1; return ( - + ); })} @@ -363,12 +435,23 @@ function SearchResults({ {results.map(({id, meta}) => { if (!meta.icons) return null; const {icon} = meta.icons; + const resultIndex = resultsInRenderedOrder.findIndex( + (r) => { + return r.id === id; + }, + ); + const rank = resultIndex + 1; return ( - + ); })} diff --git a/polaris.shopify.com/src/components/Grid/Grid.tsx b/polaris.shopify.com/src/components/Grid/Grid.tsx index 48d18d426d5..6ac6d867c3b 100644 --- a/polaris.shopify.com/src/components/Grid/Grid.tsx +++ b/polaris.shopify.com/src/components/Grid/Grid.tsx @@ -66,25 +66,39 @@ export interface GridItemProps { deepLinks?: {url: string; text: string}[]; renderPreview?: () => React.ReactNode; status?: Status; + customOnClick?: React.MouseEventHandler; + searchQuery?: string; + rank?: number; } export const GridItem = forwardRef( ( - {as = 'li', title, description, url, deepLinks, renderPreview, status}, + { + as = 'li', + title, + description, + url, + deepLinks, + renderPreview, + status, + customOnClick, + }, ref, ) => { const searchAttributes = useGlobalSearchResult(); return ( - - - {renderPreview && ( -
{renderPreview()}
- )} -

- {title} {status && } -

-

{stripMarkdownLinks(description || '')}

+ + + + {renderPreview && ( +
{renderPreview()}
+ )} +

+ {title} {status && } +

+

{stripMarkdownLinks(description || '')}

+
{deepLinks && (
    diff --git a/polaris.shopify.com/src/components/IconGrid/IconGrid.tsx b/polaris.shopify.com/src/components/IconGrid/IconGrid.tsx index f39ef25015e..ff948d17bb3 100644 --- a/polaris.shopify.com/src/components/IconGrid/IconGrid.tsx +++ b/polaris.shopify.com/src/components/IconGrid/IconGrid.tsx @@ -27,15 +27,26 @@ interface IconGridItemProps { icon: IconType; query?: string; activeIcon?: string; + customOnClick?: Function; + rank?: number; + searchTerm?: string; } -function IconGridItem({icon, activeIcon, query}: IconGridItemProps) { +function IconGridItem({ + icon, + activeIcon, + query, + customOnClick, + rank, + searchTerm, +}: IconGridItemProps) { const {id, name} = icon; const searchAttributes = useGlobalSearchResult(); return (
  • - - -

    {name}

    + + customOnClick && + customOnClick(searchTerm, rank, `/icons?icon=${id}`) + } + > + + +

    {name}

    +
  • ); diff --git a/polaris.shopify.com/src/components/TokenList/TokenList.tsx b/polaris.shopify.com/src/components/TokenList/TokenList.tsx index 9cc95ef74a9..b815d546152 100644 --- a/polaris.shopify.com/src/components/TokenList/TokenList.tsx +++ b/polaris.shopify.com/src/components/TokenList/TokenList.tsx @@ -124,11 +124,17 @@ function getFigmaUsageForToken( interface TokenListItemProps { category: string; token: TokenPropertiesWithName; + customOnClick?: Function; + searchTerm?: string; + rank?: number; } function TokenListItem({ category, token: {name, value, description}, + customOnClick, + searchTerm, + rank, }: TokenListItemProps) { const figmaUsage = getFigmaUsageForToken(name, value); const tokenNameWithPrefix = `--p-${name}`; @@ -136,6 +142,11 @@ function TokenListItem({ const searchAttributes = useGlobalSearchResult(); const isClickableSearchResult = !!searchAttributes?.tabIndex; + const url = `/tokens/${category}#${searchAttributes?.id}`; + + const customOnClickHandler = () => { + customOnClick && customOnClick(searchTerm, rank, url); + }; return ( @@ -152,11 +163,12 @@ function TokenListItem({ {isClickableSearchResult && ( - View token + View token )} @@ -177,7 +189,10 @@ function TokenListItem({ )} >