From 053e2cb769d0f0452f3c96dbc02711a140a5012c Mon Sep 17 00:00:00 2001 From: brdy <41711440+BrodyHughes@users.noreply.github.com> Date: Tue, 25 Jun 2024 06:01:09 -0500 Subject: [PATCH] stimmy analytics, additional ui fixes (#1596) Co-authored-by: Daniel Sinclair Co-authored-by: Christopher Howard --- src/analytics/event.ts | 56 +++++++++++++++++++ src/analytics/userProperties.ts | 10 ++++ src/core/raps/actions/claim.ts | 2 +- .../popup/pages/home/Points/ClaimOverview.tsx | 9 +-- .../popup/pages/home/Points/ClaimSheet.tsx | 16 +++++- .../pages/home/Points/PointsDashboard.tsx | 35 ++++++++---- static/json/languages/en_US.json | 2 +- 7 files changed, 111 insertions(+), 19 deletions(-) diff --git a/src/analytics/event.ts b/src/analytics/event.ts index b45a6307dd..818c70de5b 100644 --- a/src/analytics/event.ts +++ b/src/analytics/event.ts @@ -139,6 +139,33 @@ export const event = { * Called when a keyboard shortcut is triggered */ keyboardShortcutTriggered: 'keyboard.shortcut.triggered', + /** + * Called when user views the Leaderboard tab within Points + */ + pointsLeaderboardViewed: 'points.leaderboard.viewed', + /** + * Called when user copies their referral link + * within Points and tracks if it was a code or link + */ + pointsReferralCopied: 'points.referral.copied', + /** + * Called when user taps the claim button + * within the Points / Eth rewards screen + */ + pointsRewardsClaimButtonClicked: 'points.rewards.claim_button.clicked', + /** + * Called when user chooses which network to claim rewards on and the + * code to claim is executed within the Points / Eth rewards screen + */ + pointsRewardsClaimSubmitted: 'points.rewards.claim.submitted', + /** + * Called when user views the Rewards tab within Points + */ + pointsRewardsViewed: 'points.rewards.viewed', + /** + * Called when user views the Points tab + */ + pointsViewed: 'points.viewed', /** * Called when the popup entry is opened, including: * - extension popup @@ -549,6 +576,35 @@ export type EventProperties = { */ type: KeyboardEventDescription; }; + [event.pointsLeaderboardViewed]: undefined; + [event.pointsReferralCopied]: { + /** + * Was a `link` or `code` copied + */ + type: 'link' | 'code'; + }; + [event.pointsRewardsClaimButtonClicked]: { + /** + * Claim amount in ETH + */ + claimAmount: number; + }; + [event.pointsRewardsClaimSubmitted]: { + /** + * claim amount in ETH + */ + claimAmount: number; + /** + * claim amount in USD + */ + claimAmountUSD: number; + /** + * which network of the three possible was selected + */ + networkSelected: 'optimism' | 'base' | 'zora'; + }; + [event.pointsRewardsViewed]: undefined; + [event.pointsViewed]: undefined; [event.popupOpened]: undefined; [event.settingsAnalyticsTrackingDisabled]: undefined; [event.revokeSubmitted]: { diff --git a/src/analytics/userProperties.ts b/src/analytics/userProperties.ts index 2c8ed579e5..f36bf4a44d 100644 --- a/src/analytics/userProperties.ts +++ b/src/analytics/userProperties.ts @@ -1,13 +1,23 @@ // these can be reported separately so they must be optional export interface UserProperties { + // number of imported or generated accounts ownedAccounts?: number; + // number of accounts tied to paired hardware wallets hardwareAccounts?: number; + // number of watched addresses or ens watchedAccounts?: number; + // number of imported or generated secret recovery phrases recoveryPhrases?: number; + // number of imported secret recovery phrases importedRecoveryPhrases?: number; + // number of unique private keys privateKeys?: number; + // number of imported unique private keys importedPrivateKeys?: number; + // number of paired trezor hardware wallets trezorDevices?: number; + // number of paired ledger hardware wallets ledgerDevices?: number; + // whether a recovery phrase or private key has been imported hasImported?: boolean; } diff --git a/src/core/raps/actions/claim.ts b/src/core/raps/actions/claim.ts index 9532756bf9..e9fc59e762 100644 --- a/src/core/raps/actions/claim.ts +++ b/src/core/raps/actions/claim.ts @@ -22,7 +22,7 @@ export async function claim({ ? CLAIM_MOCK_DATA : await metadataPostClient.claimUserRewards({ address }); - // Checking ig we got the tx hash + // Checking if we got the tx hash const txHash = claimInfo.claimUserRewards?.txHash; if (!txHash) { // If there's no transaction hash the relayer didn't submit the transaction diff --git a/src/entries/popup/pages/home/Points/ClaimOverview.tsx b/src/entries/popup/pages/home/Points/ClaimOverview.tsx index 4fc1b83f6d..66564cf666 100644 --- a/src/entries/popup/pages/home/Points/ClaimOverview.tsx +++ b/src/entries/popup/pages/home/Points/ClaimOverview.tsx @@ -1,5 +1,5 @@ import { motion } from 'framer-motion'; -import { useEffect, useState } from 'react'; +import { memo, useEffect, useState } from 'react'; import { PointsErrorType } from '~/core/graphql/__generated__/metadata'; import { i18n } from '~/core/languages'; @@ -47,7 +47,7 @@ export function ClaimOverview({ const showSuccess = !waitToDisplay && success && preparingClaim && !error; useEffect(() => { - setTimeout(() => setWaitToDisplay(false), 3000); + setTimeout(() => setWaitToDisplay(false), 4000); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -186,7 +186,7 @@ function ErrorText({ error }: { error?: string }) { ); } -function RainbowSlant() { +const RainbowSlant = memo(function () { return ( @@ -208,7 +208,8 @@ function RainbowSlant() { ); -} +}); +RainbowSlant.displayName = 'RainbowSlant'; function ClaimSummary({ amount, price }: { amount: string; price: string }) { return ( diff --git a/src/entries/popup/pages/home/Points/ClaimSheet.tsx b/src/entries/popup/pages/home/Points/ClaimSheet.tsx index 2be9319f7c..171f2d7927 100644 --- a/src/entries/popup/pages/home/Points/ClaimSheet.tsx +++ b/src/entries/popup/pages/home/Points/ClaimSheet.tsx @@ -2,12 +2,14 @@ import { useMutation } from '@tanstack/react-query'; import { motion } from 'framer-motion'; import { useEffect, useState } from 'react'; +import { analytics } from '~/analytics'; +import { event } from '~/analytics/event'; import config from '~/core/firebase/remoteConfig'; import { i18n } from '~/core/languages'; import { RapClaimActionParameters } from '~/core/raps/references'; import { chainsLabel } from '~/core/references/chains'; import { useCurrentAddressStore, useCurrentCurrencyStore } from '~/core/state'; -import { ChainId } from '~/core/types/chains'; +import { ChainId, chainIdToNameMapping } from '~/core/types/chains'; import { GasSpeed } from '~/core/types/gas'; import { convertAmountAndPriceToNativeDisplay, @@ -149,7 +151,15 @@ export function ClaimSheet() { setSelectedChainId(chain); setInitialClaimableAmount(claimableBalance.amount); setInitialClaimableDisplay(claimablePriceDisplay.display); - setTimeout(() => claimRewards(), 500); + claimRewards(); + analytics.track(event.pointsRewardsClaimSubmitted, { + claimAmount: Number(claimableBalance.amount), + claimAmountUSD: Number(claimablePriceDisplay.display.slice(1)), + networkSelected: chainIdToNameMapping[chain] as + | 'optimism' + | 'zora' + | 'base', + }); }; const baseInfo = { @@ -170,7 +180,7 @@ export function ClaimSheet() { useEffect(() => { if (showSuccess && !showSummary) { - setTimeout(() => setShowSummary(true), 5000); + setTimeout(() => setShowSummary(true), 7000); } }, [showSuccess, showSummary]); diff --git a/src/entries/popup/pages/home/Points/PointsDashboard.tsx b/src/entries/popup/pages/home/Points/PointsDashboard.tsx index 93a58377ac..791ce4bc99 100644 --- a/src/entries/popup/pages/home/Points/PointsDashboard.tsx +++ b/src/entries/popup/pages/home/Points/PointsDashboard.tsx @@ -13,6 +13,8 @@ import { import { Address } from 'viem'; import rainbowIcon from 'static/images/icon-16@2x.png'; +import { analytics } from '~/analytics'; +import { event } from '~/analytics/event'; import { PointsQuery } from '~/core/graphql/__generated__/metadata'; import { i18n } from '~/core/languages'; import { useCurrentAddressStore, useCurrentCurrencyStore } from '~/core/state'; @@ -273,25 +275,28 @@ function TextWithMoreInfo({ children }: PropsWithChildren) { ); } -export const copyReferralLink = (referralCode: string) => +export const copyReferralLink = (referralCode: string) => { + analytics.track(event.pointsReferralCopied, { type: 'link' }); copy({ value: `https://rainbow.me/points?ref=${referralCode}`, title: i18n.t('points.copied_referral_link'), description: `rainbow.me/points?ref=${referralCode}`, }); +}; const formatReferralCode = (referralCode: string) => referralCode.slice(0, 3) + '-' + referralCode.slice(-3); function ReferralCode() { const { currentAddress } = useCurrentAddressStore(); const { data, isSuccess } = usePoints(currentAddress); - const copyReferralCode = () => + const copyReferralCode = () => { + analytics.track(event.pointsReferralCopied, { type: 'code' }); copy({ value: data?.user.referralCode || '', title: i18n.t('points.copied_referral_code'), description: formatReferralCode(data?.user.referralCode || ''), }); - + }; return ( @@ -716,7 +721,15 @@ function ClaimYourPointsCta({ whileTap={{ scale: 0.98 }} whileFocus={{ scale: 1.02 }} whileHover={{ scale: 1.02 }} - onClick={() => showClaimSheet()} + onClick={() => { + // TODO: Also track amount in USD + analytics.track(event.pointsRewardsClaimButtonClicked, { + claimAmount: Number( + convertRawAmountToDecimalFormat(claimableReward, 18), + ), + }); + showClaimSheet(); + }} > {i18n.t('points.rewards.claim_reward', { @@ -894,12 +907,6 @@ function MyEarnings({ earnings = '0' }: { earnings?: string }) { {i18n.t('points.rewards.my_earnings')} - @@ -1101,6 +1108,14 @@ export function PointsDashboard() { const [displayMode, setDisplayMode] = useState<'rewards' | 'leaderboard'>( 'rewards', ); + useEffect(() => { + if (displayMode === 'rewards') { + analytics.track(event.pointsRewardsViewed); + } else if (displayMode === 'leaderboard') { + analytics.track(event.pointsLeaderboardViewed); + } + analytics.track(event.pointsViewed); + }, [displayMode]); return ( <> Your reward is ready", "claim_complete": "> Claim Complete", "already_claimed": "> Your reward has already been claimed",