Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add registration tracking events for .eth and TLD (.box) funnel #840

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
9e7f8e5
Add registration tracking events for .eth funnel
nhohb Aug 30, 2024
ec53030
add estimatedTotal to pricing callback
storywithoutend Aug 30, 2024
faa5383
Refactor useRegistrationEventTracker and add tracking for "Payment se…
nhohb Aug 30, 2024
e7e4e33
Revert strict mode for development, add condition for commit wallet o…
nhohb Sep 4, 2024
7043e84
Add track registration event for TLD (.box)
nhohb Sep 4, 2024
fdcfeab
Add data for baseMockData on Pricing test
nhohb Sep 4, 2024
33be2fe
Add unit test for useRegistrationEventTracker
nhohb Sep 5, 2024
5a7ceca
Change registration tracking event name to snake case
nhohb Sep 6, 2024
95adbe7
Add e2e test for registration tracking event on registerName
nhohb Sep 6, 2024
e751725
Add e2e test for registration tracking events
nhohb Sep 10, 2024
eb52980
add some sample code
storywithoutend Sep 10, 2024
7ad1666
Update event tracker hook based on PR feedback
nhohb Sep 11, 2024
79d9b4b
Wrap event tracker expect code with test.step
nhohb Sep 12, 2024
d245e6b
Add e2e test for box registration and update search input wait time u…
nhohb Sep 13, 2024
eb690f3
Merge branch 'main' of github.com:ensdomains/ens-app-v3 into feat/FET…
nhohb Sep 13, 2024
8510aca
Remove all page.pause on registerName test
nhohb Sep 13, 2024
a25cbdf
reorder stateless tests
storywithoutend Sep 20, 2024
7615aa6
Move listen console event to fixtures, update analytics props for ref…
nhohb Sep 20, 2024
78eb780
Merge branch 'feat/FET-1177-add-registration-tracking-events' of gith…
nhohb Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const babelIncludeRegexes = [
* @type {import('next').NextConfig}
* */
const nextConfig = {
reactStrictMode: true,
reactStrictMode: process.env.NODE_ENV !== 'development',
compiler: {
nhohb marked this conversation as resolved.
Show resolved Hide resolved
styledComponents: true,
},
Expand Down
10 changes: 9 additions & 1 deletion src/components/@molecules/SearchInput/SearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ import { UsePriceQueryKey } from '@app/hooks/ensjs/public/usePrice'
import { UseWrapperDataQueryKey } from '@app/hooks/ensjs/public/useWrapperData'
import { useLocalStorage } from '@app/hooks/useLocalStorage'
import { createQueryKey } from '@app/hooks/useQueryOptions'
import { useRegistrationEventTracker } from '@app/hooks/useRegistrationEventTracker'
import { useRouterWithHistory } from '@app/hooks/useRouterWithHistory'
import { useValidate, validate } from '@app/hooks/useValidate'
import { useElementSize } from '@app/hooks/useWindowSize'
import { CreateQueryKey, GenericQueryKey } from '@app/types'
import { CreateQueryKey, GenericQueryKey, PlausibleProps, PlausibleType } from '@app/types'
import { useBreakpoint } from '@app/utils/BreakpointProvider'
import { getRegistrationStatus } from '@app/utils/registrationStatus'
import { thread, yearsToSeconds } from '@app/utils/utils'
Expand Down Expand Up @@ -311,6 +312,7 @@ type CreateSearchHandlerProps = {
setHistory: Dispatch<SetStateAction<HistoryItem[]>>
setInputVal: Dispatch<SetStateAction<string>>
queryClient: QueryClient
trackRegistrationEvent: (type: PlausibleType, customProps?: PlausibleProps | undefined) => void
}

const createSearchHandler =
Expand All @@ -323,6 +325,7 @@ const createSearchHandler =
setHistory,
setInputVal,
queryClient,
trackRegistrationEvent,
}: CreateSearchHandlerProps): SearchHandler =>
(index: number) => {
if (index === -1) return
Expand All @@ -338,6 +341,8 @@ const createSearchHandler =
{ lastAccessed: Date.now(), nameType, text, isValid: selectedItem.isValid },
])

trackRegistrationEvent('Search selected', { keyword: text })
nhohb marked this conversation as resolved.
Show resolved Hide resolved

const path = getRouteForSearchItem({ address, chainId, queryClient, selectedItem })
Copy link
Collaborator

Choose a reason for hiding this comment

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

If directing to .box registration page, path should be /dotbox/{name}. If directing to .eth registration page, path should be /register/{name}. Use this to fire the correct search_selected_[eth|box] event.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@storywithoutend
I've implemented your suggestion, but I'm encountering an issue. When a user enters a keyword and immediately presses Enter, the path always resolves to /profile/{name} instead of /register/{name}.

I believe the ownerData variable is undefined because getCachedQueryData isn't returning data in time.

To address this, I've added a waitForTimeout in e2e/specs/stateless/registerName.spec.ts and included a comment explaining the reason.

Please review these changes and let me know if you have any further feedback.

setInputVal('')
searchInputRef.current?.blur()
Expand Down Expand Up @@ -654,6 +659,7 @@ export const SearchInput = ({ size = 'extraLarge' }: { size?: 'medium' | 'extraL
const handleFocusOut = useCallback(() => toggle(false), [toggle])

const dropdownItems = useBuildDropdownItems(inputVal, history)
const { trackRegistrationEvent } = useRegistrationEventTracker()

// eslint-disable-next-line react-hooks/exhaustive-deps
const handleSearch = useCallback(
Expand All @@ -666,6 +672,7 @@ export const SearchInput = ({ size = 'extraLarge' }: { size?: 'medium' | 'extraL
searchInputRef,
setHistory,
setInputVal,
trackRegistrationEvent,
}),
[address, chainId, dropdownItems, queryClient, router, searchInputRef, setHistory, setInputVal],
)
Expand All @@ -689,6 +696,7 @@ export const SearchInput = ({ size = 'extraLarge' }: { size?: 'medium' | 'extraL
setInputVal(val)
setUsingPlaceholder(true)
debouncer(() => setUsingPlaceholder(false))
debouncer(() => trackRegistrationEvent('Start searching', { keyword: val }))
}

const SearchInputElement = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { useAddRecentTransaction } from '@app/hooks/transactions/useAddRecentTra
import { useRecentTransactions } from '@app/hooks/transactions/useRecentTransactions'
import { useIsSafeApp } from '@app/hooks/useIsSafeApp'
import { useQueryOptions } from '@app/hooks/useQueryOptions'
import { useRegistrationEventTracker } from '@app/hooks/useRegistrationEventTracker'
import {
ManagedDialogProps,
TransactionFlowAction,
Expand Down Expand Up @@ -295,7 +296,7 @@ export const TransactionStageModal = ({
}: ManagedDialogProps) => {
const { t } = useTranslation()
const chainName = useChainName()

const { trackRegistrationEvent } = useRegistrationEventTracker()
const { data: isSafeApp, isLoading: safeAppStatusLoading } = useIsSafeApp()
const { data: connectorClient } = useConnectorClient<ConfigWithEns>()
const client = useClient()
Expand Down Expand Up @@ -476,7 +477,12 @@ export const TransactionStageModal = ({
!!requestError ||
isTransactionRequestCachedData
}
onClick={() => sendTransaction(request!)}
onClick={() => {
sendTransaction(request!)
trackRegistrationEvent(
actionName === 'commitName' ? 'Commit Wallet Opened' : 'Finish Wallet Opened',
nhohb marked this conversation as resolved.
Show resolved Hide resolved
)
}}
data-testid="transaction-modal-confirm-button"
>
{t('transaction.dialog.confirm.openWallet')}
Expand All @@ -496,6 +502,8 @@ export const TransactionStageModal = ({
transactionLoading,
request,
isTransactionRequestCachedData,
trackRegistrationEvent,
actionName,
])

const stepStatus = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import Head from 'next/head'
import { useCallback, useEffect, useMemo } from 'react'
import { flushSync } from 'react-dom'
import { useTranslation } from 'react-i18next'
import styled, { css } from 'styled-components'
import { match, P } from 'ts-pattern'
import { formatUnits } from 'viem'
import { useAccount, useChainId } from 'wagmi'

import { Dialog, Helper, mq, Typography } from '@ensdomains/thorin'
Expand All @@ -13,6 +15,10 @@ import { ProfileRecord } from '@app/constants/profileRecordOptions'
import { useContractAddress } from '@app/hooks/chain/useContractAddress'
import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName'
import { useNameDetails } from '@app/hooks/useNameDetails'
import {
usePaymentSelectedEventTracker,
useRegistrationEventTracker,
} from '@app/hooks/useRegistrationEventTracker'
import useRegistrationReducer from '@app/hooks/useRegistrationReducer'
import { useResolverExists } from '@app/hooks/useResolverExists'
import { useRouterWithHistory } from '@app/hooks/useRouterWithHistory'
Expand Down Expand Up @@ -122,6 +128,8 @@ const Registration = ({ nameDetails, isLoading }: Props) => {

const labelTooLong = isLabelTooLong(normalisedName)
const { dispatch, item } = useRegistrationReducer(selected)
const { trackRegistrationEvent } = useRegistrationEventTracker()
const { trackPaymentSelectedEvent } = usePaymentSelectedEventTracker(item)
const step = item.queue[item.stepIndex]

const keySuffix = `${nameDetails.normalisedName}-${address}`
Expand All @@ -142,7 +150,13 @@ const Registration = ({ nameDetails, isLoading }: Props) => {
seconds,
reverseRecord,
paymentMethodChoice,
estimatedTotal,
ethPrice,
}: RegistrationStepData['pricing']) => {
console.log('>>', seconds, reverseRecord, paymentMethodChoice, estimatedTotal, ethPrice)
console.log('paymentTotal', formatUnits((estimatedTotal * ethPrice) / BigInt(1e8), 18))
trackPaymentSelectedEvent(paymentMethodChoice)

if (paymentMethodChoice === PaymentMethod.moonpay) {
initiateMoonpayRegistrationMutation.mutate(secondsToYears(seconds))
return
Expand Down Expand Up @@ -199,6 +213,11 @@ const Registration = ({ nameDetails, isLoading }: Props) => {
dispatch({ name: back ? 'decreaseStep' : 'increaseStep', selected })
}

const infoCallback = ({ back }: BackObj) => {
genericCallback({ back })
trackRegistrationEvent('Commit started')
}

const transactionsCallback = useCallback(
({ back, resetSecret }: BackObj & { resetSecret?: boolean }) => {
if (resetSecret) {
Expand All @@ -220,6 +239,7 @@ const Registration = ({ nameDetails, isLoading }: Props) => {

const onStart = () => {
dispatch({ name: 'setStarted', selected })
trackRegistrationEvent('Timer started')
}

const onComplete = (toProfile: boolean) => {
Expand Down Expand Up @@ -301,7 +321,7 @@ const Registration = ({ nameDetails, isLoading }: Props) => {
<Info
name={normalisedName}
registrationData={item}
callback={genericCallback}
callback={infoCallback}
onProfileClick={infoProfileCallback}
/>
))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { ConnectButton } from '@app/components/ConnectButton'
import { useAccountSafely } from '@app/hooks/account/useAccountSafely'
import { useContractAddress } from '@app/hooks/chain/useContractAddress'
import { useEstimateFullRegistration } from '@app/hooks/gasEstimation/useEstimateRegistration'
import { useEthPrice } from '@app/hooks/useEthPrice'
import { useBreakpoint } from '@app/utils/BreakpointProvider'
import { ONE_DAY, ONE_YEAR } from '@app/utils/time'

Expand Down Expand Up @@ -380,6 +381,8 @@ export type ActionButtonProps = {
seconds: number
balance: GetBalanceData | undefined
totalRequiredBalance?: bigint
estimatedTotal?: bigint
ethPrice?: bigint
}

export const ActionButton = (props: ActionButtonProps) => {
Expand All @@ -404,20 +407,35 @@ export const ActionButton = (props: ActionButtonProps) => {
reverseRecord,
seconds,
paymentMethodChoice,
estimatedTotal,
ethPrice,
callback,
}) => (
<Button
loading={initiateMoonpayRegistrationMutation.isPending}
data-testid="next-button"
onClick={() => callback({ reverseRecord, seconds, paymentMethodChoice })}
onClick={() =>
callback({
reverseRecord,
seconds,
paymentMethodChoice,
estimatedTotal,
ethPrice,
})
}
disabled={!paymentMethodChoice || initiateMoonpayRegistrationMutation.isPending}
>
{t('action.next', { ns: 'common' })}
</Button>
),
)
.with(
P.when((_props) => typeof _props.balance?.value !== 'bigint' || !_props.totalRequiredBalance),
P.when(
(_props) =>
typeof _props.balance?.value !== 'bigint' ||
!_props.totalRequiredBalance ||
!_props.ethPrice,
),
() => (
<Button data-testid="next-button" disabled>
{t('loading', { ns: 'common' })}
Expand All @@ -438,15 +456,25 @@ export const ActionButton = (props: ActionButtonProps) => {
</Button>
),
)
.otherwise(({ reverseRecord, seconds, paymentMethodChoice, callback }) => (
<Button
data-testid="next-button"
onClick={() => callback({ reverseRecord, seconds, paymentMethodChoice })}
disabled={!paymentMethodChoice}
>
{t('action.next', { ns: 'common' })}
</Button>
))
.otherwise(
({ reverseRecord, seconds, paymentMethodChoice, estimatedTotal, ethPrice, callback }) => (
<Button
data-testid="next-button"
onClick={() =>
callback({
reverseRecord,
seconds,
paymentMethodChoice,
estimatedTotal,
ethPrice,
})
}
disabled={!paymentMethodChoice}
>
{t('action.next', { ns: 'common' })}
</Button>
),
)
}

export type PricingProps = {
Expand Down Expand Up @@ -484,6 +512,7 @@ const Pricing = ({
const { address } = useAccountSafely()
const { data: balance } = useBalance({ address })
const resolverAddress = useContractAddress({ contract: 'ensPublicResolver' })
const { data: ethPrice } = useEthPrice()

const [seconds, setSeconds] = useState(() => registrationData.seconds ?? ONE_YEAR)

Expand Down Expand Up @@ -535,6 +564,8 @@ const Pricing = ({
const totalRequiredBalance = durationRequiredBalance
? durationRequiredBalance + (premiumFee || 0n) + (estimatedGasFee || 0n)
: 0n
const estimatedTotal =
(totalDurationBasedFee || 0n) + (premiumFee || 0n) + (estimatedGasFee || 0n)

const previousYearlyFee = usePreviousDistinct(yearlyFee) || 0n

Expand Down Expand Up @@ -594,6 +625,8 @@ const Pricing = ({
seconds,
balance,
totalRequiredBalance,
estimatedTotal,
ethPrice,
}}
/>
</MobileFullWidth>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Button, CountdownCircle, Dialog, Heading, mq, Spinner } from '@ensdomai
import MobileFullWidth from '@app/components/@atoms/MobileFullWidth'
import { Card } from '@app/components/Card'
import { useExistingCommitment } from '@app/hooks/registration/useExistingCommitment'
import { useRegistrationEventTracker } from '@app/hooks/useRegistrationEventTracker'
import useRegistrationParams from '@app/hooks/useRegistrationParams'
import { CenteredTypography } from '@app/transaction-flow/input/ProfileEditor/components/CenteredTypography'
import { createTransactionItem } from '@app/transaction-flow/transaction'
Expand Down Expand Up @@ -93,6 +94,7 @@ type Props = {

const Transactions = ({ registrationData, name, callback, onStart }: Props) => {
const { t } = useTranslation('register')
const { trackRegistrationEvent } = useRegistrationEventTracker()

const { address } = useAccount()
const keySuffix = `${name}-${address}`
Expand Down Expand Up @@ -140,6 +142,8 @@ const Transactions = ({ registrationData, name, callback, onStart }: Props) => {
autoClose: true,
resumeLink: `/register/${name}`,
})

trackRegistrationEvent('Finish started')
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

There's 2 register_started events. Can you double check if both are needed? This is why I suggested that we clear the events variable and check if the event has been called multiple times in registerName.spec.ts

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've analyzed the flow and determined the following:

  • If a user completes a commit transaction, the registerTx variable will be undefined.
    The makeRegisterNameFlow function will be called.

  • If the user refreshes the page, the registerTx variable will have a value, and the showRegisterTransaction function will be called.


const showCommitTransaction = () => {
Expand All @@ -148,6 +152,8 @@ const Transactions = ({ registrationData, name, callback, onStart }: Props) => {

const showRegisterTransaction = () => {
resumeTransactionFlow(registerKey)

trackRegistrationEvent('Finish started')
}

const resetTransactions = () => {
Expand Down
Loading
Loading