feat: Collection page log events (#4971)
* Log collection page view * Make property names/intention more clear * Remove console log * Add event for Activity tab * Filter events (buy now, marketplaces, and price range) * Handle trait items * Bump collection stats mobile padding * Use shouldLogImpression to conditionally fire event * Adding back trace on Collection page, still necessary * Add back address property * Drop Buy Now log, not part of first set * Update filter properties to match spreadsheet * Only trigger price range log if inputs contain a value * Fix ordering on Page Names * Capitalize text * Add constant for filter types * Add chainId as property
This commit is contained in:
parent
e2fea4a5fb
commit
d86120a257
@ -14,6 +14,9 @@ export enum EventName {
|
||||
PAGE_VIEWED = 'Page Viewed',
|
||||
NAVBAR_SEARCH_SELECTED = 'Navbar Search Selected',
|
||||
NAVBAR_SEARCH_EXITED = 'Navbar Search Exited',
|
||||
NFT_ACTIVITY_SELECTED = 'NFT Activity Selected',
|
||||
NFT_FILTER_OPENED = 'NFT Collection Filter Opened',
|
||||
NFT_FILTER_SELECTED = 'NFT Filter Selected',
|
||||
SWAP_AUTOROUTER_VISUALIZATION_EXPANDED = 'Swap Autorouter Visualization Expanded',
|
||||
SWAP_DETAILS_EXPANDED = 'Swap Details Expanded',
|
||||
SWAP_MAX_TOKEN_AMOUNT_SELECTED = 'Swap Max Token Amount Selected',
|
||||
@ -74,6 +77,7 @@ export enum SWAP_PRICE_UPDATE_USER_RESPONSE {
|
||||
* Known pages in the app. Highest order context.
|
||||
*/
|
||||
export enum PageName {
|
||||
NFT_COLLECTION_PAGE = 'nft-collection-page',
|
||||
NFT_DETAILS_PAGE = 'nft-details-page',
|
||||
TOKEN_DETAILS_PAGE = 'token-details',
|
||||
TOKENS_PAGE = 'tokens-page',
|
||||
@ -116,6 +120,9 @@ export enum ElementName {
|
||||
IMPORT_TOKEN_BUTTON = 'import-token-button',
|
||||
MAX_TOKEN_AMOUNT_BUTTON = 'max-token-amount-button',
|
||||
NAVBAR_SEARCH_INPUT = 'navbar-search-input',
|
||||
NFT_ACTIVITY_TAB = 'nft-activity-tab',
|
||||
NFT_FILTER_BUTTON = 'nft-filter-button',
|
||||
NFT_FILTER_OPTION = 'nft-filter-option',
|
||||
PRICE_UPDATE_ACCEPT_BUTTON = 'price-update-accept-button',
|
||||
SWAP_BUTTON = 'swap-button',
|
||||
SWAP_DETAILS_DROPDOWN = 'swap-details-dropdown',
|
||||
@ -137,3 +144,12 @@ export enum Event {
|
||||
onSelect = 'onSelect',
|
||||
// alphabetize additional events.
|
||||
}
|
||||
|
||||
/**
|
||||
* Known Filter Types for NFTs
|
||||
*/
|
||||
export enum FilterTypes {
|
||||
MARKETPLACE = 'Marketplace',
|
||||
PRICE_RANGE = 'Price Range',
|
||||
TRAIT = 'Trait',
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { ElementName, Event, EventName } from 'analytics/constants'
|
||||
import { TraceEvent } from 'analytics/TraceEvent'
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { Row } from 'nft/components/Flex'
|
||||
import { useIsCollectionLoading } from 'nft/hooks'
|
||||
@ -27,13 +29,19 @@ export const ActivitySwitcher = ({
|
||||
>
|
||||
Items
|
||||
</Box>
|
||||
<Box
|
||||
as="button"
|
||||
className={!showActivity ? styles.activitySwitcherToggle : styles.selectedActivitySwitcherToggle}
|
||||
onClick={() => !showActivity && toggleActivity()}
|
||||
<TraceEvent
|
||||
events={[Event.onClick]}
|
||||
element={ElementName.NFT_ACTIVITY_TAB}
|
||||
name={EventName.NFT_ACTIVITY_SELECTED}
|
||||
>
|
||||
Activity
|
||||
</Box>
|
||||
<Box
|
||||
as="button"
|
||||
className={!showActivity ? styles.activitySwitcherToggle : styles.selectedActivitySwitcherToggle}
|
||||
onClick={() => !showActivity && toggleActivity()}
|
||||
>
|
||||
Activity
|
||||
</Box>
|
||||
</TraceEvent>
|
||||
</>
|
||||
)}
|
||||
</Row>
|
||||
|
@ -1,3 +1,6 @@
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { ElementName, Event, EventName } from 'analytics/constants'
|
||||
import { TraceEvent } from 'analytics/TraceEvent'
|
||||
import clsx from 'clsx'
|
||||
import { loadingAnimation } from 'components/Loader/styled'
|
||||
import useDebounce from 'hooks/useDebounce'
|
||||
@ -104,6 +107,7 @@ export const LoadingButton = styled.div`
|
||||
`
|
||||
|
||||
export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerified }: CollectionNftsProps) => {
|
||||
const { chainId } = useWeb3React()
|
||||
const traits = useCollectionFilters((state) => state.traits)
|
||||
const minPrice = useCollectionFilters((state) => state.minPrice)
|
||||
const maxPrice = useCollectionFilters((state) => state.maxPrice)
|
||||
@ -356,12 +360,20 @@ export const CollectionNfts = ({ contractAddress, collectionStats, rarityVerifie
|
||||
<Box backgroundColor="backgroundFloating" width="full" style={{ backdropFilter: 'blur(24px)' }}>
|
||||
<ActionsContainer>
|
||||
<Row gap="12">
|
||||
<FilterButton
|
||||
isMobile={isMobile}
|
||||
isFiltersExpanded={isFiltersExpanded}
|
||||
onClick={() => setFiltersExpanded(!isFiltersExpanded)}
|
||||
collectionCount={collectionNfts?.[0]?.totalCount ?? 0}
|
||||
/>
|
||||
<TraceEvent
|
||||
events={[Event.onClick]}
|
||||
element={ElementName.NFT_FILTER_BUTTON}
|
||||
name={EventName.NFT_FILTER_OPENED}
|
||||
shouldLogImpression={!isFiltersExpanded}
|
||||
properties={{ collection_address: contractAddress, chain_id: chainId }}
|
||||
>
|
||||
<FilterButton
|
||||
isMobile={isMobile}
|
||||
isFiltersExpanded={isFiltersExpanded}
|
||||
onClick={() => setFiltersExpanded(!isFiltersExpanded)}
|
||||
collectionCount={collectionNfts?.[0]?.totalCount ?? 0}
|
||||
/>
|
||||
</TraceEvent>
|
||||
<SortDropdown dropDownOptions={sortDropDownOptions} />
|
||||
<CollectionSearch />
|
||||
</Row>
|
||||
|
@ -277,7 +277,7 @@ const StatsRow = ({ stats, isMobile, ...props }: { stats: GenieCollection; isMob
|
||||
)
|
||||
|
||||
return (
|
||||
<Row gap={{ sm: '20', md: '60' }} {...props}>
|
||||
<Row gap={{ sm: '36', md: '60' }} {...props}>
|
||||
{isCollectionStatsLoading && statsLoadingSkeleton}
|
||||
{stats.floorPrice ? (
|
||||
<StatsItem label="Global floor" isMobile={isMobile ?? false}>
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { sendAnalyticsEvent } from 'analytics'
|
||||
import { EventName, FilterTypes } from 'analytics/constants'
|
||||
import clsx from 'clsx'
|
||||
import { Box } from 'nft/components/Box'
|
||||
import * as styles from 'nft/components/collection/Filters.css'
|
||||
@ -48,6 +50,7 @@ const MarketplaceItem = ({
|
||||
removeMarket(value)
|
||||
setCheckboxSelected(false)
|
||||
}
|
||||
sendAnalyticsEvent(EventName.NFT_FILTER_SELECTED, { filter_type: FilterTypes.MARKETPLACE })
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -1,5 +1,7 @@
|
||||
import 'rc-slider/assets/index.css'
|
||||
|
||||
import { sendAnalyticsEvent } from 'analytics'
|
||||
import { EventName, FilterTypes } from 'analytics/constants'
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { Row } from 'nft/components/Flex'
|
||||
import { NumericInput } from 'nft/components/layout/Input'
|
||||
@ -54,6 +56,8 @@ export const PriceRange = () => {
|
||||
const handleBlur: FocusEventHandler<HTMLInputElement> = (e) => {
|
||||
e.currentTarget.placeholder = placeholderText
|
||||
setPlaceholderText('')
|
||||
if (minPrice || maxPrice)
|
||||
sendAnalyticsEvent(EventName.NFT_FILTER_SELECTED, { filter_type: FilterTypes.PRICE_RANGE })
|
||||
}
|
||||
|
||||
const updateMinPriceRange = (v: FormEvent<HTMLInputElement>) => {
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { sendAnalyticsEvent } from 'analytics'
|
||||
import { EventName, FilterTypes } from 'analytics/constants'
|
||||
import useDebounce from 'hooks/useDebounce'
|
||||
import { Box } from 'nft/components/Box'
|
||||
import { Column, Row } from 'nft/components/Flex'
|
||||
@ -53,6 +55,7 @@ const TraitItem = ({
|
||||
removeTrait(trait)
|
||||
setCheckboxSelected(false)
|
||||
}
|
||||
sendAnalyticsEvent(EventName.NFT_FILTER_SELECTED, { filter_type: FilterTypes.TRAIT })
|
||||
}
|
||||
|
||||
const showFullTraitName = shouldShow && trait_type === trait.trait_type && trait_value === trait.trait_value
|
||||
|
@ -1,3 +1,6 @@
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { PageName } from 'analytics/constants'
|
||||
import { Trace } from 'analytics/Trace'
|
||||
import { MobileHoverBag } from 'nft/components/bag/MobileHoverBag'
|
||||
import { AnimatedBox, Box } from 'nft/components/Box'
|
||||
import { Activity, ActivitySwitcher, CollectionNfts, CollectionStats, Filters } from 'nft/components/collection'
|
||||
@ -25,6 +28,7 @@ const Collection = () => {
|
||||
const isActivityToggled = pathname.includes('/activity')
|
||||
const setMarketCount = useCollectionFilters((state) => state.setMarketCount)
|
||||
const isBagExpanded = useBag((state) => state.bagExpanded)
|
||||
const { chainId } = useWeb3React()
|
||||
|
||||
const { data: collectionStats, isLoading } = useQuery(['collectionStats', contractAddress], () =>
|
||||
CollectionStatsFetcher(contractAddress as string)
|
||||
@ -61,75 +65,81 @@ const Collection = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Column width="full">
|
||||
{contractAddress ? (
|
||||
<>
|
||||
{' '}
|
||||
<Box width="full" height="160">
|
||||
<Trace
|
||||
page={PageName.NFT_COLLECTION_PAGE}
|
||||
properties={{ collection_address: contractAddress, chain_id: chainId }}
|
||||
shouldLogImpression
|
||||
>
|
||||
<Column width="full">
|
||||
{contractAddress ? (
|
||||
<>
|
||||
{' '}
|
||||
<Box width="full" height="160">
|
||||
{isLoading ? (
|
||||
<Box height="full" width="full" className={styles.loadingBanner} />
|
||||
) : (
|
||||
<Box
|
||||
as="img"
|
||||
height="full"
|
||||
width="full"
|
||||
src={collectionStats?.bannerImageUrl}
|
||||
className={isLoading ? styles.loadingBanner : styles.bannerImage}
|
||||
background="none"
|
||||
/>
|
||||
<Box width="full" height="160">
|
||||
{isLoading ? (
|
||||
<Box height="full" width="full" className={styles.loadingBanner} />
|
||||
) : (
|
||||
<Box
|
||||
as="img"
|
||||
height="full"
|
||||
width="full"
|
||||
src={collectionStats?.bannerImageUrl}
|
||||
className={isLoading ? styles.loadingBanner : styles.bannerImage}
|
||||
background="none"
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<Column paddingX="32">
|
||||
{(isLoading || collectionStats !== undefined) && (
|
||||
<CollectionStats stats={collectionStats || ({} as GenieCollection)} isMobile={isMobile} />
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<Column paddingX="32">
|
||||
{(isLoading || collectionStats !== undefined) && (
|
||||
<CollectionStats stats={collectionStats || ({} as GenieCollection)} isMobile={isMobile} />
|
||||
)}
|
||||
|
||||
<ActivitySwitcher
|
||||
showActivity={isActivityToggled}
|
||||
toggleActivity={() => {
|
||||
isFiltersExpanded && setFiltersExpanded(false)
|
||||
toggleActivity()
|
||||
}}
|
||||
/>
|
||||
</Column>
|
||||
<Row alignItems="flex-start" position="relative" paddingX="48">
|
||||
<Box position="sticky" top="72" width="0">
|
||||
{isFiltersExpanded && <Filters traits={collectionStats?.traits ?? []} />}
|
||||
</Box>
|
||||
<ActivitySwitcher
|
||||
showActivity={isActivityToggled}
|
||||
toggleActivity={() => {
|
||||
isFiltersExpanded && setFiltersExpanded(false)
|
||||
toggleActivity()
|
||||
}}
|
||||
/>
|
||||
</Column>
|
||||
<Row alignItems="flex-start" position="relative" paddingX="48">
|
||||
<Box position="sticky" top="72" width="0">
|
||||
{isFiltersExpanded && <Filters traits={collectionStats?.traits ?? []} />}
|
||||
</Box>
|
||||
|
||||
{/* @ts-ignore: https://github.com/microsoft/TypeScript/issues/34933 */}
|
||||
<AnimatedBox
|
||||
style={{
|
||||
transform: gridX.to((x) => `translate(${x as number}px)`),
|
||||
width: gridWidthOffset.to((x) => `calc(100% - ${x as number}px)`),
|
||||
}}
|
||||
>
|
||||
{isActivityToggled
|
||||
? contractAddress && (
|
||||
<Activity
|
||||
contractAddress={contractAddress}
|
||||
rarityVerified={collectionStats?.rarityVerified ?? false}
|
||||
collectionName={collectionStats?.name ?? ''}
|
||||
/>
|
||||
)
|
||||
: contractAddress &&
|
||||
(isLoading || collectionStats !== undefined) && (
|
||||
<CollectionNfts
|
||||
collectionStats={collectionStats || ({} as GenieCollection)}
|
||||
contractAddress={contractAddress}
|
||||
rarityVerified={collectionStats?.rarityVerified}
|
||||
/>
|
||||
)}
|
||||
</AnimatedBox>
|
||||
</Row>
|
||||
</>
|
||||
) : (
|
||||
// TODO: Put no collection asset page here
|
||||
!isLoading && <div className={styles.noCollectionAssets}>No collection assets exist at this address</div>
|
||||
)}
|
||||
</Column>
|
||||
{/* @ts-ignore: https://github.com/microsoft/TypeScript/issues/34933 */}
|
||||
<AnimatedBox
|
||||
style={{
|
||||
transform: gridX.to((x) => `translate(${x as number}px)`),
|
||||
width: gridWidthOffset.to((x) => `calc(100% - ${x as number}px)`),
|
||||
}}
|
||||
>
|
||||
{isActivityToggled
|
||||
? contractAddress && (
|
||||
<Activity
|
||||
contractAddress={contractAddress}
|
||||
rarityVerified={collectionStats?.rarityVerified ?? false}
|
||||
collectionName={collectionStats?.name ?? ''}
|
||||
/>
|
||||
)
|
||||
: contractAddress &&
|
||||
(isLoading || collectionStats !== undefined) && (
|
||||
<CollectionNfts
|
||||
collectionStats={collectionStats || ({} as GenieCollection)}
|
||||
contractAddress={contractAddress}
|
||||
rarityVerified={collectionStats?.rarityVerified}
|
||||
/>
|
||||
)}
|
||||
</AnimatedBox>
|
||||
</Row>
|
||||
</>
|
||||
) : (
|
||||
// TODO: Put no collection asset page here
|
||||
!isLoading && <div className={styles.noCollectionAssets}>No collection assets exist at this address</div>
|
||||
)}
|
||||
</Column>
|
||||
</Trace>
|
||||
<MobileHoverBag />
|
||||
</>
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user