feat(frontend): rewritten stats page with heatmap + progress + due

This commit is contained in:
2026-05-21 07:06:37 +02:00
parent 4c2d42779f
commit 2a6d048b65

View File

@@ -1,20 +1,54 @@
import { useEffect, useState } from 'react';
import { statsApi } from '../api/stats.js';
import { Heatmap } from '../components/Heatmap.js';
import { LessonProgressList, type LessonProgressRow } from '../components/LessonProgressList.js';
import { DueOverviewCard, type DueOverview } from '../components/DueOverviewCard.js';
export function StatsPage() {
const [heatmap, setHeatmap] = useState<{ day: string; sessions: number; attempts: number }[]>([]);
useEffect(() => { statsApi.heatmap(12).then(setHeatmap); }, []);
const [progress, setProgress] = useState<LessonProgressRow[]>([]);
const [due, setDue] = useState<DueOverview | null>(null);
useEffect(() => {
statsApi.heatmap(52).then(setHeatmap).catch(() => {});
statsApi.lessonsProgress().then((r) => setProgress(r.rows)).catch(() => {});
statsApi.due().then(setDue).catch(() => {});
}, []);
const max = Math.max(1, ...heatmap.map((d) => d.attempts));
return (
<div className="mx-auto max-w-4xl p-6">
<h1 className="mb-4 text-2xl font-semibold">Statistieken</h1>
<div className="flex flex-wrap gap-1">
{heatmap.map((d) => (
<div key={d.day} title={`${d.day}: ${d.attempts} pogingen`} className="h-4 w-4 rounded"
style={{ backgroundColor: `rgba(34,197,94,${0.15 + 0.85 * (d.attempts / max)})` }} />
))}
</div>
<div className="space-y-8">
<header>
<h1 className="font-display text-3xl font-bold">Statistieken</h1>
<p className="text-sm text-slate-500">Houd zicht op je voortgang en wat er te oefenen valt.</p>
</header>
{due && (
<section>
<h2 className="mb-3 font-display text-xl font-bold"> Te reviewen</h2>
<DueOverviewCard data={due} />
</section>
)}
<section>
<h2 className="mb-3 font-display text-xl font-bold">📊 Voortgang per les</h2>
<LessonProgressList rows={progress} />
</section>
<section>
<h2 className="mb-3 font-display text-xl font-bold">🔥 Activiteit</h2>
<div className="surface p-4">
<Heatmap points={heatmap} />
<div className="mt-3 flex items-center gap-2 text-xs text-slate-500">
<span>minder</span>
<span className="h-3 w-3 rounded-sm bg-slate-100 dark:bg-slate-800" />
<span className="h-3 w-3 rounded-sm bg-success-200" />
<span className="h-3 w-3 rounded-sm bg-success-400" />
<span className="h-3 w-3 rounded-sm bg-success-500" />
<span className="h-3 w-3 rounded-sm bg-success-700" />
<span>meer</span>
</div>
</div>
</section>
</div>
);
}