'use client' import * as React from 'react' import { useMemo, useState } from 'react' import { useRouter } from 'next/navigation' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Input } from '@/components/ui/input' import { Badge } from '@/components/ui/badge' import { CheckCircle2, Edit3, HelpCircle, RefreshCw, XCircle } from 'lucide-react' import type { QuizCache } from '@/lib/quiz-types' interface QuizPlayerProps { quiz: QuizCache lessonId: string courseId: string moduleId: string onCompleted?: () => void } export function QuizPlayer({ quiz, lessonId, courseId, moduleId, onCompleted }: QuizPlayerProps) { const router = useRouter() const [quizData, setQuizData] = useState(quiz) const [started, setStarted] = useState(false) const [selectedAnswers, setSelectedAnswers] = useState>({}) const [isSubmitting, setIsSubmitting] = useState(false) const [submitted, setSubmitted] = useState(false) const [isRefreshing, setIsRefreshing] = useState(false) const [topicDraft, setTopicDraft] = useState(quiz.topic) const [editingTopic, setEditingTopic] = useState(false) const answeredCount = useMemo( () => Object.values(selectedAnswers).filter((value) => value !== null && value !== undefined).length, [selectedAnswers] ) const score = useMemo(() => { return quizData.questions.reduce((sum, question) => { const answer = selectedAnswers[question.id] return sum + (typeof answer === 'number' && answer === question.answerIndex ? 1 : 0) }, 0) }, [quizData.questions, selectedAnswers]) const totalQuestions = quizData.questions.length const passed = totalQuestions > 0 && score / totalQuestions >= 0.8 const startQuiz = () => setStarted(true) const chooseAnswer = (questionId: string, answerIndex: number) => { setSelectedAnswers((prev) => ({ ...prev, [questionId]: answerIndex })) } const submitQuiz = async () => { setIsSubmitting(true) try { const response = await fetch('/api/quiz/attempt', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ lessonId, courseId, moduleId, score, totalQuestions, passed, }), }) if (!response.ok) { const data = await response.json().catch(() => ({})) throw new Error(data?.error || 'Failed to save quiz attempt') } setSubmitted(true) onCompleted?.() router.refresh() } catch (error) { console.error('Quiz submission failed:', error) } finally { setIsSubmitting(false) } } const refreshQuiz = async () => { setIsRefreshing(true) try { const response = await fetch('/api/quiz', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ lessonId, topic: topicDraft, }), }) if (!response.ok) { const data = await response.json().catch(() => ({})) throw new Error(data?.error || 'Failed to fetch quiz') } const data = await response.json() as { quiz?: QuizCache } if (data.quiz) { setQuizData(data.quiz) setSelectedAnswers({}) setStarted(false) setSubmitted(false) } setEditingTopic(false) router.refresh() } catch (error) { console.error('Quiz refresh failed:', error) } finally { setIsRefreshing(false) } } if (!started) { return (
Quiz {quizData.questions.length} questions
{quizData.title} {quizData.description}
{editingTopic && (
Override the topic and refresh the quiz cache.
setTopicDraft(event.target.value)} placeholder="Type a new quiz topic" />
)}
Source: {quizData.source.toUpperCase()}
Topic: {quizData.topic}
Questions: {quizData.questions.length}
Pass mark: 80%
) } return (

Quiz in progress

{quizData.title}

Answered {answeredCount}/{totalQuestions} Source: {quizData.source.toUpperCase()}
{quizData.questions.map((question, index) => { const selected = selectedAnswers[question.id] const answered = typeof selected === 'number' const isCorrect = submitted && selected === question.answerIndex const isWrong = submitted && answered && selected !== question.answerIndex return (
Question {index + 1} {question.prompt}
{submitted && isCorrect && } {submitted && isWrong && }
{question.options.map((option, optionIndex) => { const active = selected === optionIndex const revealCorrect = submitted && optionIndex === question.answerIndex const revealWrong = submitted && active && optionIndex !== question.answerIndex return ( ) })}
{submitted && question.explanation && (
{question.explanation}
)}
) })}
{submitted ? ( Score: {score}/{totalQuestions} —{' '} {passed ? 'Passed' : 'Not passed yet'} ) : ( Pick an answer for each question, then submit your attempt. )}
{!submitted ? ( ) : ( )}
) }