51 lines
1.7 KiB
TypeScript
51 lines
1.7 KiB
TypeScript
"use client";
|
|
|
|
/** One quiz in the /quizzes list: what it's on, its title, and your progress. */
|
|
|
|
import Link from "next/link";
|
|
import { ClipboardCheck } from "lucide-react";
|
|
import { quizActionLabel, type QuizCard } from "@/lib/quiz";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
const KIND: Record<QuizCard["target_kind"], string> = {
|
|
chapter: "Book chapter",
|
|
lecture: "Lecture",
|
|
conversation: "Conversation",
|
|
standalone: "Quiz",
|
|
};
|
|
|
|
export function QuizListCard({ q }: { q: QuizCard }) {
|
|
const done = q.my.state === "completed";
|
|
return (
|
|
<Link
|
|
href={`/quizzes/${q.id}`}
|
|
className="flex h-full min-w-0 flex-col rounded-2xl border border-border bg-card p-4 transition-colors hover:border-primary/40 hover:bg-muted/30"
|
|
>
|
|
<p className="text-xs font-medium text-primary">{KIND[q.target_kind]}</p>
|
|
<p className="mt-1 break-words font-semibold leading-snug text-foreground [overflow-wrap:anywhere]">
|
|
{q.title}
|
|
</p>
|
|
{q.target_title && (
|
|
<p className="mt-0.5 truncate text-sm text-muted-foreground">
|
|
{q.target_title}
|
|
</p>
|
|
)}
|
|
<div className="mt-auto flex flex-wrap items-center justify-between gap-x-3 gap-y-1 pt-4 text-xs">
|
|
<span className="text-muted-foreground">
|
|
{q.question_count} {q.question_count === 1 ? "question" : "questions"}
|
|
</span>
|
|
<span
|
|
className={cn(
|
|
"inline-flex items-center gap-1 whitespace-nowrap font-medium",
|
|
done ? "text-muted-foreground" : "text-primary",
|
|
)}
|
|
>
|
|
<ClipboardCheck className="size-3.5" />
|
|
{quizActionLabel(q.my.state)}
|
|
{done && q.my.score !== undefined && ` · ${q.my.score}/${q.my.total}`}
|
|
</span>
|
|
</div>
|
|
</Link>
|
|
);
|
|
}
|