diff --git a/components/AccountBody.tsx b/components/AccountBody.tsx index 59c4780..ff506d2 100644 --- a/components/AccountBody.tsx +++ b/components/AccountBody.tsx @@ -38,6 +38,7 @@ import { CopyAlert } from './CopyAlert' import { ExpandBakerInfoTable } from './ExpandBakerInfoTable' import _ from 'lodash' import { DisabledStakeAlert } from '@/components/DisabledStakeAlert' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' const getNumOfUnstake = ( unstOps?: UnstakedOperation[], @@ -75,7 +76,8 @@ export const AccountBody = ({ title, message, opHash, - resetOperation + resetOperation, + opType } = useOperationResponse() const { @@ -160,6 +162,7 @@ export const AccountBody = ({ desc={message} tzktLink={`${process.env.NEXT_PUBLIC_TZKT_UI_URL}/${opHash}`} resetOperation={resetOperation} + opType={opType} /> )} { + trackGAEvent( + GAAction.BUTTON_CLICK, + GACategory.END_DELEGATE_BEGIN + ) endDelegateModal.onOpen() }} /> @@ -249,7 +256,15 @@ export const AccountBody = ({ {accountInfo?.type === 'user' && (stakingOpsStatus.Delegated ? ( - changeBakerModal.onOpen()} /> + { + trackGAEvent( + GAAction.BUTTON_CLICK, + GACategory.CHOOSE_CHANGE_BAKER + ) + changeBakerModal.onOpen() + }} + /> ) : ( ))} @@ -263,9 +278,9 @@ export const AccountBody = ({ fontWeight={600} lineHeight='18px' > - {accountInfo?.evaluatedDelegate.alias ?? + {accountInfo?.evaluatedDelegate?.alias ?? simplifyAddress( - accountInfo?.evaluatedDelegate.address ?? '' + accountInfo?.evaluatedDelegate?.address ?? '' )} delegateModal.onOpen()} + onClick={() => { + trackGAEvent( + GAAction.BUTTON_CLICK, + GACategory.CHOOSE_BAKER_START + ) + delegateModal.onOpen() + }} w='100%' > Select Baker @@ -322,7 +343,10 @@ export const AccountBody = ({ disabled={ stakingOpsStatus.Delegated && !stakingOpsStatus.CanUnstake } - onClick={() => unstakeModal.onOpen()} + onClick={() => { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.CHOOSE_UNSTAKE) + unstakeModal.onOpen() + }} w='100%' > Unstake @@ -332,7 +356,10 @@ export const AccountBody = ({ {stakingOpsStatus.Delegated && ( stakeModal.onOpen()} + onClick={() => { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.CHOOSE_STAKE) + stakeModal.onOpen() + }} w='100%' > Stake diff --git a/components/CookieBanner.tsx b/components/CookieBanner.tsx new file mode 100644 index 0000000..a5f8ea7 --- /dev/null +++ b/components/CookieBanner.tsx @@ -0,0 +1,115 @@ +import React, { useState, useEffect } from 'react' +import { + Flex, + Text, + Modal, + ModalOverlay, + ModalContent, + ModalBody, + Box, + Link as ChakraLink +} from '@chakra-ui/react' +import Link from 'next/link' +import { PrimaryButton } from './buttons/PrimaryButton' +import { SecondaryButton } from './buttons/SecondaryButton' +import Cookies from 'js-cookie' + +function injectGoogleAnalyticsScripts() { + const scriptTag1 = document.createElement('script') + scriptTag1.setAttribute('strategy', 'afterInteractive') + scriptTag1.setAttribute( + 'src', + 'https://www.googletagmanager.com/gtag/js?id=G-39LG2721KV' + ) + + const scriptTag2 = document.createElement('script') + scriptTag2.setAttribute('id', 'google-analytics') + scriptTag2.setAttribute('strategy', 'afterInteractive') + scriptTag2.innerHTML = ` + window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + gtag('config', 'G-39LG2721KV'); + ` + + document.head.appendChild(scriptTag1) + document.head.appendChild(scriptTag2) +} + +export const CookieBanner = () => { + const [isOpen, setIsOpen] = useState(false) + + useEffect(() => { + const consent = Cookies.get('cookie-consent') + if (!consent) { + setIsOpen(true) + } else if (consent === 'accepted') { + injectGoogleAnalyticsScripts() + } + }, []) + + const handleAccept = () => { + Cookies.set('cookie-consent', 'accepted', { expires: 365 }) + injectGoogleAnalyticsScripts() + setIsOpen(false) + } + + return ( + { + console.log('click') + }} + > + + + + + + We use cookies to make your experience better. + + + + Cookie Policy + + + + + handleAccept()}> + Accept Cookies + + handleAccept()}> + Necessary Only + + + + + + ) +} diff --git a/components/LoginModal.tsx b/components/LoginModal.tsx index 041a75a..69b0099 100644 --- a/components/LoginModal.tsx +++ b/components/LoginModal.tsx @@ -3,6 +3,7 @@ import { Box, Flex, Image, Text, FlexProps } from '@chakra-ui/react' import Link from 'next/link' import { PrimaryButton } from './buttons/PrimaryButton' import { useConnection } from '@/providers/ConnectionProvider' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' const STEPS = ['DELEGATE', 'STAKE', 'EARN'] @@ -46,7 +47,14 @@ export const LoginModal = () => { ))} - + { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.WALLET_BEGIN) + connect() + }} + > Connect Wallet diff --git a/components/SuccessModal.tsx b/components/SuccessModal.tsx index 193486e..2ebfc24 100644 --- a/components/SuccessModal.tsx +++ b/components/SuccessModal.tsx @@ -14,19 +14,36 @@ import { import { PrimaryButton } from './buttons/PrimaryButton' import Link from 'next/link' import { ExternalLinkIcon } from '@chakra-ui/icons' +import { OpType } from '@/providers/OperationResponseProvider' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' + +const setGAEvent = (opType?: OpType) => { + switch (opType) { + case 'delegate': + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.CONTINUE_AFTER_DELEGATION) + return + case 'stake': + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.CONTINUE_AFTER_STAKE) + return + default: + return + } +} export const SuccessModal = ({ title, desc, tzktLink, resetOperation, - open + open, + opType }: { title?: string desc: string tzktLink: string resetOperation: () => void open: boolean + opType?: OpType }) => { const { onClose } = useDisclosure() @@ -69,6 +86,7 @@ export const SuccessModal = ({ { + setGAEvent(opType) resetOperation() onClose() }} diff --git a/components/operationModals/ChangeBaker/index.tsx b/components/operationModals/ChangeBaker/index.tsx index ef865d0..774c5f9 100644 --- a/components/operationModals/ChangeBaker/index.tsx +++ b/components/operationModals/ChangeBaker/index.tsx @@ -68,6 +68,7 @@ export const ChangeBakerModal = ({ handleOneStepBack={handleOneStepBack} selectedBaker={selectedBaker as BakerInfo} setSelectedBaker={setSelectedBaker} + isChangeBaker={true} /> ) default: @@ -92,6 +93,7 @@ export const ChangeBakerModal = ({ handleOneStepBack={handleOneStepBack} selectedBaker={selectedBaker as BakerInfo} setSelectedBaker={setSelectedBaker} + isChangeBaker={true} /> ) default: diff --git a/components/operationModals/Delegate/BakerBox.tsx b/components/operationModals/Delegate/BakerBox.tsx index 1ff98ab..bbba9c1 100644 --- a/components/operationModals/Delegate/BakerBox.tsx +++ b/components/operationModals/Delegate/BakerBox.tsx @@ -6,6 +6,7 @@ import useClipboard from '@/utils/useClipboard' import { CopyAlert } from '@/components/CopyAlert' import { BakerInfo } from '@/components/Operations/tezInterfaces' import { mutezToTez } from '@/utils/mutezToTez' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' interface BakerBoxProps { baker: BakerInfo @@ -57,6 +58,10 @@ export const BakerBox = ({ { + trackGAEvent( + GAAction.BUTTON_CLICK, + GACategory.CHOOSE_BAKER_SUCCESS + ) setSelectedBaker(baker) handleOneStepForward() }} diff --git a/components/operationModals/Delegate/ConfirmBaker.tsx b/components/operationModals/Delegate/ConfirmBaker.tsx index bec46a3..03ac893 100644 --- a/components/operationModals/Delegate/ConfirmBaker.tsx +++ b/components/operationModals/Delegate/ConfirmBaker.tsx @@ -19,22 +19,26 @@ import { useConnection } from '@/providers/ConnectionProvider' import { setDelegate } from '@/components/Operations/operations' import { PrimaryButton } from '@/components/buttons/PrimaryButton' import { ErrorBlock } from '@/components/ErrorBlock' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' interface ChooseBakerProps { handleOneStepForward: () => void handleOneStepBack: () => void selectedBaker: BakerInfo setSelectedBaker: (b: null) => void + isChangeBaker?: boolean } export const ConfirmBaker = ({ handleOneStepForward, handleOneStepBack, selectedBaker, - setSelectedBaker + setSelectedBaker, + isChangeBaker }: ChooseBakerProps) => { const { Tezos, beaconWallet } = useConnection() - const { setMessage, setSuccess, setOpHash } = useOperationResponse() + const { setMessage, setSuccess, setOpHash, setOpType } = + useOperationResponse() const [errorMessage, setErrorMessage] = useState('') const [waitingOperation, setWaitingOperation] = useState(false) @@ -99,6 +103,7 @@ export const ConfirmBaker = ({ { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.START_DELEGATE_BEGIN) if (!Tezos || !beaconWallet) { setErrorMessage('Wallet is not initialized, log out to try again.') return @@ -116,7 +121,16 @@ export const ConfirmBaker = ({ ) setWaitingOperation(false) if (response.success) { + if (isChangeBaker) + trackGAEvent( + GAAction.BUTTON_CLICK, + GACategory.CHANGE_BAKER_SUCCESS + ) + else + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.START_DELEGATE_END) + setOpHash(response.opHash) + setOpType('delegate') setMessage( "You have successfully delegated your balance to the baker. If you'd like, you can now stake and potentially earn double rewards!" ) diff --git a/components/operationModals/Delegate/DelegateStart.tsx b/components/operationModals/Delegate/DelegateStart.tsx index 7b918bc..d9e99e3 100644 --- a/components/operationModals/Delegate/DelegateStart.tsx +++ b/components/operationModals/Delegate/DelegateStart.tsx @@ -2,6 +2,7 @@ import React from 'react' import { Image, Box, Flex, Text } from '@chakra-ui/react' import { PrimaryButton } from '@/components/buttons/PrimaryButton' import { Header, Description } from '@/components/modalBody' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' export const DelegateStart = ({ handleOneStepForward @@ -26,7 +27,14 @@ export const DelegateStart = ({ - Continue + { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.CONTINUE_DELEGATION) + handleOneStepForward() + }} + > + Continue + ) } diff --git a/components/operationModals/Delegate/index.tsx b/components/operationModals/Delegate/index.tsx index b8a76c2..8406ca4 100644 --- a/components/operationModals/Delegate/index.tsx +++ b/components/operationModals/Delegate/index.tsx @@ -14,6 +14,7 @@ import useCurrentStep from '@/utils/useCurrentStep' import { Stepper } from '@/components/modalBody/Stepper' import { BackIcon, CloseIcon } from '@/components/icons' import { ConfirmBaker } from './ConfirmBaker' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' export interface DelegateModalProps { isOpen: boolean @@ -99,6 +100,10 @@ export const DelegationModal = ({ /> { + trackGAEvent( + GAAction.BUTTON_CLICK, + GACategory.CHOOSE_BAKER_CLOSED + ) closeReset() onClose() }} diff --git a/components/operationModals/EndDelegate/ConfirmEndDelegate.tsx b/components/operationModals/EndDelegate/ConfirmEndDelegate.tsx index 6c8c7a1..5070fb2 100644 --- a/components/operationModals/EndDelegate/ConfirmEndDelegate.tsx +++ b/components/operationModals/EndDelegate/ConfirmEndDelegate.tsx @@ -6,6 +6,7 @@ import { useConnection } from '@/providers/ConnectionProvider' import { AddressBox, Header, ColumnHeader } from '@/components/modalBody' import { useOperationResponse } from '@/providers/OperationResponseProvider' import { ErrorBlock } from '@/components/ErrorBlock' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' interface ConfirmEndDelegate { spendableBalance: number @@ -39,6 +40,7 @@ export const ConfirmEndDelegate = ({ const response = await setDelegate(Tezos, undefined, beaconWallet) setWaitingOperation(false) if (response.success) { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.END_DELEGATE_END) setOpHash(response.opHash) setTitle('Delegation Ended!') setMessage( diff --git a/components/operationModals/FinalizeUnstake/ConfirmFinalizeUnstake.tsx b/components/operationModals/FinalizeUnstake/ConfirmFinalizeUnstake.tsx index 3f09326..652b1b9 100644 --- a/components/operationModals/FinalizeUnstake/ConfirmFinalizeUnstake.tsx +++ b/components/operationModals/FinalizeUnstake/ConfirmFinalizeUnstake.tsx @@ -6,6 +6,7 @@ import { useConnection } from '@/providers/ConnectionProvider' import { Header, BalanceBox, ColumnHeader } from '@/components/modalBody' import { useOperationResponse } from '@/providers/OperationResponseProvider' import { ErrorBlock } from '@/components/ErrorBlock' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' interface ConfirmFinalizeUnstake { withdrawAmount: number @@ -42,6 +43,7 @@ export const ConfirmFinalizeUnstake = ({ setWaitingOperation(false) if (response.success) { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.FINALIZE_END) setOpHash(response.opHash) setMessage( `You have successfully finalized ${withdrawAmount} ꜩ. These funds are now part of your spendable balance.` diff --git a/components/operationModals/FinalizeUnstake/UnstakeOperationBox.tsx b/components/operationModals/FinalizeUnstake/UnstakeOperationBox.tsx index 4b447e7..4773188 100644 --- a/components/operationModals/FinalizeUnstake/UnstakeOperationBox.tsx +++ b/components/operationModals/FinalizeUnstake/UnstakeOperationBox.tsx @@ -5,6 +5,7 @@ import { mutezToTez } from '@/utils/mutezToTez' import { TertiaryButton } from '@/components/buttons/TertiaryButton' import { FinalizeUnstakeModal } from '.' import Link from 'next/link' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' export const UnstakeOperationBox = ({ unstakeOp, @@ -101,7 +102,12 @@ export const UnstakeOperationBox = ({ )} {canFinalize && ( - finalizeUnstakeModal.onOpen()}> + { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.FINALIZE_BEGIN) + finalizeUnstakeModal.onOpen() + }} + > Finalize )} diff --git a/components/operationModals/Stake/SelectAmount.tsx b/components/operationModals/Stake/SelectAmount.tsx index d78ac84..116a74d 100644 --- a/components/operationModals/Stake/SelectAmount.tsx +++ b/components/operationModals/Stake/SelectAmount.tsx @@ -6,6 +6,7 @@ import { stake } from '@/components/Operations/operations' import { useConnection } from '@/providers/ConnectionProvider' import { useOperationResponse } from '@/providers/OperationResponseProvider' import { ErrorBlock } from '@/components/ErrorBlock' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' export const SelectAmount = ({ spendableBalance, @@ -19,12 +20,14 @@ export const SelectAmount = ({ stakedAmount: number }) => { const { Tezos, beaconWallet } = useConnection() - const { setMessage, setSuccess, setOpHash } = useOperationResponse() + const { setMessage, setSuccess, setOpHash, setOpType } = + useOperationResponse() const [errorMessage, setErrorMessage] = useState('') const [waitingOperation, setWaitingOperation] = useState(false) const handleChange = (event: any) => { const val = Number(event.target.value) + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.INPUT_AMOUNT) if (val <= spendableBalance) setStakedAmount(val) else if (val === 0) setStakedAmount(0) @@ -67,12 +70,16 @@ export const SelectAmount = ({ return } + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.START_STAKE_BEGIN) + setWaitingOperation(true) const response = await stake(Tezos, stakedAmount, beaconWallet) setWaitingOperation(false) if (response.success) { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.START_STAKE_END) setOpHash(response.opHash) + setOpType('stake') setMessage(`You have successfully staked ${stakedAmount} ꜩ`) setSuccess(true) setStakedAmount(0) diff --git a/components/operationModals/Stake/StakeStart.tsx b/components/operationModals/Stake/StakeStart.tsx index 542bb04..5fa630e 100644 --- a/components/operationModals/Stake/StakeStart.tsx +++ b/components/operationModals/Stake/StakeStart.tsx @@ -2,6 +2,7 @@ import React, { useState } from 'react' import { Flex, Text, Checkbox, Image } from '@chakra-ui/react' import { Header, Description } from '@/components/modalBody' import { PrimaryButton } from '@/components/buttons/PrimaryButton' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' export const StakeStart = ({ handleOneStepForward @@ -34,7 +35,10 @@ export const StakeStart = ({ > setIsChecked(!isChecked)} + onChange={() => { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.ACCEPT_DISCLAIMER) + setIsChecked(!isChecked) + }} /> - + { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.CONTINUE_STAKE) + handleOneStepForward() + }} + > Continue diff --git a/components/operationModals/Unstake/SelectAmount.tsx b/components/operationModals/Unstake/SelectAmount.tsx index 4c16fea..234d928 100644 --- a/components/operationModals/Unstake/SelectAmount.tsx +++ b/components/operationModals/Unstake/SelectAmount.tsx @@ -13,6 +13,7 @@ import { unstake } from '@/components/Operations/operations' import { useConnection } from '@/providers/ConnectionProvider' import { useOperationResponse } from '@/providers/OperationResponseProvider' import { ErrorBlock } from '@/components/ErrorBlock' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' export const SelectAmount = ({ stakedAmount, @@ -84,11 +85,14 @@ export const SelectAmount = ({ return } + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.END_STAKE_BEGIN) + setWaitingOperation(true) const response = await unstake(Tezos, unstakeAmount, beaconWallet) setWaitingOperation(false) if (response.success) { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.END_STAKE_END) setOpHash(response.opHash) setTitle('Unstake Requested') setMessage( diff --git a/components/operationModals/Unstake/UnstakeStart.tsx b/components/operationModals/Unstake/UnstakeStart.tsx index 260a71a..99b1c17 100644 --- a/components/operationModals/Unstake/UnstakeStart.tsx +++ b/components/operationModals/Unstake/UnstakeStart.tsx @@ -3,6 +3,7 @@ import { Flex, Image } from '@chakra-ui/react' import { Header, Description } from '@/components/modalBody' import { PrimaryButton } from '@/components/buttons/PrimaryButton' import { RoundBorderText } from '../Delegate/DelegateStart' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' export const UnstakeStart = ({ handleOneStepForward @@ -22,7 +23,14 @@ export const UnstakeStart = ({ - I Understand + { + trackGAEvent(GAAction.BUTTON_CLICK, GACategory.CHOOSE_I_UNDERSTAND) + handleOneStepForward() + }} + > + I Understand + ) } diff --git a/package.json b/package.json index cd4ebc8..a89470a 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "bufferutil": "^4.0.8", "date-fns": "^3.6.0", "framer-motion": "^11.2.0", + "js-cookie": "^3.0.5", "lodash": "^4.17.21", "next": "14.2.3", "pino-pretty": "^11.0.0", @@ -30,6 +31,7 @@ "utf-8-validate": "^6.0.4" }, "devDependencies": { + "@types/js-cookie": "^3", "@types/lodash": "^4", "@types/react": "^18", "@types/react-dom": "^18", diff --git a/pages/_document.tsx b/pages/_document.tsx index 23d501c..1f18aff 100644 --- a/pages/_document.tsx +++ b/pages/_document.tsx @@ -1,4 +1,5 @@ import { Html, Head, Main, NextScript } from 'next/document' +import Script from 'next/script' export default function Document() { return ( diff --git a/pages/index.tsx b/pages/index.tsx index 6eca78f..d76e5c5 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,4 +1,3 @@ -'use client' import { Center, Flex, Spinner } from '@chakra-ui/react' import { LoginModal } from '@/components/LoginModal' import { useEffect, useState } from 'react' @@ -14,6 +13,7 @@ import Head from 'next/head' import { BakerInfo } from '@/components/Operations/tezInterfaces' import { getBakerList } from '@/components/operationModals/Delegate' import { shuffleBakerList } from '@/components/operationModals/Delegate/ChooseBaker' +import { CookieBanner } from '@/components/CookieBanner' export interface DelegateData { address: string @@ -96,7 +96,7 @@ export default function Home() { return ( <> - Staking App | Tezos + Staking Tezos | Tezos @@ -154,6 +154,8 @@ export default function Home() { )} + + ) } diff --git a/providers/ConnectionProvider/index.tsx b/providers/ConnectionProvider/index.tsx index c7089c6..0eb5910 100644 --- a/providers/ConnectionProvider/index.tsx +++ b/providers/ConnectionProvider/index.tsx @@ -7,6 +7,8 @@ import { connectBeacon } from './beacon' import { BeaconWallet } from '@taquito/beacon-wallet' +import { trackGAEvent, GAAction, GACategory } from '@/utils/trackGAEvent' + interface ConnectionContextType extends Partial { connect: () => Promise disconnect: () => Promise @@ -67,9 +69,11 @@ export const ConnectionProvider = ({ children }: { children: any }) => { setTezos(Tezos) setBeaconWallet(beaconWallet) location.reload() + trackGAEvent(GAAction.CONNECT_SUCCESS, GACategory.WALLET_SUCCESS) }) .catch(() => { reset() + trackGAEvent(GAAction.CONNECT_ERROR, GACategory.WALLET_ERROR) throw new Error( 'Error connecting to wallet, please try again later' ) diff --git a/providers/OperationResponseProvider/index.tsx b/providers/OperationResponseProvider/index.tsx index f604138..5996d24 100644 --- a/providers/OperationResponseProvider/index.tsx +++ b/providers/OperationResponseProvider/index.tsx @@ -1,5 +1,13 @@ import React, { createContext, useContext, useState } from 'react' +export type OpType = + | 'delegate' + | 'end_delegate' + | 'change_baker' + | 'stake' + | 'unstake' + | 'finalize_unstake' + interface OperationResponseContextType { success: boolean setSuccess: (arg: boolean) => void @@ -10,6 +18,8 @@ interface OperationResponseContextType { message: string setMessage: (message: string) => void resetOperation: () => void + opType: OpType | undefined + setOpType: (arg: OpType) => void } const OperationResponseContext = createContext< @@ -31,12 +41,14 @@ export const OperationResponseProvider = ({ children }: { children: any }) => { const [title, setTitle] = useState('') const [success, setSuccess] = useState(false) const [opHash, setOpHash] = useState(undefined) + const [opType, setOpType] = useState(undefined) const resetOperation = () => { setMessage('') setTitle('') setSuccess(false) setOpHash(undefined) + setOpType(undefined) } return ( @@ -50,7 +62,9 @@ export const OperationResponseProvider = ({ children }: { children: any }) => { setTitle, message, setMessage, - resetOperation + resetOperation, + opType, + setOpType }} > {children} diff --git a/utils/trackGAEvent.ts b/utils/trackGAEvent.ts new file mode 100644 index 0000000..1d98d08 --- /dev/null +++ b/utils/trackGAEvent.ts @@ -0,0 +1,47 @@ +export enum GAAction { + BUTTON_CLICK = 'button_click', + CONNECT_SUCCESS = 'connect_success', + CONNECT_ERROR = 'connect_error' +} + +export enum GACategory { + WALLET_BEGIN = 'wallet_begin', + WALLET_SUCCESS = 'wallet_success', + WALLET_ERROR = 'wallet_error', + + CHOOSE_BAKER_START = 'choose_baker_start', + CONTINUE_DELEGATION = 'continue_delegation', + CHOOSE_BAKER_SUCCESS = 'choose_baker_succcess', + CHOOSE_BAKER_CLOSED = 'choose_baker_closed', + START_DELEGATE_BEGIN = 'start_delegate_begin', + START_DELEGATE_END = 'start_delegate_end', + CONTINUE_AFTER_DELEGATION = 'continue_after_delegation', + + CHOOSE_CHANGE_BAKER = 'choose_change_baker', + CHANGE_BAKER_SUCCESS = 'change_baker_success', + + END_DELEGATE_BEGIN = 'end_delegate_begin', + END_DELEGATE_END = 'end_delegate_end', + + CHOOSE_STAKE = 'choose_stake', + ACCEPT_DISCLAIMER = 'accept_disclaimer', + CONTINUE_STAKE = 'continue_stake', + INPUT_AMOUNT = 'input_amount', + START_STAKE_BEGIN = 'start_stake_begin', + START_STAKE_END = 'start_stake_end', + CONTINUE_AFTER_STAKE = 'continue_after_stake', + + CHOOSE_UNSTAKE = 'choose_unstake', + CHOOSE_I_UNDERSTAND = 'choose_i_understand', + END_STAKE_BEGIN = 'end_stake_begin', + END_STAKE_END = 'end_stake_end', + + FINALIZE_BEGIN = 'finalize_begin', + FINALIZE_END = 'finalize_end' +} + +export const trackGAEvent = (action: GAAction, category: GACategory) => { + ;(window as any)?.gtag('event', action, { + event_category: category + }) +} diff --git a/yarn.lock b/yarn.lock index 49da9ea..4bbd488 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2503,6 +2503,13 @@ __metadata: languageName: node linkType: hard +"@types/js-cookie@npm:^3": + version: 3.0.6 + resolution: "@types/js-cookie@npm:3.0.6" + checksum: 10c0/173afaf5ea9d86c22395b9d2a00b6adb0006dcfef165d6dcb0395cdc32f5a5dcf9c3c60f97194119963a15849b8f85121e1ae730b03e40bc0c29b84396ba22f9 + languageName: node + linkType: hard + "@types/json5@npm:^0.0.29": version: 0.0.29 resolution: "@types/json5@npm:0.0.29" @@ -5563,6 +5570,13 @@ __metadata: languageName: node linkType: hard +"js-cookie@npm:^3.0.5": + version: 3.0.5 + resolution: "js-cookie@npm:3.0.5" + checksum: 10c0/04a0e560407b4489daac3a63e231d35f4e86f78bff9d792011391b49c59f721b513411cd75714c418049c8dc9750b20fcddad1ca5a2ca616c3aca4874cce5b3a + languageName: node + linkType: hard + "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -7344,6 +7358,7 @@ __metadata: "@taquito/beacon-wallet": "npm:^20.0.0-beta.1" "@taquito/rpc": "npm:^20.0.0-beta.1" "@taquito/taquito": "npm:^20.0.0-beta.1" + "@types/js-cookie": "npm:^3" "@types/lodash": "npm:^4" "@types/react": "npm:^18" "@types/react-dom": "npm:^18" @@ -7353,6 +7368,7 @@ __metadata: eslint: "npm:^8" eslint-config-next: "npm:14.2.3" framer-motion: "npm:^11.2.0" + js-cookie: "npm:^3.0.5" lodash: "npm:^4.17.21" next: "npm:14.2.3" pino-pretty: "npm:^11.0.0"