"use client"; import { useEffect, useMemo, useState, useSyncExternalStore } from "react"; import { useRouter } from "next/navigation"; import { SessionFeed, type SessionItem } from "@/components/SessionFeed"; import { RouteLoading } from "@/components/RouteLoading"; import { Button } from "@/components/ui"; import { haptic } from "@/lib/haptics"; import { ensureLearningHydrated, learningStore, recordAnswer } from "@/lib/history"; import { useI18n } from "@/lib/i18n"; import { dueItems, mistakeItems, type ReviewItem } from "@/lib/learning"; /** * Review / mistakes session: built from due items (SRS) across every deck, or * from the activities whose latest answer was wrong. Every answer is recorded, * so mistakes clear themselves once answered correctly. */ export function ReviewClient({ mistakes, deckId }: { mistakes: boolean; deckId?: string }) { const { t } = useI18n(); const router = useRouter(); const answers = useSyncExternalStore( learningStore.subscribe, learningStore.getAnswersSnapshot, learningStore.getServerAnswers, ); const srs = useSyncExternalStore( learningStore.subscribe, learningStore.getSrsSnapshot, learningStore.getServerSrs, ); const [ready, setReady] = useState(false); /** Frozen at session start: answering must not shrink the live queue. */ const [session, setSession] = useState(null); useEffect(() => { void ensureLearningHydrated().then(() => setReady(true)); }, []); const items = useMemo( () => (mistakes ? mistakeItems(answers, deckId) : dueItems(srs)), [mistakes, deckId, answers, srs], ); useEffect(() => { if (!ready || session || items.length === 0) return; setSession(items); }, [ready, session, items]); const title = mistakes ? deckId ? t("review.mistakesDeck") : t("review.mistakesTitle") : t("review.title"); if (!ready) { return ; } if (!session) { return (

{title}

{mistakes ? t("review.noMistakes") : t("review.nothingDue")}

); } const sessionItems: SessionItem[] = session.map(({ deck, activity }) => ({ deck, activity })); return ( router.push("/")} onAnswered={(item, correct) => { haptic(correct ? "success" : "error"); recordAnswer({ deckId: item.deck.id, deckTitle: item.deck.title, activityId: item.activity.id, type: item.activity.type, topic: item.activity.topic, correct, }); }} renderResults={({ correct, total, score }) => (

{title}

{score}%

{t("results.gotOf", { correct, total, retry: "" })}

)} /> ); }