"use client"; /** * /quizzes — every published quiz, with where you are in each. * * Reached from the Quizzes card on the search page. Quizzes are deliberately * not in search results: they're something to do, not something to look up. * Signed in only: visitors get the sign-in modal, and home if they dismiss it. * * The tab (?tab=todo) and, under All, the category you've drilled into * (?in=books&book=bg) both live in the URL, so a refresh keeps your place. */ import { useEffect, useMemo, useState } from "react"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { useSignedInPage } from "@/components/auth/use-signed-in-page"; import { quiz, type QuizCard } from "@/lib/quiz"; import { QuizGrid } from "@/components/quiz/quiz-grid"; import { QuizBrowser } from "@/components/quiz/quiz-browser"; import { cn } from "@/lib/utils"; type Filter = "all" | "todo" | "done"; const FILTERS: readonly Filter[] = ["all", "todo", "done"]; export function QuizzesList() { const { user } = useSignedInPage(); const userId = user?.id; const [list, setList] = useState(null); const params = useSearchParams(); const router = useRouter(); const pathname = usePathname(); const tabParam = params.get("tab") as Filter | null; const filter: Filter = tabParam && FILTERS.includes(tabParam) ? tabParam : "all"; // Switching tab starts that tab at its top; All is the bare URL. const setFilter = (f: Filter) => router.replace(f === "all" ? pathname : `${pathname}?tab=${f}`, { scroll: false, }); useEffect(() => { if (!userId) return; let cancelled = false; quiz .list() .then((l) => !cancelled && setList(l)) .catch(() => !cancelled && setList([])); return () => { cancelled = true; }; }, [userId]); const shown = useMemo( () => (list ?? []).filter((q) => filter === "all" ? true : filter === "done" ? q.my.state === "completed" : q.my.state !== "completed", ), [list, filter], ); return (

Quizzes

Test what you've read and heard. Each quiz can be taken once, and only you can see your results.

{user && ( // Phones: three equal, thumb-sized tabs across the width. From sm up // they shrink back to compact pills.
{( [ ["all", "All"], ["todo", "To do"], ["done", "Finished"], ] as const ).map(([k, label]) => ( ))}
)} {!user ? null : list === null ? (

Loading…

) : shown.length === 0 ? (

{list.length === 0 ? "No quizzes yet — check back soon." : "Nothing here."}

) : filter !== "all" ? ( ) : ( )}
); }