Skip to content

Commit 1a78445

Browse files
committed
Better analytics
1 parent 8907703 commit 1a78445

File tree

10 files changed

+227
-8
lines changed

10 files changed

+227
-8
lines changed

package-lock.json

+120
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/groups/[groupId]/balances/page.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { BalancesList } from '@/app/groups/[groupId]/balances-list'
22
import { ReimbursementList } from '@/app/groups/[groupId]/reimbursement-list'
3+
import { TrackPage } from '@/components/track-page'
34
import {
45
Card,
56
CardContent,
@@ -30,6 +31,7 @@ export default async function GroupPage({
3031

3132
return (
3233
<>
34+
<TrackPage path={`/groups/${group.id}/balances`} />
3335
<Card className="mb-4">
3436
<CardHeader>
3537
<CardTitle>Balances</CardTitle>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use client'
2+
3+
import { useAnalytics } from '@/components/track-page'
4+
import Link from 'next/link'
5+
import { PropsWithChildren } from 'react'
6+
7+
export const ExportLink = function ExportLink({
8+
groupId,
9+
children,
10+
className,
11+
}: PropsWithChildren<{ groupId: string; className?: string }>) {
12+
const sendEvent = useAnalytics()
13+
14+
return (
15+
<Link
16+
className={className}
17+
href={`/groups/${groupId}/expenses/export/json`}
18+
target="_blank"
19+
onClick={() => {
20+
sendEvent('group: export expenses', { props: { groupId } })
21+
}}
22+
>
23+
{children}
24+
</Link>
25+
)
26+
}

src/app/groups/[groupId]/expenses/page.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { ActiveUserModal } from '@/app/groups/[groupId]/expenses/active-user-modal'
22
import { ExpenseList } from '@/app/groups/[groupId]/expenses/expense-list'
3+
import { ExportLink } from '@/app/groups/[groupId]/expenses/export-link'
4+
import { TrackPage } from '@/components/track-page'
35
import { Button } from '@/components/ui/button'
46
import {
57
Card,
@@ -30,6 +32,7 @@ export default async function GroupExpensesPage({
3032

3133
return (
3234
<>
35+
<TrackPage path={`/groups/${group.id}/expenses`} />
3336
<Card className="mb-4 rounded-none -mx-4 border-x-0 sm:border-x sm:rounded-lg sm:mx-0">
3437
<div className="flex flex-1">
3538
<CardHeader className="flex-1 p-4 sm:p-6">
@@ -40,12 +43,9 @@ export default async function GroupExpensesPage({
4043
</CardHeader>
4144
<CardHeader className="p-4 sm:p-6 flex flex-row space-y-0 gap-2">
4245
<Button variant="secondary" size="icon" asChild>
43-
<Link
44-
href={`/groups/${groupId}/expenses/export/json`}
45-
target="_blank"
46-
>
46+
<ExportLink groupId={groupId}>
4747
<Download className="w-4 h-4" />
48-
</Link>
48+
</ExportLink>
4949
</Button>
5050
<Button asChild size="icon">
5151
<Link href={`/groups/${groupId}/expenses/create`}>

src/app/groups/page.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { RecentGroupList } from '@/app/groups/recent-group-list'
2+
import { TrackPage } from '@/components/track-page'
23
import { Button } from '@/components/ui/button'
34
import { Plus } from 'lucide-react'
45
import { Metadata } from 'next'
@@ -11,6 +12,7 @@ export const metadata: Metadata = {
1112
export default async function GroupsPage() {
1213
return (
1314
<>
15+
<TrackPage path="/groups" />
1416
<div className="flex justify-between items-center gap-4">
1517
<h1 className="font-bold text-2xl">
1618
<Link href="/groups">My groups</Link>

src/app/layout.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,11 @@ export default function RootLayout({
6868
return (
6969
<html lang="en" suppressHydrationWarning>
7070
{env.PLAUSIBLE_DOMAIN && (
71-
<PlausibleProvider domain={env.PLAUSIBLE_DOMAIN} trackOutboundLinks />
71+
<PlausibleProvider
72+
domain={env.PLAUSIBLE_DOMAIN}
73+
trackOutboundLinks
74+
manualPageviews
75+
/>
7276
)}
7377
<body className="pt-16 min-h-[100dvh] flex flex-col items-stretch bg-slate-50 bg-opacity-30 dark:bg-background">
7478
<ThemeProvider

src/app/page.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { StatsDisplay } from '@/app/stats-display'
2+
import { TrackPage } from '@/components/track-page'
23
import { Button } from '@/components/ui/button'
34
import {
45
BarChartHorizontalBig,
@@ -22,6 +23,7 @@ export const dynamic = 'force-dynamic'
2223
export default function HomePage() {
2324
return (
2425
<main>
26+
<TrackPage path="/" />
2527
<section className="py-16 md:py-24 lg:py-32">
2628
<div className="container flex max-w-screen-md flex-col items-center gap-4 text-center">
2729
<h1 className="!leading-none font-bold text-3xl sm:text-5xl md:text-6xl lg:text-7xl landing-header py-2">

src/components/expense-form.tsx

+20-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { AsyncButton } from '@/components/async-button'
33
import { CategorySelector } from '@/components/category-selector'
44
import { SubmitButton } from '@/components/submit-button'
5+
import { useAnalytics } from '@/components/track-page'
56
import { Button } from '@/components/ui/button'
67
import {
78
Card,
@@ -112,10 +113,22 @@ export function ExpenseForm({
112113
splitMode: 'EVENLY',
113114
},
114115
})
116+
const sendEvent = useAnalytics()
115117

116118
return (
117119
<Form {...form}>
118-
<form onSubmit={form.handleSubmit((values) => onSubmit(values))}>
120+
<form
121+
onSubmit={form.handleSubmit(async (values) => {
122+
if (expense) {
123+
sendEvent('expense: update', {
124+
props: { groupId: group.id, expenseId: expense.id },
125+
})
126+
} else {
127+
sendEvent('expense: create', { props: { groupId: group.id } })
128+
}
129+
await onSubmit(values)
130+
})}
131+
>
119132
<Card>
120133
<CardHeader>
121134
<CardTitle>
@@ -514,7 +527,12 @@ export function ExpenseForm({
514527
type="button"
515528
variant="destructive"
516529
loadingContent="Deleting…"
517-
action={onDelete}
530+
action={async () => {
531+
sendEvent('expense: delete', {
532+
props: { groupId: group.id, expenseId: expense.id },
533+
})
534+
await onDelete()
535+
}}
518536
>
519537
<Trash2 className="w-4 h-4 mr-2" />
520538
Delete

src/components/group-form.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client'
22
import { SubmitButton } from '@/components/submit-button'
3+
import { useAnalytics } from '@/components/track-page'
34
import { Button } from '@/components/ui/button'
45
import {
56
Card,
@@ -67,6 +68,7 @@ export function GroupForm({
6768
name: 'participants',
6869
keyName: 'key',
6970
})
71+
const sendEvent = useAnalytics()
7072

7173
let activeUser = 'None'
7274

@@ -87,6 +89,11 @@ export function GroupForm({
8789
<Form {...form}>
8890
<form
8991
onSubmit={form.handleSubmit(async (values) => {
92+
if (group) {
93+
sendEvent('group: update', { props: { groupId: group.id } })
94+
} else {
95+
sendEvent('group: create', { props: {} })
96+
}
9097
await onSubmit(values)
9198
})}
9299
>

src/components/track-page.tsx

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use client'
2+
3+
import { usePlausible } from 'next-plausible'
4+
import { useEffect } from 'react'
5+
6+
type Event = {
7+
pageview: {}
8+
'group: create': {}
9+
'group: update': { groupId: string }
10+
'expense: create': { groupId: string }
11+
'expense: update': { groupId: string; expenseId: string }
12+
'expense: delete': { groupId: string; expenseId: string }
13+
'group: export expenses': { groupId: string }
14+
}
15+
16+
export function TrackPage({ path }: { path: string }) {
17+
const sendEvent = useAnalytics()
18+
19+
useEffect(() => {
20+
const url = `${window.location.origin}${path}`
21+
22+
sendEvent('pageview', { u: url, props: {} })
23+
}, [path, sendEvent])
24+
25+
return null
26+
}
27+
28+
export function useAnalytics() {
29+
const plausible = usePlausible<Event>()
30+
31+
const sendEvent: typeof plausible = (eventName, ...rest) => {
32+
if (process.env.NODE_ENV !== 'production')
33+
console.log('Analytics event:', eventName, ...rest)
34+
plausible(eventName, ...rest)
35+
}
36+
37+
return sendEvent
38+
}

0 commit comments

Comments
 (0)