"use client"; import { useEffect, useMemo, useState } from "react"; import Link from "next/link"; import { BookOpen, Brain, CheckCircle2, FileText, LineChart, MessageSquareText, Play, Target, } from "lucide-react"; import { hydratePhase3Activity, readPhase3Activity, type Phase3Activity } from "@/lib/phase3-learning"; import { buildStudentProgressSummary, listActivities, type ActivityEvent, } from "@/lib/student-activity"; import { getLocalStudentContext, loadStudentContext, type StudentContext } from "@/lib/student-context"; import { useStudentActivityVersion } from "@/hooks/useStudentActivity"; // ============================================================================= // Truthful progress: every number traces to something the student actually did // (the student-activity ledger) or real weak-topic evidence (phase3 aggregate, // fed by quiz mistakes). No sample metrics. Extracted from the /progress route // so /library can compose it as a tab. // ============================================================================= const KIND_META: Record = { question_asked: { label: "Asked in StudyChat", icon: MessageSquareText }, lesson_started: { label: "Lesson started", icon: Play }, lesson_completed: { label: "Lesson completed", icon: CheckCircle2 }, note_saved: { label: "Note saved", icon: FileText }, quiz_attempted: { label: "Quiz attempted", icon: Brain }, demo_class_completed: { label: "Demo class completed", icon: CheckCircle2 }, }; export function ProgressView() { const [events, setEvents] = useState([]); const [phase3, setPhase3] = useState({}); const [ctx, setCtx] = useState(() => getLocalStudentContext()); // Live token: re-read the ledger whenever activity changes (this tab or another). const activityVersion = useStudentActivityVersion(); useEffect(() => { let cancelled = false; void Promise.resolve().then(() => { if (cancelled) return; setEvents(listActivities(30)); setPhase3(readPhase3Activity()); }); return () => { cancelled = true; }; }, [activityVersion]); useEffect(() => { let cancelled = false; void loadStudentContext().then((merged) => { if (!cancelled) setCtx(merged); }); // Pull the saved weak-topic aggregate from the backend on fresh devices. void hydratePhase3Activity().then((remote) => { if (!cancelled && remote) setPhase3(readPhase3Activity()); }); return () => { cancelled = true; }; }, []); const summary = useMemo(() => buildStudentProgressSummary(events, phase3), [events, phase3]); return (

Study progress

Built only from what you actually did — questions, lessons, notes, and quiz results on this device.

{ctx.onboardingComplete ? (

Onboarding completed{ctx.classLevel ? ` · ${ctx.classLevel}` : ""}{ctx.board ? ` · ${ctx.board}` : ""}

{ctx.synced ? "Account profile synced." : "Local profile active · account sync unavailable."}

) : (

Complete onboarding {" "} to set your study focus.

)}
{!summary.hasActivity ? (

Start a lesson, ask a question, or take a quiz to build your progress.

Start a lesson Ask a question Take a quiz
) : ( <>
{summary.metrics.map((metric) => (

{metric.label}

{metric.value}

))}
{summary.sampleActivityCount > 0 ? (

Demo activity is labelled below and does not represent full tuition progress.

) : null}
{/* ── Recent activity (real ledger) ── */}

Recent activity

{summary.recentActivities.slice(0, 10).map((event) => { const meta = KIND_META[event.kind]; const Icon = meta.icon; return (

{event.title}

{meta.label} {event.detail ? ` · ${event.detail}` : ""} {event.sample ? " · demo/sample" : ""} · {new Date(event.at).toLocaleString()}

); })} {summary.recentActivities.length === 0 ? (

No activity recorded yet.

) : null}
{/* ── Weak areas (evidence only) ── */}

Weak topics

{summary.weakTopics.length > 0 ? (
{summary.weakTopics.map((topic) => (

{topic}

From a missed quiz question or saved feedback.

))}
) : (

No weak topics yet — they appear here when you miss a quiz question.

)}
)}
); }