feat(frontend): due-overview card with start-review CTA
This commit is contained in:
55
packages/frontend/src/components/DueOverviewCard.tsx
Normal file
55
packages/frontend/src/components/DueOverviewCard.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { sessionsApi } from '../api/sessions.js';
|
||||
import { useSession } from '../stores/sessionStore.js';
|
||||
|
||||
export interface DueOverview { overdue: number; today: number; tomorrow: number; thisWeek: number; }
|
||||
|
||||
export function DueOverviewCard({ data }: { data: DueOverview }) {
|
||||
const navigate = useNavigate();
|
||||
const total = data.overdue + data.today;
|
||||
async function startReview() {
|
||||
const r = await sessionsApi.startDue();
|
||||
useSession.setState({
|
||||
session: r.session,
|
||||
current: r.queue[0] ?? null,
|
||||
done: r.queue.length === 0,
|
||||
showAnswer: false,
|
||||
shownAt: Date.now(),
|
||||
});
|
||||
navigate(`/practice/${r.session.lessonId}`);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="surface space-y-4 p-5">
|
||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
|
||||
<Badge tone="danger" label="Overdue" value={data.overdue} />
|
||||
<Badge tone="brand" label="Vandaag" value={data.today} />
|
||||
<Badge tone="success" label="Morgen" value={data.tomorrow} />
|
||||
<Badge tone="muted" label="Deze week" value={data.thisWeek} />
|
||||
</div>
|
||||
<button
|
||||
className="btn-primary w-full py-3"
|
||||
onClick={startReview}
|
||||
disabled={total === 0}
|
||||
>
|
||||
{total === 0
|
||||
? 'Niets te reviewen — alles up-to-date 🎉'
|
||||
: `Start review (${total} ${total === 1 ? 'kaart' : 'kaarten'})`}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Badge({ tone, label, value }: { tone: 'danger'|'brand'|'success'|'muted'; label: string; value: number }) {
|
||||
const cls =
|
||||
tone === 'danger' ? 'bg-danger-50 text-danger-700 dark:bg-danger-400/15 dark:text-danger-400'
|
||||
: tone === 'brand' ? 'bg-brand-100 text-brand-700 dark:bg-brand-900/30 dark:text-brand-200'
|
||||
: tone === 'success' ? 'bg-success-50 text-success-700 dark:bg-success-700/15 dark:text-success-400'
|
||||
: 'bg-slate-100 text-slate-700 dark:bg-slate-800 dark:text-slate-300';
|
||||
return (
|
||||
<div className={`rounded-2xl p-3 ${cls}`}>
|
||||
<div className="text-[10px] font-semibold uppercase tracking-wider opacity-80">{label}</div>
|
||||
<div className="mt-1 font-display text-2xl font-bold">{value}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user