"use client"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import { CategoryBreakdown } from "./CategoryBreakdown"; import { scoreQuestion } from "@/lib/scoring"; interface QuizResultsProps { quiz: any; // QuizData attempt: any; // QuizAttempt onRetake: (missedIds: string[]) => void; onClose: () => void; } export function QuizResults({ quiz, attempt, onRetake, onClose }: QuizResultsProps) { let answers: Record = {}; try { answers = JSON.parse(attempt.answersJson); } catch {} // Determine non-full-credit questions for review list const reviewItems: any[] = []; const missedIds: string[] = []; const answeredIds = Object.keys(answers); const questionsToReview = quiz.questions.filter((q: any) => answeredIds.includes(q.id)); questionsToReview.forEach((q: any) => { const formattedQ = { id: q.id, type: q.type, options: q.options, }; const score = scoreQuestion(formattedQ, answers[q.id] || []); // If not full credit (1.0), add to review and missed arrays if (score < 1) { missedIds.push(q.id); reviewItems.push({ question: q, score, selections: answers[q.id] || [] }); } }); const percentage = attempt.maxScore > 0 ? (attempt.score / attempt.maxScore) * 100 : 0; return (
{/* Top Banner */}
{percentage >= 80 && (
)} {percentage < 80 && percentage >= 60 && (
)} {percentage < 60 && (
)}

Quiz Complete

{attempt.isPartialRetake && (

(Partial Retake)

)}
{Math.round(percentage)}% ({attempt.score.toFixed(2)} / {attempt.maxScore})
{missedIds.length > 0 && ( )}
{/* Category Breakdown */}

Category Breakdown

{/* Review List */} {reviewItems.length > 0 && (

Areas for Review

{reviewItems.map((item, idx) => { const q = item.question; const sels = item.selections; return (
Score: {item.score.toFixed(2)} / 1 {q.category}
{q.prompt}
{q.options.map((opt: any) => { const isSelected = sels.includes(opt.id); let style = "text-text-body"; if (opt.isCorrect) style = "text-success font-medium bg-success-bg/50 border-success/30"; else if (isSelected && !opt.isCorrect) style = "text-error font-medium line-through bg-error-bg/50 border-error/30"; else style = "border-transparent"; return (
{opt.isCorrect ? "✓" : (isSelected ? "✗" : "•")}
{opt.text}
); })}

Rationale

{q.rationale}
); })}
)}
); }