import { useEffect, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { ArrowLeft, ClipboardList, NotebookPen, CheckCircle2, Circle, Users, Activity, ChevronDown, ChevronUp, } from "lucide-react"; import { useCourses } from "@/contexts/AdminCoursesContext"; import { PageMeta } from "@/contexts/MetadataContext"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Separator } from "@/components/ui/separator"; import { Skeleton } from "@/components/ui/skeleton"; // ─── Helpers ────────────────────────────────────────────────────────────────── function InfoRow({ label, children }) { return (
{label} {children ?? —}
); } function SectionCard({ title, children }) { return (
{title && (<>

{title}

)} {children}
); } function StatCard({ label, value, color = "default" }) { const colors = { default: "bg-card border", green: "bg-green-500/5 border-green-500/20", red: "bg-red-500/5 border-red-500/20", blue: "bg-blue-500/5 border-blue-500/20", amber: "bg-amber-500/5 border-amber-500/20", }; return (

{value ?? 0}

{label}

); } const TYPE_LABELS = { multiple_choice: "Multiple Choice", multi_select: "Multi Select", true_false: "True / False", }; function QuestionView({ question, index }) { return (
{index + 1}

{question.question?.trim() || Untitled}

{TYPE_LABELS[question.type] ?? question.type} {question.points ?? 1} pt{(question.points ?? 1) !== 1 ? "s" : ""}
{question.type === "multi_select" && (() => { const cnt = (question.options ?? []).filter((o) => o.is_correct).length; return cnt > 0 ? (

Students select {cnt} answer{cnt !== 1 ? "s" : ""}

) : null; })()}
); } // ─── Completions tab ────────────────────────────────────────────────────────── function CompletionRow({ row }) { const [open, setOpen] = useState(false); return ( <> setOpen((v) => !v)} >

{row.full_name}

{row.email}

{row.attempt_count} {row.best_score}% {row.passed ? ( Passed ) : ( Not yet )} {row.latest_at ? new Date(row.latest_at).toLocaleDateString() : "—"} {open ? : } {open && ( {(row.attempts ?? []).map((a) => ( ))}
Attempt Score Points Result Date
#{a.attempt_number} {a.score}% {a.earned_points}/{a.total_points} {a.passed ? Pass : Fail} {new Date(a.createdAt).toLocaleString()}
)} ); } function CompletionsTab({ completions, loading }) { if (loading) return
{[...Array(3)].map((_, i) => )}
; if (!completions) return (

No data yet.

); const { summary, completions: rows } = completions; return (
{rows.length === 0 ? (

No one has attempted this assessment yet.

) : (
{rows.map((row) => )}
Student Attempts Best Score Status Last Attempt
)}
); } // ─── Sessions tab ───────────────────────────────────────────────────────────── const SESSION_BADGE = { completed: "bg-green-500/10 text-green-700 dark:text-green-400 border-green-500/20", expired: "bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/20", in_progress: "bg-amber-500/10 text-amber-700 dark:text-amber-400 border-amber-500/20", }; function fmtDuration(secs) { if (secs == null) return "—"; if (secs < 60) return `${secs}s`; const m = Math.floor(secs / 60); const s = secs % 60; return s > 0 ? `${m}m ${s}s` : `${m}m`; } function SessionsTab({ sessions, loading }) { if (loading) return
{[...Array(4)].map((_, i) => )}
; if (!sessions) return (

No data yet.

); const { summary, sessions: rows } = sessions; return (
{rows.length === 0 ? (

No sessions recorded yet.

) : (
{rows.map((s) => ( ))}
Student Status Started Expires At Time Spent

{s.full_name}

{s.email}

{s.status === 'in_progress' ? 'In Progress' : s.status.charAt(0).toUpperCase() + s.status.slice(1)} {new Date(s.started_at).toLocaleString()} {s.expires_at ? new Date(s.expires_at).toLocaleString() : "—"} {fmtDuration(s.time_spent_seconds)}
)}
); } function LoadingSkeleton() { return (
{[...Array(3)].map((_, i) => )}
); } // ─── Page ───────────────────────────────────────────────────────────────────── const TABS = [ { key: "questions", label: "Questions", icon: ClipboardList }, { key: "completions", label: "Completions", icon: Users }, { key: "sessions", label: "Sessions", icon: Activity }, ]; export default function ViewAssessment() { const navigate = useNavigate(); const { courseId } = useParams(); const { fetchAssessment, assessment, fetchAssessmentCompletions, fetchAssessmentSessions, completions, sessions, loading, } = useCourses(); const [activeTab, setActiveTab] = useState("questions"); useEffect(() => { fetchAssessment(courseId); }, [courseId]); // Lazy-load completions/sessions the first time each tab is opened const loadedRef = { completions: false, sessions: false }; useEffect(() => { if (!assessment?.assessment_id) return; if (activeTab === "completions") fetchAssessmentCompletions(courseId, assessment.assessment_id); if (activeTab === "sessions") fetchAssessmentSessions(courseId, assessment.assessment_id); }, [activeTab, assessment?.assessment_id]); const questions = assessment?.questions ?? []; const totalPoints = questions.reduce((sum, q) => sum + (q.points ?? 1), 0); return (
{/* ── Header ── */}

View Assessment

{assessment && (

{questions.length} question{questions.length !== 1 ? "s" : ""} · {totalPoints} total point{totalPoints !== 1 ? "s" : ""}

)}
{/* Tabs */} {assessment && (
{TABS.map(({ key, label, icon: Icon }) => ( ))}
)}
{/* ── Content ── */}
{loading && !assessment ? ( ) : !assessment ? (

No assessment has been created for this course yet.

) : activeTab === "questions" ? ( <>
{assessment.title || "Course Assessment"} {assessment.is_required ? "Required" : "Optional"} {assessment.passing_score ?? 70}% {assessment.time_limit_minutes ? `${assessment.time_limit_minutes} mins` : "No limit"} {questions.length} {assessment.max_questions ? `${assessment.max_questions} (random)` : `All (${questions.length})`} {totalPoints} {assessment.max_attempts ?? 3} {assessment.cooldown_hours ?? 24}h

Questions

{questions.length === 0 ? (

No questions added yet.

) : ( questions.map((q, i) => ) )}
) : activeTab === "completions" ? ( ) : ( )}
); }