import QuestionAnswerResult from '@/components/exam/question-answer-result'; import QuestionStatusBadge from '@/components/exam/question-status-badge'; import QuestionStatusIcon from '@/components/exam/question-status-icon'; import QuestionTypeBadge from '@/components/exam/question-type-badge'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Progress } from '@/components/ui/progress'; import { safeQuestion } from '@/lib/exam'; import { StudentExamProps } from '@/types/page'; import { Link, usePage } from '@inertiajs/react'; import { ArrowLeft, Check, Clock, TrendingUp, X } from 'lucide-react'; import { useMemo } from 'react'; import { Renderer } from 'richtor'; import 'richtor/styles'; const ExamResult = () => { const { attempt } = usePage().props; const answers = attempt?.attempt_answers ?? []; const answersByType = useMemo(() => { return answers.reduce>( (acc, answer) => { const question = safeQuestion(answer); const type = question.question_type as ExamQuestionType; if (!type) return acc; if (!acc[type]) { acc[type] = { correct: 0, total: 0, marks: 0, totalMarks: 0 }; } acc[type].total += 1; acc[type].totalMarks += question.marks ?? 0; acc[type].marks += answer.marks_obtained || 0; if (answer.is_correct) acc[type].correct += 1; return acc; }, {} as Record, ); }, [answers]); if (!attempt) { return (

Attempt data unavailable

Please return to the exam list and try again.

); } const isPassed = attempt.is_passed; const percentage = attempt.percentage || 0; const correctAnswers = answers.filter((a) => a.is_correct).length; const incorrectAnswers = answers.filter((a) => a.is_correct === false).length; const pendingAnswers = answers.filter((a) => a.is_correct === null).length; type QuestionTypeStats = { correct: number; total: number; marks: number; totalMarks: number }; return (
{/* Header */}
Attempt {attempt.attempt_number} Result
{/* Score Card */}
{percentage.toFixed(1)}%

Score

{attempt.obtained_marks}/{attempt.total_marks}

Marks

{isPassed ? 'PASSED' : 'FAILED'}

Pass mark: {attempt.exam.pass_mark}

{Math.floor((new Date(attempt.end_time).getTime() - new Date(attempt.start_time).getTime()) / 60000)} min

Time Taken

{/* Statistics */}
Correct Answers
{correctAnswers}
Incorrect Answers
{incorrectAnswers}
Pending Review
{pendingAnswers}
{pendingAnswers > 0 &&

Manual grading in progress

}
{/* Performance by Question Type */} {Object.keys(answersByType).length > 0 && ( Performance by Question Type
{(Object.entries(answersByType) as [ExamQuestionType, QuestionTypeStats][]).map(([type, stats]) => (
{stats.correct}/{stats.total} correct
{stats.marks}/{stats.totalMarks} marks
))}
)} {/* Question-wise Analysis */} Detailed Analysis
{answers.map((answer, index) => { const question = safeQuestion(answer); return (
{/* Question Header */}
Question {index + 1} {question.question_type && }

{answer.marks_obtained || 0} / {question.marks || 0}

marks

{question.title}

{/* Question Content */}
{question.description && } {/* Render Question with Answer */}
); })}
); }; export default ExamResult;