* tracking helper functions

* track everything

* remove extraneous code
This commit is contained in:
mantikoros 2022-06-15 16:34:34 -05:00 committed by GitHub
parent 730b7272ce
commit c45da8c334
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 142 additions and 28 deletions

View File

@ -61,7 +61,7 @@ export function AddFundsButton(props: { className?: string }) {
> >
<button <button
type="submit" type="submit"
className="btn btn-primary bg-gradient-to-r from-teal-500 to-green-500 px-10 font-medium hover:from-teal-600 hover:to-green-600" className="btn btn-primary bg-gradient-to-r from-indigo-500 to-blue-500 px-10 font-medium hover:from-indigo-600 hover:to-blue-600"
> >
Checkout Checkout
</button> </button>

View File

@ -22,9 +22,9 @@ import {
calculateDpmPayoutAfterCorrectBet, calculateDpmPayoutAfterCorrectBet,
getDpmOutcomeProbabilityAfterBet, getDpmOutcomeProbabilityAfterBet,
} from 'common/calculate-dpm' } from 'common/calculate-dpm'
import { firebaseLogin } from 'web/lib/firebase/users'
import { Bet } from 'common/bet' import { Bet } from 'common/bet'
import { track } from 'web/lib/service/analytics' import { track } from 'web/lib/service/analytics'
import { SignUpPrompt } from '../sign-up-prompt'
export function AnswerBetPanel(props: { export function AnswerBetPanel(props: {
answer: Answer answer: Answer
@ -183,12 +183,7 @@ export function AnswerBetPanel(props: {
{isSubmitting ? 'Submitting...' : 'Submit trade'} {isSubmitting ? 'Submitting...' : 'Submit trade'}
</button> </button>
) : ( ) : (
<button <SignUpPrompt />
className="btn self-stretch whitespace-nowrap border-none bg-gradient-to-r from-teal-500 to-green-500 px-10 text-lg font-medium normal-case hover:from-teal-600 hover:to-green-600"
onClick={firebaseLogin}
>
Sign up to bet!
</button>
)} )}
</Col> </Col>
) )

View File

@ -22,6 +22,7 @@ import {
import { firebaseLogin } from 'web/lib/firebase/users' import { firebaseLogin } from 'web/lib/firebase/users'
import { Bet } from 'common/bet' import { Bet } from 'common/bet'
import { MAX_ANSWER_LENGTH } from 'common/answer' import { MAX_ANSWER_LENGTH } from 'common/answer'
import { withTracking } from 'web/lib/service/analytics'
export function CreateAnswerPanel(props: { contract: FreeResponseContract }) { export function CreateAnswerPanel(props: { contract: FreeResponseContract }) {
const { contract } = props const { contract } = props
@ -143,7 +144,7 @@ export function CreateAnswerPanel(props: { contract: FreeResponseContract }) {
isSubmitting && 'loading' isSubmitting && 'loading'
)} )}
disabled={!canSubmit} disabled={!canSubmit}
onClick={submitAnswer} onClick={withTracking(submitAnswer, 'submit answer')}
> >
Submit answer & buy Submit answer & buy
</button> </button>
@ -151,7 +152,7 @@ export function CreateAnswerPanel(props: { contract: FreeResponseContract }) {
text && ( text && (
<button <button
className="btn self-end whitespace-nowrap border-none bg-gradient-to-r from-teal-500 to-green-500 px-10 text-lg font-medium normal-case hover:from-teal-600 hover:to-green-600" className="btn self-end whitespace-nowrap border-none bg-gradient-to-r from-teal-500 to-green-500 px-10 text-lg font-medium normal-case hover:from-teal-600 hover:to-green-600"
onClick={firebaseLogin} onClick={withTracking(firebaseLogin, 'answer panel sign in')}
> >
Sign in Sign in
</button> </button>

View File

@ -26,6 +26,8 @@ import { EditCategoriesButton } from './feed/category-selector'
import { CATEGORIES } from 'common/categories' import { CATEGORIES } from 'common/categories'
import { Tabs } from './layout/tabs' import { Tabs } from './layout/tabs'
import { EditFollowingButton } from './following-button' import { EditFollowingButton } from './following-button'
import { track } from '@amplitude/analytics-browser'
import { trackCallback } from 'web/lib/service/analytics'
const searchClient = algoliasearch( const searchClient = algoliasearch(
'GJQPAYENIF', 'GJQPAYENIF',
@ -129,11 +131,13 @@ export function ContractSearch(props: {
input: '!pl-10 !input !input-bordered shadow-none w-[100px]', input: '!pl-10 !input !input-bordered shadow-none w-[100px]',
resetIcon: 'mt-2 hidden sm:flex', resetIcon: 'mt-2 hidden sm:flex',
}} }}
onBlur={trackCallback('search')}
/> />
<select <select
className="!select !select-bordered" className="!select !select-bordered"
value={filter} value={filter}
onChange={(e) => setFilter(e.target.value as filter)} onChange={(e) => setFilter(e.target.value as filter)}
onBlur={trackCallback('select search filter')}
> >
<option value="open">Open</option> <option value="open">Open</option>
<option value="closed">Closed</option> <option value="closed">Closed</option>
@ -145,6 +149,7 @@ export function ContractSearch(props: {
classNames={{ classNames={{
select: '!select !select-bordered', select: '!select !select-bordered',
}} }}
onBlur={trackCallback('select search sort')}
/> />
<Configure <Configure
facetFilters={filters} facetFilters={filters}
@ -296,7 +301,11 @@ function CategoryFollowSelector(props: {
] ]
: []), : []),
]} ]}
onClick={(_, index) => setMode(index === 0 ? 'categories' : 'following')} onClick={(_, index) => {
const mode = index === 0 ? 'categories' : 'following'
setMode(mode)
track(`click ${mode} tab`)
}}
/> />
) )
} }

View File

@ -22,6 +22,8 @@ import { getExpectedValue, getValueFromBucket } from 'common/calculate-dpm'
import { QuickBet, ProbBar, getColor } from './quick-bet' import { QuickBet, ProbBar, getColor } from './quick-bet'
import { useContractWithPreload } from 'web/hooks/use-contract' import { useContractWithPreload } from 'web/hooks/use-contract'
import { useUser } from 'web/hooks/use-user' import { useUser } from 'web/hooks/use-user'
import { track } from '@amplitude/analytics-browser'
import { trackCallback } from 'web/lib/service/analytics'
export function ContractCard(props: { export function ContractCard(props: {
contract: Contract contract: Contract
@ -71,12 +73,22 @@ export function ContractCard(props: {
if (e.ctrlKey || e.metaKey) return if (e.ctrlKey || e.metaKey) return
e.preventDefault() e.preventDefault()
track('click market card', {
slug: contract.slug,
contractId: contract.id,
})
onClick() onClick()
}} }}
/> />
) : ( ) : (
<Link href={contractPath(contract)}> <Link href={contractPath(contract)}>
<a className="absolute top-0 left-0 right-0 bottom-0" /> <a
onClick={trackCallback('click market card', {
slug: contract.slug,
contractId: contract.id,
})}
className="absolute top-0 left-0 right-0 bottom-0"
/>
</Link> </Link>
)} )}
</div> </div>

View File

@ -2,11 +2,13 @@ import React, { Fragment } from 'react'
import { LinkIcon } from '@heroicons/react/outline' import { LinkIcon } from '@heroicons/react/outline'
import { Menu, Transition } from '@headlessui/react' import { Menu, Transition } from '@headlessui/react'
import clsx from 'clsx' import clsx from 'clsx'
import { Contract } from 'common/contract' import { Contract } from 'common/contract'
import { copyToClipboard } from 'web/lib/util/copy' import { copyToClipboard } from 'web/lib/util/copy'
import { contractPath } from 'web/lib/firebase/contracts' import { contractPath } from 'web/lib/firebase/contracts'
import { ENV_CONFIG } from 'common/envs/constants' import { ENV_CONFIG } from 'common/envs/constants'
import { ToastClipboard } from 'web/components/toast-clipboard' import { ToastClipboard } from 'web/components/toast-clipboard'
import { track } from 'web/lib/service/analytics'
function copyContractUrl(contract: Contract) { function copyContractUrl(contract: Contract) {
copyToClipboard(`https://${ENV_CONFIG.domain}${contractPath(contract)}`) copyToClipboard(`https://${ENV_CONFIG.domain}${contractPath(contract)}`)
@ -23,7 +25,10 @@ export function CopyLinkButton(props: {
<Menu <Menu
as="div" as="div"
className="relative z-10 flex-shrink-0" className="relative z-10 flex-shrink-0"
onMouseUp={() => copyContractUrl(contract)} onMouseUp={() => {
copyContractUrl(contract)
track('copy share link')
}}
> >
<Menu.Button <Menu.Button
className={clsx( className={clsx(

View File

@ -9,6 +9,7 @@ import { Col } from '../layout/col'
import { useState } from 'react' import { useState } from 'react'
import { updateUser, User } from 'web/lib/firebase/users' import { updateUser, User } from 'web/lib/firebase/users'
import { Checkbox } from '../checkbox' import { Checkbox } from '../checkbox'
import { track } from 'web/lib/service/analytics'
export function CategorySelector(props: { export function CategorySelector(props: {
category: string category: string
@ -93,7 +94,10 @@ export function EditCategoriesButton(props: {
className, className,
'btn btn-sm btn-ghost cursor-pointer gap-2 whitespace-nowrap text-sm normal-case text-gray-700' 'btn btn-sm btn-ghost cursor-pointer gap-2 whitespace-nowrap text-sm normal-case text-gray-700'
)} )}
onClick={() => setIsOpen(true)} onClick={() => {
setIsOpen(true)
track('edit categories button')
}}
> >
<PencilIcon className="inline h-4 w-4" /> <PencilIcon className="inline h-4 w-4" />
Categories Categories

View File

@ -24,6 +24,7 @@ import { Col } from 'web/components/layout/col'
import { getProbability } from 'common/calculate' import { getProbability } from 'common/calculate'
import { LoadingIndicator } from 'web/components/loading-indicator' import { LoadingIndicator } from 'web/components/loading-indicator'
import { PaperAirplaneIcon } from '@heroicons/react/outline' import { PaperAirplaneIcon } from '@heroicons/react/outline'
import { track } from 'web/lib/service/analytics'
export function FeedCommentThread(props: { export function FeedCommentThread(props: {
contract: Contract contract: Contract
@ -354,6 +355,7 @@ export function CommentInput(props: {
async function submitComment(betId: string | undefined) { async function submitComment(betId: string | undefined) {
if (!user) { if (!user) {
track('sign in to comment')
return await firebaseLogin() return await firebaseLogin()
} }
if (!comment || isSubmitting) return if (!comment || isSubmitting) return

View File

@ -2,6 +2,7 @@ import clsx from 'clsx'
import { useFollows } from 'web/hooks/use-follows' import { useFollows } from 'web/hooks/use-follows'
import { useUser } from 'web/hooks/use-user' import { useUser } from 'web/hooks/use-user'
import { follow, unfollow } from 'web/lib/firebase/users' import { follow, unfollow } from 'web/lib/firebase/users'
import { withTracking } from 'web/lib/service/analytics'
export function FollowButton(props: { export function FollowButton(props: {
isFollowing: boolean | undefined isFollowing: boolean | undefined
@ -34,7 +35,7 @@ export function FollowButton(props: {
small && smallStyle, small && smallStyle,
className className
)} )}
onClick={onUnfollow} onClick={withTracking(onUnfollow, 'unfollow')}
> >
Following Following
</button> </button>
@ -44,7 +45,7 @@ export function FollowButton(props: {
return ( return (
<button <button
className={clsx('btn btn-sm', small && smallStyle, className)} className={clsx('btn btn-sm', small && smallStyle, className)}
onClick={onFollow} onClick={withTracking(onFollow, 'follow')}
> >
Follow Follow
</button> </button>

View File

@ -1,5 +1,6 @@
import clsx from 'clsx' import clsx from 'clsx'
import { PencilIcon } from '@heroicons/react/outline' import { PencilIcon } from '@heroicons/react/outline'
import { User } from 'common/user' import { User } from 'common/user'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useFollowers, useFollows } from 'web/hooks/use-follows' import { useFollowers, useFollows } from 'web/hooks/use-follows'
@ -10,6 +11,7 @@ import { Modal } from './layout/modal'
import { Tabs } from './layout/tabs' import { Tabs } from './layout/tabs'
import { useDiscoverUsers } from 'web/hooks/use-users' import { useDiscoverUsers } from 'web/hooks/use-users'
import { TextButton } from './text-button' import { TextButton } from './text-button'
import { track } from 'web/lib/service/analytics'
export function FollowingButton(props: { user: User }) { export function FollowingButton(props: { user: User }) {
const { user } = props const { user } = props
@ -48,7 +50,10 @@ export function EditFollowingButton(props: { user: User; className?: string }) {
className, className,
'btn btn-sm btn-ghost cursor-pointer gap-2 whitespace-nowrap text-sm normal-case text-gray-700' 'btn btn-sm btn-ghost cursor-pointer gap-2 whitespace-nowrap text-sm normal-case text-gray-700'
)} )}
onClick={() => setIsOpen(true)} onClick={() => {
setIsOpen(true)
track('edit following button')
}}
> >
<PencilIcon className="inline h-4 w-4" /> <PencilIcon className="inline h-4 w-4" />
Following Following

View File

@ -12,6 +12,7 @@ import { Tabs } from './layout/tabs'
import { NoLabel, YesLabel } from './outcome-label' import { NoLabel, YesLabel } from './outcome-label'
import { Col } from './layout/col' import { Col } from './layout/col'
import { InfoTooltip } from './info-tooltip' import { InfoTooltip } from './info-tooltip'
import { track } from 'web/lib/service/analytics'
export function LiquidityPanel(props: { contract: CPMMContract }) { export function LiquidityPanel(props: { contract: CPMMContract }) {
const { contract } = props const { contract } = props
@ -57,7 +58,7 @@ export function LiquidityPanel(props: { contract: CPMMContract }) {
function AddLiquidityPanel(props: { contract: CPMMContract }) { function AddLiquidityPanel(props: { contract: CPMMContract }) {
const { contract } = props const { contract } = props
const { id: contractId } = contract const { id: contractId, slug } = contract
const user = useUser() const user = useUser()
@ -99,6 +100,8 @@ function AddLiquidityPanel(props: { contract: CPMMContract }) {
} }
}) })
.catch((_) => setError('Server error')) .catch((_) => setError('Server error'))
track('add liquidity', { amount, contractId, slug })
} }
return ( return (
@ -177,6 +180,8 @@ function WithdrawLiquidityPanel(props: {
setIsLoading(false) setIsLoading(false)
}) })
.catch((_) => setError('Server error')) .catch((_) => setError('Server error'))
track('withdraw liquidity')
} }
if (isSuccess) if (isSuccess)

View File

@ -17,6 +17,7 @@ import clsx from 'clsx'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import NotificationsIcon from 'web/components/notifications-icon' import NotificationsIcon from 'web/components/notifications-icon'
import { useIsIframe } from 'web/hooks/use-is-iframe' import { useIsIframe } from 'web/hooks/use-is-iframe'
import { trackCallback } from 'web/lib/service/analytics'
function getNavigation(username: string) { function getNavigation(username: string) {
return [ return [
@ -106,6 +107,7 @@ function NavBarItem(props: { item: Item; currentPage: string }) {
'block w-full py-1 px-3 text-center hover:bg-indigo-200 hover:text-indigo-700', 'block w-full py-1 px-3 text-center hover:bg-indigo-200 hover:text-indigo-700',
currentPage === item.href && 'bg-gray-200 text-indigo-700' currentPage === item.href && 'bg-gray-200 text-indigo-700'
)} )}
onClick={trackCallback('navbar: ' + item.name)}
> >
<item.icon className="my-1 mx-auto h-6 w-6" /> <item.icon className="my-1 mx-auto h-6 w-6" />
{item.name} {item.name}

View File

@ -1,13 +1,18 @@
import Link from 'next/link' import Link from 'next/link'
import { User } from 'web/lib/firebase/users' import { User } from 'web/lib/firebase/users'
import { formatMoney } from 'common/util/format' import { formatMoney } from 'common/util/format'
import { Avatar } from '../avatar' import { Avatar } from '../avatar'
import { trackCallback } from 'web/lib/service/analytics'
export function ProfileSummary(props: { user: User }) { export function ProfileSummary(props: { user: User }) {
const { user } = props const { user } = props
return ( return (
<Link href={`/${user.username}`}> <Link href={`/${user.username}`}>
<a className="group flex flex-row items-center gap-4 rounded-md py-3 text-gray-500 hover:bg-gray-100 hover:text-gray-700"> <a
onClick={trackCallback('sidebar: profile')}
className="group flex flex-row items-center gap-4 rounded-md py-3 text-gray-500 hover:bg-gray-100 hover:text-gray-700"
>
<Avatar avatarUrl={user.avatarUrl} username={user.username} noLink /> <Avatar avatarUrl={user.avatarUrl} username={user.username} noLink />
<div className="truncate"> <div className="truncate">

View File

@ -26,6 +26,7 @@ import { Row } from '../layout/row'
import NotificationsIcon from 'web/components/notifications-icon' import NotificationsIcon from 'web/components/notifications-icon'
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { IS_PRIVATE_MANIFOLD } from 'common/envs/constants' import { IS_PRIVATE_MANIFOLD } from 'common/envs/constants'
import { trackCallback, withTracking } from 'web/lib/service/analytics'
// Create an icon from the url of an image // Create an icon from the url of an image
function IconFromUrl(url: string): React.ComponentType<{ className?: string }> { function IconFromUrl(url: string): React.ComponentType<{ className?: string }> {
@ -125,6 +126,7 @@ function SidebarItem(props: { item: Item; currentPage: string }) {
return ( return (
<Link href={item.href} key={item.name}> <Link href={item.href} key={item.name}>
<a <a
onClick={trackCallback('sidebar: ' + item.name)}
className={clsx( className={clsx(
item.href == currentPage item.href == currentPage
? 'bg-gray-200 text-gray-900' ? 'bg-gray-200 text-gray-900'
@ -216,7 +218,11 @@ export default function Sidebar(props: { className?: string }) {
{user && ( {user && (
<MenuButton <MenuButton
menuItems={[ menuItems={[
{ name: 'Sign out', href: '#', onClick: () => firebaseLogout() }, {
name: 'Sign out',
href: '#',
onClick: withTracking(firebaseLogout, 'sign out'),
},
]} ]}
buttonContent={<MoreButton />} buttonContent={<MoreButton />}
/> />
@ -237,13 +243,16 @@ export default function Sidebar(props: { className?: string }) {
<div className={'aligncenter flex justify-center'}> <div className={'aligncenter flex justify-center'}>
{user ? ( {user ? (
<Link href={'/create'} passHref> <Link href={'/create'} passHref>
<button className={clsx(gradient, buttonStyle)}> <button
className={clsx(gradient, buttonStyle)}
onClick={trackCallback('create question button')}
>
Create a question Create a question
</button> </button>
</Link> </Link>
) : ( ) : (
<button <button
onClick={firebaseLogin} onClick={withTracking(firebaseLogin, 'sign in')}
className={clsx(gradient, buttonStyle)} className={clsx(gradient, buttonStyle)}
> >
Sign in Sign in

View File

@ -1,11 +1,13 @@
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
import { CodeIcon } from '@heroicons/react/outline' import { CodeIcon } from '@heroicons/react/outline'
import { Menu, Transition } from '@headlessui/react' import { Menu, Transition } from '@headlessui/react'
import { Contract } from 'common/contract' import { Contract } from 'common/contract'
import { contractPath } from 'web/lib/firebase/contracts' import { contractPath } from 'web/lib/firebase/contracts'
import { DOMAIN } from 'common/envs/constants' import { DOMAIN } from 'common/envs/constants'
import { copyToClipboard } from 'web/lib/util/copy' import { copyToClipboard } from 'web/lib/util/copy'
import { ToastClipboard } from 'web/components/toast-clipboard' import { ToastClipboard } from 'web/components/toast-clipboard'
import { track } from 'web/lib/service/analytics'
function copyEmbedCode(contract: Contract) { function copyEmbedCode(contract: Contract) {
const title = contract.question const title = contract.question
@ -26,7 +28,10 @@ export function ShareEmbedButton(props: {
<Menu <Menu
as="div" as="div"
className="relative z-10 flex-shrink-0" className="relative z-10 flex-shrink-0"
onMouseUp={() => copyEmbedCode(contract)} onMouseUp={() => {
copyEmbedCode(contract)
track('copy embed code')
}}
> >
<Menu.Button <Menu.Button
className="btn btn-xs normal-case" className="btn btn-xs normal-case"

View File

@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import { useUser } from 'web/hooks/use-user' import { useUser } from 'web/hooks/use-user'
import { firebaseLogin } from 'web/lib/firebase/users' import { firebaseLogin } from 'web/lib/firebase/users'
import { withTracking } from 'web/lib/service/analytics'
export function SignUpPrompt() { export function SignUpPrompt() {
const user = useUser() const user = useUser()
@ -8,7 +9,7 @@ export function SignUpPrompt() {
return user === null ? ( return user === null ? (
<button <button
className="btn flex-1 whitespace-nowrap border-none bg-gradient-to-r from-teal-500 to-green-500 px-10 text-lg font-medium normal-case hover:from-teal-600 hover:to-green-600" className="btn flex-1 whitespace-nowrap border-none bg-gradient-to-r from-teal-500 to-green-500 px-10 text-lg font-medium normal-case hover:from-teal-600 hover:to-green-600"
onClick={firebaseLogin} onClick={withTracking(firebaseLogin, 'sign up to bet')}
> >
Sign up to bet! Sign up to bet!
</button> </button>

View File

@ -6,6 +6,7 @@ import { Col } from './layout/col'
import { Row } from './layout/row' import { Row } from './layout/row'
import { TagsList } from './tags-list' import { TagsList } from './tags-list'
import { MAX_TAG_LENGTH } from 'common/contract' import { MAX_TAG_LENGTH } from 'common/contract'
import { track } from 'web/lib/service/analytics'
export function TagsInput(props: { contract: Contract; className?: string }) { export function TagsInput(props: { contract: Contract; className?: string }) {
const { contract, className } = props const { contract, className } = props
@ -24,6 +25,7 @@ export function TagsInput(props: { contract: Contract; className?: string }) {
}) })
setIsSubmitting(false) setIsSubmitting(false)
setTagText('') setTagText('')
track('save tags')
} }
return ( return (

View File

@ -1,4 +1,5 @@
import clsx from 'clsx' import clsx from 'clsx'
import { trackCallback } from 'web/lib/service/analytics'
export function TweetButton(props: { className?: string; tweetText: string }) { export function TweetButton(props: { className?: string; tweetText: string }) {
const { tweetText, className } = props const { tweetText, className } = props
@ -12,6 +13,7 @@ export function TweetButton(props: { className?: string; tweetText: string }) {
color: '#1da1f2', color: '#1da1f2',
}} }}
href={getTweetHref(tweetText)} href={getTweetHref(tweetText)}
onClick={trackCallback('share tweet')}
target="_blank" target="_blank"
> >
<img className="mr-2" src={'/twitter-logo.svg'} width={15} height={15} /> <img className="mr-2" src={'/twitter-logo.svg'} width={15} height={15} />

View File

@ -0,0 +1,8 @@
import { track } from '@amplitude/analytics-browser'
import { useEffect } from 'react'
export const useTracking = (eventName: string, eventProperties?: any) => {
useEffect(() => {
track(eventName, eventProperties)
}, [])
}

View File

@ -12,15 +12,24 @@ init(ENV_CONFIG.amplitudeApiKey ?? '', undefined, { includeReferrer: true })
export { track } export { track }
// convenience function // Convenience functions:
export const trackCallback =
(eventName: string, eventProperties?: any) => () => {
track(eventName, eventProperties)
}
export const withTracking = export const withTracking =
( (
f: (() => void) | (() => Promise<void>), f: (() => void) | (() => Promise<void>),
eventName: string, eventName: string,
eventProperties?: any eventProperties?: any
) => ) =>
() => async () => {
Promise.all([f(), track(eventName, eventProperties).promise]) const promise = f()
track(eventName, eventProperties)
await promise
}
export async function identifyUser(userId: string) { export async function identifyUser(userId: string) {
setUserId(userId) setUserId(userId)

View File

@ -40,6 +40,7 @@ import { useIsIframe } from 'web/hooks/use-is-iframe'
import ContractEmbedPage from '../embed/[username]/[contractSlug]' import ContractEmbedPage from '../embed/[username]/[contractSlug]'
import { useBets } from 'web/hooks/use-bets' import { useBets } from 'web/hooks/use-bets'
import { AlertBox } from 'web/components/alert-box' import { AlertBox } from 'web/components/alert-box'
import { useTracking } from 'web/hooks/use-tracking'
export const getStaticProps = fromPropz(getStaticPropz) export const getStaticProps = fromPropz(getStaticPropz)
export async function getStaticPropz(props: { export async function getStaticPropz(props: {
@ -108,6 +109,12 @@ export function ContractPageContent(
const contract = useContractWithPreload(props.contract) ?? props.contract const contract = useContractWithPreload(props.contract) ?? props.contract
useTracking('view market', {
slug: contract.slug,
contractId: contract.id,
creatorId: contract.creatorId,
})
const bets = useBets(contract.id) ?? props.bets const bets = useBets(contract.id) ?? props.bets
// Sort for now to see if bug is fixed. // Sort for now to see if bug is fixed.
comments.sort((c1, c2) => c1.createdTime - c2.createdTime) comments.sort((c1, c2) => c1.createdTime - c2.createdTime)

View File

@ -5,6 +5,7 @@ import { getUserByUsername, User } from 'web/lib/firebase/users'
import { UserPage } from 'web/components/user-page' import { UserPage } from 'web/components/user-page'
import { useUser } from 'web/hooks/use-user' import { useUser } from 'web/hooks/use-user'
import Custom404 from '../404' import Custom404 from '../404'
import { useTracking } from 'web/hooks/use-tracking'
export default function UserProfile(props: { export default function UserProfile(props: {
tab?: 'markets' | 'comments' | 'bets' tab?: 'markets' | 'comments' | 'bets'
@ -12,6 +13,7 @@ export default function UserProfile(props: {
const router = useRouter() const router = useRouter()
const [user, setUser] = useState<User | null | 'loading'>('loading') const [user, setUser] = useState<User | null | 'loading'>('loading')
const { username } = router.query as { username: string } const { username } = router.query as { username: string }
useEffect(() => { useEffect(() => {
if (username) { if (username) {
getUserByUsername(username).then(setUser) getUserByUsername(username).then(setUser)
@ -20,6 +22,8 @@ export default function UserProfile(props: {
const currentUser = useUser() const currentUser = useUser()
useTracking('view user profile', { username })
if (user === 'loading') return <></> if (user === 'loading') return <></>
return user ? ( return user ? (

View File

@ -6,6 +6,8 @@ import { FundsSelector } from 'web/components/yes-no-selector'
import { useUser } from 'web/hooks/use-user' import { useUser } from 'web/hooks/use-user'
import { checkoutURL } from 'web/lib/service/stripe' import { checkoutURL } from 'web/lib/service/stripe'
import { Page } from 'web/components/page' import { Page } from 'web/components/page'
import { useTracking } from 'web/hooks/use-tracking'
import { trackCallback } from 'web/lib/service/analytics'
export default function AddFundsPage() { export default function AddFundsPage() {
const user = useUser() const user = useUser()
@ -14,6 +16,8 @@ export default function AddFundsPage() {
2500 2500
) )
useTracking('view add funds')
return ( return (
<Page> <Page>
<SEO <SEO
@ -59,6 +63,7 @@ export default function AddFundsPage() {
<button <button
type="submit" type="submit"
className="btn btn-primary w-full bg-gradient-to-r from-indigo-500 to-blue-500 font-medium hover:from-indigo-600 hover:to-blue-600" className="btn btn-primary w-full bg-gradient-to-r from-indigo-500 to-blue-500 font-medium hover:from-indigo-600 hover:to-blue-600"
onClick={trackCallback('checkout', { amount: amountSelected })}
> >
Checkout Checkout
</button> </button>

View File

@ -19,6 +19,7 @@ import { getAllCharityTxns } from 'web/lib/firebase/txns'
import { manaToUSD } from 'common/util/format' import { manaToUSD } from 'common/util/format'
import { quadraticMatches } from 'common/quadratic-funding' import { quadraticMatches } from 'common/quadratic-funding'
import { Txn } from 'common/txn' import { Txn } from 'common/txn'
import { useTracking } from 'web/hooks/use-tracking'
export async function getStaticProps() { export async function getStaticProps() {
const txns = await getAllCharityTxns() const txns = await getAllCharityTxns()
@ -95,6 +96,8 @@ export default function Charity(props: {
[charities, query] [charities, query]
) )
useTracking('view charity')
return ( return (
<Page> <Page>
<Col className="w-full rounded px-4 py-6 sm:px-8 xl:w-[125%]"> <Col className="w-full rounded px-4 py-6 sm:px-8 xl:w-[125%]">

View File

@ -22,11 +22,14 @@ import { removeUndefinedProps } from 'common/util/object'
import { CATEGORIES } from 'common/categories' import { CATEGORIES } from 'common/categories'
import { ChoicesToggleGroup } from 'web/components/choices-toggle-group' import { ChoicesToggleGroup } from 'web/components/choices-toggle-group'
import { track } from 'web/lib/service/analytics' import { track } from 'web/lib/service/analytics'
import { useTracking } from 'web/hooks/use-tracking'
import { useWarnUnsavedChanges } from 'web/hooks/use-warn-unsaved-changes' import { useWarnUnsavedChanges } from 'web/hooks/use-warn-unsaved-changes'
export default function Create() { export default function Create() {
const [question, setQuestion] = useState('') const [question, setQuestion] = useState('')
useTracking('view create page')
return ( return (
<Page> <Page>
<div className="mx-auto w-full max-w-2xl"> <div className="mx-auto w-full max-w-2xl">

View File

@ -9,6 +9,8 @@ import { ContractSearch } from 'web/components/contract-search'
import { Contract } from 'common/contract' import { Contract } from 'common/contract'
import { ContractPageContent } from './[username]/[contractSlug]' import { ContractPageContent } from './[username]/[contractSlug]'
import { getContractFromSlug } from 'web/lib/firebase/contracts' import { getContractFromSlug } from 'web/lib/firebase/contracts'
import { useTracking } from 'web/hooks/use-tracking'
import { track } from 'web/lib/service/analytics'
const Home = () => { const Home = () => {
const user = useUser() const user = useUser()
@ -16,6 +18,8 @@ const Home = () => {
const router = useRouter() const router = useRouter()
useTracking('view home')
if (user === null) { if (user === null) {
Router.replace('/') Router.replace('/')
return <></> return <></>
@ -42,7 +46,10 @@ const Home = () => {
<button <button
type="button" type="button"
className="fixed bottom-[70px] right-3 inline-flex items-center rounded-full border border-transparent bg-indigo-600 p-3 text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 lg:hidden" className="fixed bottom-[70px] right-3 inline-flex items-center rounded-full border border-transparent bg-indigo-600 p-3 text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 lg:hidden"
onClick={() => router.push('/create')} onClick={() => {
router.push('/create')
track('mobile create button')
}}
> >
<PlusSmIcon className="h-8 w-8" aria-hidden="true" /> <PlusSmIcon className="h-8 w-8" aria-hidden="true" />
</button> </button>

View File

@ -4,6 +4,7 @@ import { Page } from 'web/components/page'
import { getTopCreators, getTopTraders, User } from 'web/lib/firebase/users' import { getTopCreators, getTopTraders, User } from 'web/lib/firebase/users'
import { formatMoney } from 'common/util/format' import { formatMoney } from 'common/util/format'
import { fromPropz, usePropz } from 'web/hooks/use-propz' import { fromPropz, usePropz } from 'web/hooks/use-propz'
import { useTracking } from 'web/hooks/use-tracking'
export const getStaticProps = fromPropz(getStaticPropz) export const getStaticProps = fromPropz(getStaticPropz)
export async function getStaticPropz() { export async function getStaticPropz() {
@ -32,6 +33,8 @@ export default function Leaderboards(props: {
} }
const { topTraders, topCreators } = props const { topTraders, topCreators } = props
useTracking('view leaderboards')
return ( return (
<Page margin> <Page margin>
<Col className="items-center gap-10 lg:flex-row"> <Col className="items-center gap-10 lg:flex-row">