Commit 74accb2b authored by Greg Bugyis's avatar Greg Bugyis Committed by GitHub

feat: Search result events (#5025)

parent 28911983
......@@ -12,6 +12,7 @@ export enum EventName {
EXPLORE_SEARCH_SELECTED = 'Explore Search Selected',
EXPLORE_TOKEN_ROW_CLICKED = 'Explore Token Row Clicked',
PAGE_VIEWED = 'Page Viewed',
NAVBAR_RESULT_SELECTED = 'Navbar Result Selected',
NAVBAR_SEARCH_SELECTED = 'Navbar Search Selected',
NAVBAR_SEARCH_EXITED = 'Navbar Search Exited',
NFT_ACTIVITY_SELECTED = 'NFT Activity Selected',
......@@ -97,6 +98,7 @@ export enum PageName {
export enum SectionName {
CURRENCY_INPUT_PANEL = 'swap-currency-input',
CURRENCY_OUTPUT_PANEL = 'swap-currency-output',
NAVBAR_SEARCH = 'Navbar Search',
WIDGET = 'widget',
// alphabetize additional section names.
}
......@@ -148,6 +150,15 @@ export enum Event {
// alphabetize additional events.
}
/** Known navbar search result types */
export enum NavBarSearchTypes {
COLLECTION_SUGGESTION = 'collection-suggestion',
COLLECTION_TRENDING = 'collection-trending',
RECENT_SEARCH = 'recent',
TOKEN_SUGGESTION = 'token-suggestion',
TOKEN_TRENDING = 'token-trending',
}
/**
* Known Filter Types for NFTs
*/
......
// eslint-disable-next-line no-restricted-imports
import { t } from '@lingui/macro'
import { sendAnalyticsEvent } from 'analytics'
import { ElementName, Event, EventName } from 'analytics/constants'
import { ElementName, Event, EventName, SectionName } from 'analytics/constants'
import { Trace } from 'analytics/Trace'
import { useTrace } from 'analytics/Trace'
import { TraceEvent } from 'analytics/TraceEvent'
import clsx from 'clsx'
import { NftVariant, useNftFlag } from 'featureFlags/flags/nft'
......@@ -95,77 +97,85 @@ export const SearchBar = () => {
const showCenteredSearchContent =
!isOpen && phase1Flag !== NftVariant.Enabled && !isMobileOrTablet && searchValue.length === 0
const trace = useTrace({ section: SectionName.NAVBAR_SEARCH })
const navbarSearchEventProperties = {
navbar_search_input_text: debouncedSearchValue,
hasInput: debouncedSearchValue && debouncedSearchValue.length > 0,
...trace,
}
return (
<Box position="relative">
<Box
position={{ sm: 'fixed', md: 'absolute' }}
width={{ sm: isOpen ? 'viewWidth' : 'auto', md: 'auto' }}
ref={searchRef}
className={styles.searchBarContainer}
display={{ sm: isOpen ? 'inline-block' : 'none', xl: 'inline-block' }}
>
<Row
className={clsx(
` ${styles.searchBar} ${!isOpen && !isMobile && magicalGradientOnHover} ${
isMobileOrTablet && (isOpen ? styles.visible : styles.hidden)
}`
)}
borderRadius={isOpen || isMobileOrTablet ? undefined : '12'}
borderTopRightRadius={isOpen && !isMobile ? '12' : undefined}
borderTopLeftRadius={isOpen && !isMobile ? '12' : undefined}
borderBottomWidth={isOpen || isMobileOrTablet ? '0px' : '1px'}
onClick={() => !isOpen && toggleOpen()}
gap="12"
<Trace section={SectionName.NAVBAR_SEARCH}>
<Box
position={{ sm: 'fixed', md: 'absolute' }}
width={{ sm: isOpen ? 'viewWidth' : 'auto', md: 'auto' }}
ref={searchRef}
className={styles.searchBarContainer}
display={{ sm: isOpen ? 'inline-block' : 'none', xl: 'inline-block' }}
>
<Box className={showCenteredSearchContent ? styles.searchContentCentered : styles.searchContentLeftAlign}>
<Box display={{ sm: 'none', md: 'flex' }}>
<MagnifyingGlassIcon />
</Box>
<Box display={{ sm: 'flex', md: 'none' }} color="textTertiary" onClick={toggleOpen}>
<ChevronLeftIcon />
<Row
className={clsx(
` ${styles.searchBar} ${!isOpen && !isMobile && magicalGradientOnHover} ${
isMobileOrTablet && (isOpen ? styles.visible : styles.hidden)
}`
)}
borderRadius={isOpen || isMobileOrTablet ? undefined : '12'}
borderTopRightRadius={isOpen && !isMobile ? '12' : undefined}
borderTopLeftRadius={isOpen && !isMobile ? '12' : undefined}
borderBottomWidth={isOpen || isMobileOrTablet ? '0px' : '1px'}
onClick={() => !isOpen && toggleOpen()}
gap="12"
>
<Box className={showCenteredSearchContent ? styles.searchContentCentered : styles.searchContentLeftAlign}>
<Box display={{ sm: 'none', md: 'flex' }}>
<MagnifyingGlassIcon />
</Box>
<Box display={{ sm: 'flex', md: 'none' }} color="textTertiary" onClick={toggleOpen}>
<ChevronLeftIcon />
</Box>
</Box>
<TraceEvent
events={[Event.onFocus]}
name={EventName.NAVBAR_SEARCH_SELECTED}
element={ElementName.NAVBAR_SEARCH_INPUT}
properties={{ ...trace }}
>
<Box
as="input"
placeholder={placeholderText}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
!isOpen && toggleOpen()
setSearchValue(event.target.value)
}}
onBlur={() => sendAnalyticsEvent(EventName.NAVBAR_SEARCH_EXITED, navbarSearchEventProperties)}
className={`${styles.searchBarInput} ${
showCenteredSearchContent ? styles.searchContentCentered : styles.searchContentLeftAlign
}`}
value={searchValue}
ref={inputRef}
width={phase1Flag === NftVariant.Enabled || isOpen ? 'full' : '160'}
/>
</TraceEvent>
</Row>
<Box className={clsx(isOpen ? styles.visible : styles.hidden)}>
{isOpen && (
<SearchBarDropdown
toggleOpen={toggleOpen}
tokens={reducedTokens}
collections={reducedCollections}
queryText={debouncedSearchValue}
hasInput={debouncedSearchValue.length > 0}
isLoading={tokensAreLoading || (collectionsAreLoading && phase1Flag === NftVariant.Enabled)}
/>
)}
</Box>
<TraceEvent
events={[Event.onFocus]}
name={EventName.NAVBAR_SEARCH_SELECTED}
element={ElementName.NAVBAR_SEARCH_INPUT}
>
<Box
as="input"
placeholder={placeholderText}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
!isOpen && toggleOpen()
setSearchValue(event.target.value)
}}
onBlur={() => sendAnalyticsEvent(EventName.NAVBAR_SEARCH_EXITED, navbarSearchEventProperties)}
className={`${styles.searchBarInput} ${
showCenteredSearchContent ? styles.searchContentCentered : styles.searchContentLeftAlign
}`}
value={searchValue}
ref={inputRef}
width={phase1Flag === NftVariant.Enabled || isOpen ? 'full' : '160'}
/>
</TraceEvent>
</Row>
<Box className={clsx(isOpen ? styles.visible : styles.hidden)}>
{isOpen && (
<SearchBarDropdown
toggleOpen={toggleOpen}
tokens={reducedTokens}
collections={reducedCollections}
hasInput={debouncedSearchValue.length > 0}
isLoading={tokensAreLoading || (collectionsAreLoading && phase1Flag === NftVariant.Enabled)}
/>
)}
</Box>
</Box>
<NavIcon onClick={toggleOpen}>
<NavMagnifyingGlassIcon />
</NavIcon>
<NavIcon onClick={toggleOpen}>
<NavMagnifyingGlassIcon />
</NavIcon>
</Trace>
</Box>
)
}
import { Trans } from '@lingui/macro'
import { sendAnalyticsEvent } from 'analytics'
import { EventName } from 'analytics/constants'
import { NavBarSearchTypes, SectionName } from 'analytics/constants'
import { useTrace } from 'analytics/Trace'
import { NftVariant, useNftFlag } from 'featureFlags/flags/nft'
import { Box } from 'nft/components/Box'
import { Column, Row } from 'nft/components/Flex'
......@@ -31,6 +31,7 @@ interface SearchBarDropdownSectionProps {
startingIndex: number
setHoveredIndex: (index: number | undefined) => void
isLoading?: boolean
eventProperties: Record<string, unknown>
}
export const SearchBarDropdownSection = ({
......@@ -42,6 +43,7 @@ export const SearchBarDropdownSection = ({
startingIndex,
setHoveredIndex,
isLoading,
eventProperties,
}: SearchBarDropdownSectionProps) => {
return (
<Column gap="12">
......@@ -60,16 +62,13 @@ export const SearchBarDropdownSection = ({
isHovered={hoveredIndex === index + startingIndex}
setHoveredIndex={setHoveredIndex}
toggleOpen={toggleOpen}
traceEvent={() =>
sendAnalyticsEvent(EventName.NAVBAR_SEARCH_EXITED, {
position: index,
selected_type: 'collection',
suggestion_count: suggestions.length,
selected_name: suggestion.name,
selected_address: suggestion.address,
})
}
index={index + startingIndex}
eventProperties={{
position: index + startingIndex,
selected_search_result_name: suggestion.name,
selected_search_result_address: suggestion.address,
...eventProperties,
}}
/>
) : (
<TokenRow
......@@ -78,16 +77,13 @@ export const SearchBarDropdownSection = ({
isHovered={hoveredIndex === index + startingIndex}
setHoveredIndex={setHoveredIndex}
toggleOpen={toggleOpen}
traceEvent={() =>
sendAnalyticsEvent(EventName.NAVBAR_SEARCH_EXITED, {
position: index,
selected_type: 'token',
suggestion_count: suggestions.length,
selected_name: suggestion.name,
selected_address: suggestion.address,
})
}
index={index + startingIndex}
eventProperties={{
position: index + startingIndex,
selected_search_result_name: suggestion.name,
selected_search_result_address: suggestion.address,
...eventProperties,
}}
/>
)
)}
......@@ -100,11 +96,19 @@ interface SearchBarDropdownProps {
toggleOpen: () => void
tokens: FungibleToken[]
collections: GenieCollection[]
queryText: string
hasInput: boolean
isLoading: boolean
}
export const SearchBarDropdown = ({ toggleOpen, tokens, collections, hasInput, isLoading }: SearchBarDropdownProps) => {
export const SearchBarDropdown = ({
toggleOpen,
tokens,
collections,
queryText,
hasInput,
isLoading,
}: SearchBarDropdownProps) => {
const [hoveredIndex, setHoveredIndex] = useState<number | undefined>(0)
const { history: searchHistory, updateItem: updateSearchHistory } = useSearchHistory()
const shortenedHistory = useMemo(() => searchHistory.slice(0, 2), [searchHistory])
......@@ -192,7 +196,10 @@ export const SearchBarDropdown = ({ toggleOpen, tokens, collections, hasInput, i
}
}, [toggleOpen, hoveredIndex, totalSuggestions])
const trace = useTrace({ section: SectionName.NAVBAR_SEARCH })
useEffect(() => {
const eventProperties = { total_suggestions: totalSuggestions, query_text: queryText, ...trace }
if (!isLoading) {
const tokenSearchResults =
tokens.length > 0 ? (
......@@ -202,6 +209,10 @@ export const SearchBarDropdown = ({ toggleOpen, tokens, collections, hasInput, i
setHoveredIndex={setHoveredIndex}
toggleOpen={toggleOpen}
suggestions={tokens}
eventProperties={{
suggestion_type: NavBarSearchTypes.TOKEN_SUGGESTION,
...eventProperties,
}}
header={<Trans>Tokens</Trans>}
/>
) : (
......@@ -219,6 +230,10 @@ export const SearchBarDropdown = ({ toggleOpen, tokens, collections, hasInput, i
setHoveredIndex={setHoveredIndex}
toggleOpen={toggleOpen}
suggestions={collections}
eventProperties={{
suggestion_type: NavBarSearchTypes.COLLECTION_SUGGESTION,
...eventProperties,
}}
header={<Trans>NFT Collections</Trans>}
/>
) : (
......@@ -252,6 +267,10 @@ export const SearchBarDropdown = ({ toggleOpen, tokens, collections, hasInput, i
setHoveredIndex={setHoveredIndex}
toggleOpen={toggleOpen}
suggestions={shortenedHistory}
eventProperties={{
suggestion_type: NavBarSearchTypes.RECENT_SEARCH,
...eventProperties,
}}
header={<Trans>Recent searches</Trans>}
headerIcon={<ClockIcon />}
/>
......@@ -263,6 +282,10 @@ export const SearchBarDropdown = ({ toggleOpen, tokens, collections, hasInput, i
setHoveredIndex={setHoveredIndex}
toggleOpen={toggleOpen}
suggestions={trendingTokens}
eventProperties={{
suggestion_type: NavBarSearchTypes.TOKEN_TRENDING,
...eventProperties,
}}
header={<Trans>Popular tokens</Trans>}
headerIcon={<TrendingArrow />}
isLoading={trendingTokensAreLoading}
......@@ -275,6 +298,10 @@ export const SearchBarDropdown = ({ toggleOpen, tokens, collections, hasInput, i
setHoveredIndex={setHoveredIndex}
toggleOpen={toggleOpen}
suggestions={trendingCollections as unknown as GenieCollection[]}
eventProperties={{
suggestion_type: NavBarSearchTypes.COLLECTION_TRENDING,
...eventProperties,
}}
header={<Trans>Popular NFT collections</Trans>}
headerIcon={<TrendingArrow />}
isLoading={trendingCollectionsAreLoading}
......@@ -300,6 +327,9 @@ export const SearchBarDropdown = ({ toggleOpen, tokens, collections, hasInput, i
hasInput,
isNFTPage,
isTokenPage,
queryText,
totalSuggestions,
trace,
])
return (
......
import { useWeb3React } from '@web3-react/core'
import { sendAnalyticsEvent } from 'analytics'
import { EventName } from 'analytics/constants'
import clsx from 'clsx'
import { L2NetworkLogo, LogoContainer } from 'components/Tokens/TokenTable/TokenRow'
import TokenSafetyIcon from 'components/TokenSafety/TokenSafetyIcon'
......@@ -25,8 +27,8 @@ interface CollectionRowProps {
isHovered: boolean
setHoveredIndex: (index: number | undefined) => void
toggleOpen: () => void
traceEvent: () => void
index: number
eventProperties: Record<string, unknown>
}
export const CollectionRow = ({
......@@ -34,8 +36,8 @@ export const CollectionRow = ({
isHovered,
setHoveredIndex,
toggleOpen,
traceEvent,
index,
eventProperties,
}: CollectionRowProps) => {
const [brokenImage, setBrokenImage] = useState(false)
const [loaded, setLoaded] = useState(false)
......@@ -47,8 +49,8 @@ export const CollectionRow = ({
const handleClick = useCallback(() => {
addToSearchHistory(collection)
toggleOpen()
traceEvent()
}, [addToSearchHistory, collection, toggleOpen, traceEvent])
sendAnalyticsEvent(EventName.NAVBAR_RESULT_SELECTED, { ...eventProperties })
}, [addToSearchHistory, collection, toggleOpen, eventProperties])
useEffect(() => {
const keyDownHandler = (event: KeyboardEvent) => {
......@@ -120,11 +122,11 @@ interface TokenRowProps {
isHovered: boolean
setHoveredIndex: (index: number | undefined) => void
toggleOpen: () => void
traceEvent: () => void
index: number
eventProperties: Record<string, unknown>
}
export const TokenRow = ({ token, isHovered, setHoveredIndex, toggleOpen, traceEvent, index }: TokenRowProps) => {
export const TokenRow = ({ token, isHovered, setHoveredIndex, toggleOpen, index, eventProperties }: TokenRowProps) => {
const [brokenImage, setBrokenImage] = useState(false)
const [loaded, setLoaded] = useState(false)
const addToSearchHistory = useSearchHistory(
......@@ -135,8 +137,8 @@ export const TokenRow = ({ token, isHovered, setHoveredIndex, toggleOpen, traceE
const handleClick = useCallback(() => {
addToSearchHistory(token)
toggleOpen()
traceEvent()
}, [addToSearchHistory, toggleOpen, token, traceEvent])
sendAnalyticsEvent(EventName.NAVBAR_RESULT_SELECTED, { ...eventProperties })
}, [addToSearchHistory, toggleOpen, token, eventProperties])
const [bridgedAddress, bridgedChain, L2Icon] = useBridgedAddress(token)
const tokenDetailsPath = getTokenDetailsURL(bridgedAddress ?? token.address, undefined, bridgedChain ?? token.chainId)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment