Skip to content

Commit 3873dcf

Browse files
committed
Add counters
1 parent 3f1ab63 commit 3873dcf

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

src/app/page.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { StatsDisplay } from '@/app/stats-display'
12
import { Button } from '@/components/ui/button'
23
import {
34
BarChartHorizontalBig,
@@ -41,6 +42,9 @@ export default function HomePage() {
4142
</Link>
4243
</Button>
4344
</div>
45+
<p className="mt-12 max-w-[42rem] leading-normal text-muted-foreground text-xl sm:text-2xl sm:leading-8">
46+
<StatsDisplay />
47+
</p>
4448
</div>
4549
</section>
4650

src/app/stats-display-actions.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use server'
2+
3+
import { getPrisma } from '@/lib/prisma'
4+
5+
export type Stats = {
6+
groupsCount: number
7+
expensesCount: number
8+
}
9+
10+
export async function getStatsAction(): Promise<Stats> {
11+
'use server'
12+
const prisma = await getPrisma()
13+
const groupsCount = await prisma.group.count()
14+
const expensesCount = await prisma.expense.count()
15+
return { groupsCount, expensesCount }
16+
}

src/app/stats-display.tsx

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
'use client'
2+
3+
import { Stats, getStatsAction } from '@/app/stats-display-actions'
4+
import { useEffect, useState } from 'react'
5+
6+
export function StatsDisplay() {
7+
const stats = useStats()
8+
9+
return (
10+
<>
11+
Already{' '}
12+
<strong>
13+
{stats ? <AnimatedCounter count={stats?.groupsCount} /> : '…'}
14+
</strong>{' '}
15+
groups and <br className="sm:hidden" />
16+
<strong>
17+
{stats ? <AnimatedCounter count={stats?.expensesCount} /> : '…'}
18+
</strong>{' '}
19+
expenses created.
20+
</>
21+
)
22+
}
23+
24+
function useStats() {
25+
const [stats, setStats] = useState<null | Stats>(null)
26+
27+
useEffect(() => {
28+
getStatsAction().then(setStats).catch(console.error)
29+
}, [])
30+
31+
return stats
32+
}
33+
34+
export function AnimatedCounter({ count }: { count: number }) {
35+
const start = count - 10
36+
const [current, setCurrent] = useState(start)
37+
38+
useEffect(() => {
39+
if (current < count) {
40+
const delay = 200 * (2 - 2 / ((current - start) / (count - start) + 1))
41+
setTimeout(() => setCurrent((c) => c + 1), delay)
42+
}
43+
}, [start, current, count])
44+
45+
return (
46+
<span className="tabular-nums">
47+
{current.toLocaleString('en-US', { useGrouping: true })}
48+
</span>
49+
)
50+
}

0 commit comments

Comments
 (0)