@schoolio/player 1.4.2 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/QuizPlayer.tsx","../src/api.ts","../src/utils.ts","../src/TextToSpeech.tsx","../src/QuestionChatPanel.tsx","../src/AttemptViewer.tsx"],"sourcesContent":["// Main components\r\nexport { QuizPlayer } from './QuizPlayer';\r\nexport { AttemptViewer } from './AttemptViewer';\r\nexport { TextToSpeech } from './TextToSpeech';\r\n\r\n// API client for custom implementations\r\nexport { QuizApiClient } from './api';\r\nexport type { ApiClientConfig } from './api';\r\n\r\n// Utility functions\r\nexport { checkAnswer, createAnswerDetail, calculateScore, formatTime } from './utils';\r\n\r\n// Types\r\nexport type {\r\n QuestionType,\r\n QuizQuestion,\r\n Quiz,\r\n QuizAnswerDetail,\r\n AttemptStatus,\r\n ExternalQuizAttempt,\r\n QuizPlayerProps,\r\n QuizResult,\r\n QuizProgress,\r\n QuizPlayerStyles,\r\n AttemptViewerProps,\r\n GenerateMoreQuestionsResult,\r\n} from './types';\r\n","import { useState, useEffect, useCallback, useRef } from 'react';\r\nimport type {\r\n QuizPlayerProps,\r\n Quiz,\r\n QuizQuestion,\r\n QuizAnswerDetail,\r\n ExternalQuizAttempt,\r\n QuizResult,\r\n SkipReason,\r\n QuestionContextForChat,\r\n} from './types';\r\nimport { QuizApiClient } from './api';\r\nimport { createAnswerDetail, calculateScore, formatTime } from './utils';\r\nimport { TextToSpeech } from './TextToSpeech';\r\nimport { QuestionChatPanel } from './QuestionChatPanel';\r\n\r\n// Default styles that can be overridden\r\nconst defaultStyles = {\r\n container: {\r\n fontFamily: 'system-ui, -apple-system, sans-serif',\r\n width: '100%',\r\n height: '100%',\r\n padding: '20px',\r\n backgroundColor: '#ffffff',\r\n borderRadius: '12px',\r\n boxSizing: 'border-box' as const,\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n },\r\n header: {\r\n marginBottom: '20px',\r\n borderBottom: '1px solid #e5e7eb',\r\n paddingBottom: '16px',\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n },\r\n headerTop: {\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n alignItems: 'flex-start',\r\n },\r\n headerLeft: {\r\n flex: 1,\r\n },\r\n title: {\r\n fontSize: '24px',\r\n fontWeight: '600',\r\n marginBottom: '8px',\r\n },\r\n progress: {\r\n fontSize: '14px',\r\n color: '#6b7280',\r\n },\r\n progressBar: {\r\n width: '50%',\r\n maxWidth: '300px',\r\n height: '8px',\r\n backgroundColor: '#e5e7eb',\r\n borderRadius: '4px',\r\n overflow: 'hidden' as const,\r\n marginTop: '8px',\r\n },\r\n progressFill: {\r\n height: '100%',\r\n backgroundColor: '#6721b0',\r\n transition: 'width 0.3s ease',\r\n },\r\n question: {\r\n marginBottom: '24px',\r\n minHeight: '280px',\r\n },\r\n questionText: {\r\n fontSize: '18px',\r\n fontWeight: '500',\r\n marginBottom: '16px',\r\n },\r\n options: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '8px',\r\n },\r\n option: {\r\n padding: '12px 16px',\r\n border: '2px solid #e5e7eb',\r\n borderRadius: '8px',\r\n cursor: 'pointer',\r\n transition: 'all 0.2s ease',\r\n outline: 'none',\r\n boxShadow: 'none',\r\n backgroundColor: '#ffffff',\r\n WebkitTapHighlightColor: 'transparent',\r\n userSelect: 'none' as const,\r\n },\r\n optionSelected: {\r\n borderColor: '#6721b0',\r\n backgroundColor: '#f3e8ff',\r\n },\r\n optionCorrect: {\r\n borderColor: '#22c55e',\r\n backgroundColor: '#f0fdf4',\r\n },\r\n optionIncorrect: {\r\n borderColor: '#ef4444',\r\n backgroundColor: '#fef2f2',\r\n },\r\n input: {\r\n width: '100%',\r\n padding: '12px 16px',\r\n border: '2px solid #e5e7eb',\r\n borderRadius: '8px',\r\n fontSize: '16px',\r\n outline: 'none',\r\n boxSizing: 'border-box' as const,\r\n backgroundColor: '#ffffff',\r\n },\r\n buttons: {\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n marginTop: '24px',\r\n },\r\n button: {\r\n padding: '12px 24px',\r\n borderRadius: '8px',\r\n fontSize: '16px',\r\n fontWeight: '500',\r\n cursor: 'pointer',\r\n border: 'none',\r\n transition: 'all 0.2s ease',\r\n },\r\n buttonPrimary: {\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n },\r\n buttonSecondary: {\r\n backgroundColor: '#f3f4f6',\r\n color: '#374151',\r\n },\r\n buttonDisabled: {\r\n backgroundColor: '#e5e7eb',\r\n color: '#9ca3af',\r\n cursor: 'not-allowed',\r\n },\r\n buttonAddMore: {\r\n padding: '12px 24px',\r\n borderRadius: '8px',\r\n fontSize: '16px',\r\n fontWeight: '500',\r\n cursor: 'pointer',\r\n border: '2px solid #6721b0',\r\n backgroundColor: 'transparent',\r\n color: '#6721b0',\r\n transition: 'all 0.2s ease',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n gap: '8px',\r\n },\r\n buttonAddMoreDisabled: {\r\n border: '2px solid #e5e7eb',\r\n color: '#9ca3af',\r\n cursor: 'not-allowed',\r\n },\r\n buttonsColumn: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '12px',\r\n marginTop: '24px',\r\n },\r\n mainLayout: {\r\n display: 'flex',\r\n gap: '24px',\r\n flex: 1,\r\n minHeight: 0,\r\n alignItems: 'stretch',\r\n },\r\n quizContent: {\r\n flex: 1,\r\n minWidth: 0,\r\n overflow: 'auto',\r\n },\r\n chatPanel: {\r\n width: '320px',\r\n flexShrink: 0,\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n },\r\n timer: {\r\n fontSize: '14px',\r\n color: '#6b7280',\r\n marginLeft: '16px',\r\n },\r\n results: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n padding: '48px 24px',\r\n textAlign: 'center' as const,\r\n minHeight: '400px',\r\n position: 'relative' as const,\r\n overflow: 'hidden' as const,\r\n },\r\n resultsBackground: {\r\n position: 'absolute' as const,\r\n inset: '0',\r\n borderRadius: '16px',\r\n zIndex: 0,\r\n },\r\n resultsContent: {\r\n position: 'relative' as const,\r\n zIndex: 1,\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n alignItems: 'center',\r\n },\r\n resultDetails: {\r\n fontSize: '18px',\r\n color: '#6b7280',\r\n marginBottom: '4px',\r\n },\r\n resultStars: {\r\n display: 'flex',\r\n justifyContent: 'center',\r\n gap: '8px',\r\n marginBottom: '20px',\r\n },\r\n resultStar: {\r\n fontSize: '32px',\r\n animation: 'starPop 0.5s ease-out forwards',\r\n opacity: 0,\r\n },\r\n confettiContainer: {\r\n position: 'absolute' as const,\r\n inset: '0',\r\n pointerEvents: 'none' as const,\r\n overflow: 'hidden' as const,\r\n zIndex: 0,\r\n },\r\n confettiPiece: {\r\n position: 'absolute' as const,\r\n width: '10px',\r\n height: '10px',\r\n top: '-10px',\r\n animation: 'confettiFall 3s ease-out forwards',\r\n },\r\n loading: {\r\n textAlign: 'center' as const,\r\n padding: '40px',\r\n color: '#6b7280',\r\n },\r\n error: {\r\n textAlign: 'center' as const,\r\n padding: '40px',\r\n color: '#ef4444',\r\n },\r\n intro: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n padding: '48px 24px',\r\n textAlign: 'center' as const,\r\n background: 'linear-gradient(135deg, #f3e8ff 0%, #e0e7ff 50%, #fce7f3 100%)',\r\n borderRadius: '16px',\r\n minHeight: '320px',\r\n },\r\n introTitle: {\r\n fontSize: '28px',\r\n fontWeight: '700',\r\n color: '#4c1d95',\r\n marginBottom: '12px',\r\n },\r\n introSubtitle: {\r\n fontSize: '16px',\r\n color: '#6b7280',\r\n marginBottom: '8px',\r\n },\r\n introQuestionCount: {\r\n fontSize: '14px',\r\n color: '#8b5cf6',\r\n marginBottom: '32px',\r\n fontWeight: '500',\r\n },\r\n startButton: {\r\n padding: '16px 48px',\r\n fontSize: '18px',\r\n fontWeight: '600',\r\n backgroundColor: '#7c3aed',\r\n color: '#ffffff',\r\n border: 'none',\r\n borderRadius: '12px',\r\n cursor: 'pointer',\r\n transition: 'all 0.2s ease',\r\n boxShadow: '0 4px 14px rgba(124, 58, 237, 0.4)',\r\n },\r\n feedback: {\r\n marginTop: '16px',\r\n padding: '16px',\r\n borderRadius: '8px',\r\n backgroundColor: '#f9fafb',\r\n border: '1px solid #e5e7eb',\r\n },\r\n feedbackCorrect: {\r\n backgroundColor: '#f0fdf4',\r\n borderColor: '#22c55e',\r\n },\r\n feedbackIncorrect: {\r\n backgroundColor: '#fef2f2',\r\n borderColor: '#ef4444',\r\n },\r\n feedbackTitle: {\r\n fontSize: '16px',\r\n fontWeight: '600',\r\n marginBottom: '8px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n },\r\n feedbackTitleCorrect: {\r\n color: '#16a34a',\r\n },\r\n feedbackTitleIncorrect: {\r\n color: '#dc2626',\r\n },\r\n feedbackExplanation: {\r\n fontSize: '14px',\r\n color: '#4b5563',\r\n lineHeight: '1.5',\r\n },\r\n};\r\n\r\n// Inline spinner component\r\nfunction Spinner({ size = 16, color = '#ffffff' }: { size?: number; color?: string }) {\r\n return (\r\n <span\r\n style={{\r\n display: 'inline-block',\r\n width: size,\r\n height: size,\r\n border: `2px solid ${color}`,\r\n borderTopColor: 'transparent',\r\n borderRadius: '50%',\r\n animation: 'spin 0.8s linear infinite',\r\n }}\r\n >\r\n <style>\r\n {`@keyframes spin { to { transform: rotate(360deg); } }`}\r\n </style>\r\n </span>\r\n );\r\n}\r\n\r\nexport function QuizPlayer({\r\n quizId,\r\n lessonId,\r\n assignLessonId,\r\n courseId,\r\n childId,\r\n parentId,\r\n apiBaseUrl,\r\n authToken,\r\n onComplete,\r\n onError,\r\n onProgress,\r\n onGenerateMoreQuestions,\r\n className,\r\n forceNewAttempt = true,\r\n}: QuizPlayerProps) {\r\n const [quiz, setQuiz] = useState<Quiz | null>(null);\r\n const [attempt, setAttempt] = useState<ExternalQuizAttempt | null>(null);\r\n const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);\r\n const [answers, setAnswers] = useState<Map<string, unknown>>(new Map());\r\n const [answersDetail, setAnswersDetail] = useState<QuizAnswerDetail[]>([]);\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [isNavigating, setIsNavigating] = useState(false);\r\n const [isCompleted, setIsCompleted] = useState(false);\r\n const [result, setResult] = useState<QuizResult | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n const [isLoading, setIsLoading] = useState(true);\r\n const [elapsedSeconds, setElapsedSeconds] = useState(0);\r\n const [showIntro, setShowIntro] = useState(true);\r\n const [timerStarted, setTimerStarted] = useState(false);\r\n const [showFeedback, setShowFeedback] = useState(false);\r\n const [currentAnswerDetail, setCurrentAnswerDetail] = useState<QuizAnswerDetail | null>(null);\r\n const [extraQuestions, setExtraQuestions] = useState<QuizQuestion[]>([]);\r\n const [isGeneratingExtra, setIsGeneratingExtra] = useState(false);\r\n const [showSkipModal, setShowSkipModal] = useState(false);\r\n const [skippedQuestionIds, setSkippedQuestionIds] = useState<Set<string>>(new Set());\r\n const [isSkipping, setIsSkipping] = useState(false);\r\n const [skipComment, setSkipComment] = useState('');\r\n const [selectedSkipReason, setSelectedSkipReason] = useState<SkipReason | null>(null);\r\n \r\n // Report states (for premade questions)\r\n const [showReportModal, setShowReportModal] = useState(false);\r\n const [isReporting, setIsReporting] = useState(false);\r\n const [reportComment, setReportComment] = useState('');\r\n\r\n const apiClient = useRef<QuizApiClient | null>(null);\r\n const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);\r\n const startTimeRef = useRef<number>(0);\r\n\r\n // Refs for callback props to prevent useEffect re-runs when parent re-renders\r\n const onCompleteRef = useRef(onComplete);\r\n const onErrorRef = useRef(onError);\r\n const onProgressRef = useRef(onProgress);\r\n const onGenerateMoreQuestionsRef = useRef(onGenerateMoreQuestions);\r\n\r\n // Keep refs up to date with latest callbacks\r\n useEffect(() => {\r\n onCompleteRef.current = onComplete;\r\n onErrorRef.current = onError;\r\n onProgressRef.current = onProgress;\r\n onGenerateMoreQuestionsRef.current = onGenerateMoreQuestions;\r\n });\r\n\r\n // Initialize API client\r\n useEffect(() => {\r\n apiClient.current = new QuizApiClient({ baseUrl: apiBaseUrl, authToken });\r\n }, [apiBaseUrl, authToken]);\r\n\r\n // Load quiz and create/resume attempt\r\n useEffect(() => {\r\n async function initialize() {\r\n if (!apiClient.current) return;\r\n\r\n try {\r\n setIsLoading(true);\r\n setError(null);\r\n\r\n // Fetch quiz\r\n const quizData = await apiClient.current.getQuiz(quizId);\r\n setQuiz(quizData);\r\n\r\n // Create attempt (forceNew ensures clean slate for multiple attempts)\r\n const attemptData = await apiClient.current.createAttempt({\r\n quizId,\r\n lessonId,\r\n assignLessonId,\r\n courseId,\r\n childId,\r\n parentId,\r\n forceNew: forceNewAttempt,\r\n });\r\n setAttempt(attemptData);\r\n\r\n // Resume from existing answers if resuming an in-progress attempt (not forcing new)\r\n if (!forceNewAttempt && attemptData.answers && attemptData.answers.length > 0) {\r\n setAnswersDetail(attemptData.answers);\r\n const answersMap = new Map<string, unknown>();\r\n attemptData.answers.forEach(a => {\r\n answersMap.set(a.questionId, a.selectedAnswer);\r\n });\r\n setAnswers(answersMap);\r\n }\r\n\r\n // Check if already completed\r\n if (attemptData.status === 'completed') {\r\n setIsCompleted(true);\r\n const scoreData = calculateScore(attemptData.answers);\r\n setResult({\r\n attemptId: attemptData.id,\r\n score: attemptData.score || scoreData.score,\r\n correctAnswers: attemptData.correctAnswers || scoreData.correctAnswers,\r\n totalQuestions: attemptData.totalQuestions,\r\n answers: attemptData.answers,\r\n timeSpentSeconds: attemptData.timeSpentSeconds || 0,\r\n });\r\n }\r\n\r\n setIsLoading(false);\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : 'Failed to load quiz';\r\n setError(message);\r\n setIsLoading(false);\r\n onErrorRef.current?.(err instanceof Error ? err : new Error(message));\r\n }\r\n }\r\n\r\n initialize();\r\n }, [quizId, lessonId, assignLessonId, courseId, childId, parentId, forceNewAttempt]);\r\n\r\n // Timer - only starts when timerStarted is true (after clicking Start)\r\n useEffect(() => {\r\n if (timerStarted && !isCompleted && !error) {\r\n startTimeRef.current = Date.now();\r\n timerRef.current = setInterval(() => {\r\n setElapsedSeconds(Math.floor((Date.now() - startTimeRef.current) / 1000));\r\n }, 1000);\r\n }\r\n\r\n return () => {\r\n if (timerRef.current) {\r\n clearInterval(timerRef.current);\r\n }\r\n };\r\n }, [timerStarted, isCompleted, error]);\r\n\r\n // Handle start button click\r\n const handleStart = useCallback(() => {\r\n setShowIntro(false);\r\n setTimerStarted(true);\r\n }, []);\r\n\r\n // Reset feedback state when question changes\r\n useEffect(() => {\r\n setShowFeedback(false);\r\n setCurrentAnswerDetail(null);\r\n }, [currentQuestionIndex]);\r\n\r\n // Combine original questions with extra generated questions, excluding skipped ones\r\n const allQuestions = quiz \r\n ? [...quiz.questions, ...extraQuestions].filter(q => !skippedQuestionIds.has(q.id)) \r\n : [];\r\n const totalQuestions = allQuestions.length;\r\n const maxQuestions = 50;\r\n\r\n // Report progress\r\n useEffect(() => {\r\n if (quiz && onProgressRef.current) {\r\n onProgressRef.current({\r\n currentQuestion: currentQuestionIndex + 1,\r\n totalQuestions: totalQuestions,\r\n answeredQuestions: answers.size,\r\n });\r\n }\r\n }, [currentQuestionIndex, answers.size, quiz, totalQuestions]);\r\n\r\n const currentQuestion = allQuestions[currentQuestionIndex];\r\n\r\n const handleAnswerChange = useCallback((value: unknown) => {\r\n if (!currentQuestion) return;\r\n setAnswers(prev => new Map(prev).set(currentQuestion.id, value));\r\n }, [currentQuestion]);\r\n\r\n // Check answer and show feedback\r\n const handleCheckAnswer = useCallback(async () => {\r\n if (!quiz || !attempt || !currentQuestion || !apiClient.current) return;\r\n\r\n const selectedAnswer = answers.get(currentQuestion.id);\r\n if (selectedAnswer === undefined) return;\r\n\r\n setIsNavigating(true);\r\n\r\n // Create answer detail\r\n const answerDetail = createAnswerDetail(currentQuestion, selectedAnswer);\r\n setCurrentAnswerDetail(answerDetail);\r\n \r\n // Update answers detail state\r\n const newAnswersDetail = [...answersDetail];\r\n const existingIdx = newAnswersDetail.findIndex(a => a.questionId === currentQuestion.id);\r\n if (existingIdx >= 0) {\r\n newAnswersDetail[existingIdx] = answerDetail;\r\n } else {\r\n newAnswersDetail.push(answerDetail);\r\n }\r\n setAnswersDetail(newAnswersDetail);\r\n\r\n // Save progress to server\r\n try {\r\n await apiClient.current.updateAttempt(attempt.id, {\r\n answers: newAnswersDetail,\r\n });\r\n } catch (err) {\r\n console.error('Failed to save progress:', err);\r\n } finally {\r\n setIsNavigating(false);\r\n }\r\n\r\n // Show feedback instead of moving to next question\r\n setShowFeedback(true);\r\n }, [quiz, attempt, currentQuestion, answers, answersDetail]);\r\n\r\n // Continue to next question after viewing feedback\r\n const handleContinue = useCallback(() => {\r\n if (!quiz) return;\r\n \r\n setShowFeedback(false);\r\n setCurrentAnswerDetail(null);\r\n \r\n // Move to next question (use totalQuestions which includes extras)\r\n if (currentQuestionIndex < totalQuestions - 1) {\r\n setCurrentQuestionIndex(prev => prev + 1);\r\n }\r\n }, [quiz, currentQuestionIndex, totalQuestions]);\r\n\r\n // Generate more questions handler\r\n const handleAddMoreQuestions = useCallback(async () => {\r\n if (!attempt || !onGenerateMoreQuestions || isGeneratingExtra) return;\r\n \r\n // Check if we've reached the limit\r\n if (totalQuestions >= maxQuestions) return;\r\n \r\n setIsGeneratingExtra(true);\r\n try {\r\n const result = await onGenerateMoreQuestionsRef.current!(attempt.id, totalQuestions);\r\n \r\n if (result.extraQuestions && result.extraQuestions.length > 0) {\r\n // Clamp new questions to not exceed 50 total\r\n const slotsAvailable = maxQuestions - totalQuestions;\r\n const questionsToAppend = result.extraQuestions.slice(0, slotsAvailable);\r\n \r\n if (questionsToAppend.length > 0) {\r\n setExtraQuestions(prev => [...prev, ...questionsToAppend]);\r\n \r\n // Move to the first new question\r\n setCurrentQuestionIndex(totalQuestions);\r\n setShowFeedback(false);\r\n setCurrentAnswerDetail(null);\r\n }\r\n }\r\n } catch (err) {\r\n console.error('Failed to generate extra questions:', err);\r\n onErrorRef.current?.(err instanceof Error ? err : new Error('Failed to generate extra questions'));\r\n } finally {\r\n setIsGeneratingExtra(false);\r\n }\r\n }, [attempt, isGeneratingExtra, totalQuestions, maxQuestions]);\r\n\r\n const handleSubmit = useCallback(async () => {\r\n if (!quiz || !attempt || !apiClient.current) return;\r\n\r\n setIsSubmitting(true);\r\n\r\n try {\r\n // Ensure current answer is saved\r\n const currentAnswer = currentQuestion ? answers.get(currentQuestion.id) : undefined;\r\n let finalAnswersDetail = [...answersDetail];\r\n \r\n if (currentQuestion && currentAnswer !== undefined) {\r\n const answerDetail = createAnswerDetail(currentQuestion, currentAnswer);\r\n const existingIdx = finalAnswersDetail.findIndex(a => a.questionId === currentQuestion.id);\r\n if (existingIdx >= 0) {\r\n finalAnswersDetail[existingIdx] = answerDetail;\r\n } else {\r\n finalAnswersDetail.push(answerDetail);\r\n }\r\n }\r\n\r\n // Calculate final score\r\n const scoreData = calculateScore(finalAnswersDetail);\r\n const timeSpent = timerStarted && startTimeRef.current > 0 \r\n ? Math.floor((Date.now() - startTimeRef.current) / 1000) \r\n : elapsedSeconds;\r\n\r\n // Submit to server (include totalQuestions to account for dynamically added extra questions)\r\n const updatedAttempt = await apiClient.current.updateAttempt(attempt.id, {\r\n answers: finalAnswersDetail,\r\n status: 'completed',\r\n score: scoreData.score,\r\n correctAnswers: scoreData.correctAnswers,\r\n totalQuestions: totalQuestions,\r\n timeSpentSeconds: timeSpent,\r\n });\r\n\r\n // Update state\r\n setIsCompleted(true);\r\n const quizResult: QuizResult = {\r\n attemptId: updatedAttempt.id,\r\n score: scoreData.score,\r\n correctAnswers: scoreData.correctAnswers,\r\n totalQuestions: totalQuestions,\r\n answers: finalAnswersDetail,\r\n timeSpentSeconds: timeSpent,\r\n };\r\n setResult(quizResult);\r\n\r\n // Stop timer\r\n if (timerRef.current) {\r\n clearInterval(timerRef.current);\r\n }\r\n\r\n // Callback\r\n onCompleteRef.current?.(quizResult);\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : 'Failed to submit quiz';\r\n setError(message);\r\n onErrorRef.current?.(err instanceof Error ? err : new Error(message));\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n }, [quiz, attempt, currentQuestion, answers, answersDetail, totalQuestions, timerStarted, elapsedSeconds]);\r\n\r\n // Check if current question is an \"extra\" (dynamically generated) question\r\n const isExtraQuestion = currentQuestion && extraQuestions.some(q => q.id === currentQuestion.id);\r\n\r\n // Handle skip question (only for extra questions)\r\n const handleSkipQuestion = useCallback(async (reason: SkipReason, comment?: string) => {\r\n if (!currentQuestion || !apiClient.current || !attempt) return;\r\n \r\n setIsSkipping(true);\r\n try {\r\n // Submit skip to backend\r\n await apiClient.current.skipQuestion({\r\n questionId: currentQuestion.id,\r\n questionContent: currentQuestion,\r\n skipReason: reason,\r\n skipComment: comment?.trim() || undefined,\r\n quizId: quiz?.id,\r\n attemptId: attempt.id,\r\n childId,\r\n parentId,\r\n lessonId,\r\n courseId,\r\n assignLessonId,\r\n });\r\n\r\n // Mark question as skipped (remove from active questions)\r\n const newSkippedIds = new Set(skippedQuestionIds).add(currentQuestion.id);\r\n setSkippedQuestionIds(newSkippedIds);\r\n \r\n // Remove from extraQuestions\r\n const newExtraQuestions = extraQuestions.filter(q => q.id !== currentQuestion.id);\r\n setExtraQuestions(newExtraQuestions);\r\n \r\n // Calculate new total questions after skip\r\n const newAllQuestions = quiz \r\n ? [...quiz.questions, ...newExtraQuestions].filter(q => !newSkippedIds.has(q.id))\r\n : [];\r\n const newTotalQuestions = newAllQuestions.length;\r\n \r\n // Handle navigation after skip\r\n if (newTotalQuestions === 0) {\r\n // All questions skipped - complete the quiz\r\n setIsCompleted(true);\r\n const quizResult: QuizResult = {\r\n attemptId: attempt.id,\r\n score: 0,\r\n correctAnswers: 0,\r\n totalQuestions: 0,\r\n answers: [],\r\n timeSpentSeconds: elapsedSeconds,\r\n };\r\n setResult(quizResult);\r\n onCompleteRef.current?.(quizResult);\r\n } else if (currentQuestionIndex >= newTotalQuestions) {\r\n // We were at the last question, move back to the new last question\r\n setCurrentQuestionIndex(newTotalQuestions - 1);\r\n }\r\n // Otherwise stay at current index (next question slides into place)\r\n \r\n // Close modal and reset state\r\n setShowSkipModal(false);\r\n setSkipComment('');\r\n setSelectedSkipReason(null);\r\n } catch (err) {\r\n console.error('Failed to skip question:', err);\r\n } finally {\r\n setIsSkipping(false);\r\n }\r\n }, [currentQuestion, apiClient, attempt, quiz, childId, parentId, lessonId, courseId, assignLessonId, skippedQuestionIds, extraQuestions, currentQuestionIndex, elapsedSeconds]);\r\n\r\n // Handle report question (only for premade questions - doesn't remove question)\r\n const handleReportQuestion = useCallback(async (comment: string) => {\r\n if (!currentQuestion || !apiClient.current || !attempt || !comment.trim()) return;\r\n \r\n setIsReporting(true);\r\n try {\r\n // Submit report to backend\r\n await apiClient.current.reportQuestion({\r\n questionId: currentQuestion.id,\r\n questionContent: currentQuestion,\r\n reportComment: comment.trim(),\r\n quizId: quiz?.id,\r\n attemptId: attempt.id,\r\n childId,\r\n parentId,\r\n lessonId,\r\n courseId,\r\n assignLessonId,\r\n });\r\n\r\n // Close modal and reset state (question remains - user still answers it)\r\n setShowReportModal(false);\r\n setReportComment('');\r\n } catch (err) {\r\n console.error('Failed to report question:', err);\r\n } finally {\r\n setIsReporting(false);\r\n }\r\n }, [currentQuestion, apiClient, attempt, quiz, childId, parentId, lessonId, courseId, assignLessonId]);\r\n\r\n // Render loading state\r\n if (isLoading) {\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <div style={defaultStyles.loading}>Loading quiz...</div>\r\n </div>\r\n );\r\n }\r\n\r\n // Render error state\r\n if (error) {\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <div style={defaultStyles.error}>\r\n <p>Error: {error}</p>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n // Render completed state\r\n if (isCompleted && result) {\r\n // Calculate percentage based on correct answers (not points)\r\n // Guard against division by zero when all questions were skipped\r\n const percentage = result.totalQuestions > 0 \r\n ? Math.round((result.correctAnswers / result.totalQuestions) * 100)\r\n : 0;\r\n \r\n // Determine theme based on percentage\r\n const getScoreTheme = (pct: number) => {\r\n if (pct >= 80) {\r\n return {\r\n color: '#22c55e',\r\n bgGradient: 'linear-gradient(135deg, #dcfce7 0%, #bbf7d0 50%, #86efac 100%)',\r\n badge: 'Quiz Champion!',\r\n badgeColor: '#fbbf24',\r\n badgeBg: 'linear-gradient(135deg, #fef3c7 0%, #fde68a 100%)',\r\n mascotMood: 'celebrating',\r\n stars: 3,\r\n };\r\n } else if (pct >= 60) {\r\n return {\r\n color: '#f59e0b',\r\n bgGradient: 'linear-gradient(135deg, #fef3c7 0%, #fde68a 50%, #fcd34d 100%)',\r\n badge: 'Rising Star!',\r\n badgeColor: '#f59e0b',\r\n badgeBg: 'linear-gradient(135deg, #fed7aa 0%, #fdba74 100%)',\r\n mascotMood: 'happy',\r\n stars: 2,\r\n };\r\n } else if (pct >= 40) {\r\n return {\r\n color: '#3b82f6',\r\n bgGradient: 'linear-gradient(135deg, #dbeafe 0%, #bfdbfe 50%, #93c5fd 100%)',\r\n badge: 'Great Learner!',\r\n badgeColor: '#3b82f6',\r\n badgeBg: 'linear-gradient(135deg, #bfdbfe 0%, #93c5fd 100%)',\r\n mascotMood: 'encouraging',\r\n stars: 1,\r\n };\r\n } else {\r\n return {\r\n color: '#8b5cf6',\r\n bgGradient: 'linear-gradient(135deg, #f3e8ff 0%, #e9d5ff 50%, #d8b4fe 100%)',\r\n badge: 'Keep Growing!',\r\n badgeColor: '#8b5cf6',\r\n badgeBg: 'linear-gradient(135deg, #e9d5ff 0%, #d8b4fe 100%)',\r\n mascotMood: 'supportive',\r\n stars: 0,\r\n };\r\n }\r\n };\r\n\r\n const theme = getScoreTheme(percentage);\r\n\r\n // Generate confetti pieces\r\n const confettiColors = ['#f43f5e', '#ec4899', '#8b5cf6', '#3b82f6', '#22c55e', '#f59e0b', '#ef4444'];\r\n const confettiPieces = Array.from({ length: 50 }, (_, i) => ({\r\n id: i,\r\n left: `${Math.random() * 100}%`,\r\n delay: `${Math.random() * 2}s`,\r\n duration: `${2 + Math.random() * 2}s`,\r\n color: confettiColors[Math.floor(Math.random() * confettiColors.length)],\r\n rotation: Math.random() * 360,\r\n size: 6 + Math.random() * 8,\r\n }));\r\n\r\n // Star SVG component\r\n const StarIcon = ({ filled, delay }: { filled: boolean; delay: number }) => (\r\n <svg\r\n width=\"36\"\r\n height=\"36\"\r\n viewBox=\"0 0 24 24\"\r\n style={{\r\n animation: 'starPop 0.5s ease-out forwards',\r\n animationDelay: `${delay}s`,\r\n opacity: 0,\r\n }}\r\n >\r\n <path\r\n d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\"\r\n fill={filled ? '#fbbf24' : '#e5e7eb'}\r\n stroke={filled ? '#f59e0b' : '#d1d5db'}\r\n strokeWidth=\"1\"\r\n />\r\n </svg>\r\n );\r\n\r\n // Mascot SVG component - a friendly owl character\r\n const MascotOwl = ({ mood }: { mood: string }) => {\r\n const getEyeExpression = () => {\r\n switch (mood) {\r\n case 'celebrating':\r\n return { leftEye: '>', rightEye: '<', pupilY: 42 }; // Squinting happy\r\n case 'happy':\r\n return { leftEye: null, rightEye: null, pupilY: 42 }; // Normal happy\r\n case 'encouraging':\r\n return { leftEye: null, rightEye: null, pupilY: 44 }; // Looking down warmly\r\n default:\r\n return { leftEye: null, rightEye: null, pupilY: 42 }; // Supportive\r\n }\r\n };\r\n const eyeExpr = getEyeExpression();\r\n\r\n return (\r\n <svg\r\n width=\"120\"\r\n height=\"120\"\r\n viewBox=\"0 0 100 100\"\r\n style={{\r\n animation: mood === 'celebrating' ? 'bounce 0.6s ease-in-out infinite' : 'gentleBob 2s ease-in-out infinite',\r\n }}\r\n >\r\n {/* Body */}\r\n <ellipse cx=\"50\" cy=\"60\" rx=\"35\" ry=\"30\" fill=\"#8b5cf6\" />\r\n {/* Belly */}\r\n <ellipse cx=\"50\" cy=\"65\" rx=\"25\" ry=\"20\" fill=\"#c4b5fd\" />\r\n {/* Head */}\r\n <circle cx=\"50\" cy=\"35\" r=\"28\" fill=\"#a78bfa\" />\r\n {/* Ear tufts */}\r\n <polygon points=\"28,15 35,30 22,28\" fill=\"#7c3aed\" />\r\n <polygon points=\"72,15 65,30 78,28\" fill=\"#7c3aed\" />\r\n {/* Eye whites */}\r\n <ellipse cx=\"38\" cy=\"38\" rx=\"10\" ry=\"12\" fill=\"white\" />\r\n <ellipse cx=\"62\" cy=\"38\" rx=\"10\" ry=\"12\" fill=\"white\" />\r\n {/* Pupils */}\r\n {eyeExpr.leftEye ? (\r\n <text x=\"38\" y=\"44\" textAnchor=\"middle\" fontSize=\"16\" fill=\"#1f2937\">{eyeExpr.leftEye}</text>\r\n ) : (\r\n <circle cx=\"38\" cy={eyeExpr.pupilY} r=\"5\" fill=\"#1f2937\" />\r\n )}\r\n {eyeExpr.rightEye ? (\r\n <text x=\"62\" y=\"44\" textAnchor=\"middle\" fontSize=\"16\" fill=\"#1f2937\">{eyeExpr.rightEye}</text>\r\n ) : (\r\n <circle cx=\"62\" cy={eyeExpr.pupilY} r=\"5\" fill=\"#1f2937\" />\r\n )}\r\n {/* Beak */}\r\n <polygon points=\"50,45 45,52 55,52\" fill=\"#fbbf24\" />\r\n {/* Blush for happy moods */}\r\n {(mood === 'celebrating' || mood === 'happy') && (\r\n <>\r\n <ellipse cx=\"28\" cy=\"45\" rx=\"5\" ry=\"3\" fill=\"#fda4af\" opacity=\"0.6\" />\r\n <ellipse cx=\"72\" cy=\"45\" rx=\"5\" ry=\"3\" fill=\"#fda4af\" opacity=\"0.6\" />\r\n </>\r\n )}\r\n {/* Wings */}\r\n {mood === 'celebrating' ? (\r\n <>\r\n <ellipse cx=\"18\" cy=\"55\" rx=\"8\" ry=\"15\" fill=\"#7c3aed\" transform=\"rotate(-30 18 55)\" />\r\n <ellipse cx=\"82\" cy=\"55\" rx=\"8\" ry=\"15\" fill=\"#7c3aed\" transform=\"rotate(30 82 55)\" />\r\n </>\r\n ) : (\r\n <>\r\n <ellipse cx=\"20\" cy=\"60\" rx=\"8\" ry=\"15\" fill=\"#7c3aed\" />\r\n <ellipse cx=\"80\" cy=\"60\" rx=\"8\" ry=\"15\" fill=\"#7c3aed\" />\r\n </>\r\n )}\r\n {/* Feet */}\r\n <ellipse cx=\"40\" cy=\"88\" rx=\"8\" ry=\"4\" fill=\"#fbbf24\" />\r\n <ellipse cx=\"60\" cy=\"88\" rx=\"8\" ry=\"4\" fill=\"#fbbf24\" />\r\n </svg>\r\n );\r\n };\r\n\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <style>\r\n {`\r\n @keyframes confettiFall {\r\n 0% {\r\n transform: translateY(-10px) rotate(0deg);\r\n opacity: 1;\r\n }\r\n 100% {\r\n transform: translateY(500px) rotate(720deg);\r\n opacity: 0;\r\n }\r\n }\r\n @keyframes starPop {\r\n 0% {\r\n transform: scale(0);\r\n opacity: 0;\r\n }\r\n 50% {\r\n transform: scale(1.3);\r\n }\r\n 100% {\r\n transform: scale(1);\r\n opacity: 1;\r\n }\r\n }\r\n @keyframes bounce {\r\n 0%, 100% {\r\n transform: translateY(0);\r\n }\r\n 50% {\r\n transform: translateY(-10px);\r\n }\r\n }\r\n @keyframes gentleBob {\r\n 0%, 100% {\r\n transform: translateY(0);\r\n }\r\n 50% {\r\n transform: translateY(-5px);\r\n }\r\n }\r\n @keyframes badgePop {\r\n 0% {\r\n transform: scale(0) rotate(-10deg);\r\n opacity: 0;\r\n }\r\n 60% {\r\n transform: scale(1.1) rotate(5deg);\r\n }\r\n 100% {\r\n transform: scale(1) rotate(0deg);\r\n opacity: 1;\r\n }\r\n }\r\n @keyframes scoreSlideIn {\r\n 0% {\r\n transform: translateY(20px);\r\n opacity: 0;\r\n }\r\n 100% {\r\n transform: translateY(0);\r\n opacity: 1;\r\n }\r\n }\r\n `}\r\n </style>\r\n <div style={defaultStyles.results}>\r\n {/* Confetti animation for high scores */}\r\n {percentage >= 60 && (\r\n <div style={defaultStyles.confettiContainer}>\r\n {confettiPieces.map((piece) => (\r\n <div\r\n key={piece.id}\r\n style={{\r\n ...defaultStyles.confettiPiece,\r\n left: piece.left,\r\n width: `${piece.size}px`,\r\n height: `${piece.size}px`,\r\n backgroundColor: piece.color,\r\n borderRadius: Math.random() > 0.5 ? '50%' : '2px',\r\n animationDelay: piece.delay,\r\n animationDuration: piece.duration,\r\n transform: `rotate(${piece.rotation}deg)`,\r\n }}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Background gradient */}\r\n <div style={{ ...defaultStyles.resultsBackground, background: theme.bgGradient }} />\r\n\r\n {/* Content */}\r\n <div style={defaultStyles.resultsContent}>\r\n {/* Stars */}\r\n <div style={defaultStyles.resultStars}>\r\n <StarIcon filled={theme.stars >= 1} delay={0.3} />\r\n <StarIcon filled={theme.stars >= 2} delay={0.5} />\r\n <StarIcon filled={theme.stars >= 3} delay={0.7} />\r\n </div>\r\n\r\n {/* Mascot Character */}\r\n <div style={{ marginBottom: '16px' }}>\r\n <MascotOwl mood={theme.mascotMood} />\r\n </div>\r\n\r\n {/* Achievement Badge */}\r\n <div\r\n style={{\r\n background: theme.badgeBg,\r\n padding: '12px 28px',\r\n borderRadius: '50px',\r\n boxShadow: '0 4px 12px rgba(0,0,0,0.15)',\r\n marginBottom: '20px',\r\n animation: 'badgePop 0.6s ease-out 0.2s forwards',\r\n opacity: 0,\r\n border: `3px solid ${theme.badgeColor}`,\r\n }}\r\n >\r\n <span\r\n style={{\r\n fontSize: '22px',\r\n fontWeight: '700',\r\n color: '#1f2937',\r\n textShadow: '0 1px 2px rgba(255,255,255,0.5)',\r\n }}\r\n >\r\n {theme.badge}\r\n </span>\r\n </div>\r\n\r\n {/* Big Score Display */}\r\n <div\r\n style={{\r\n animation: 'scoreSlideIn 0.5s ease-out 0.4s forwards',\r\n opacity: 0,\r\n }}\r\n >\r\n <div\r\n style={{\r\n fontSize: '48px',\r\n fontWeight: '800',\r\n color: theme.color,\r\n lineHeight: '1',\r\n marginBottom: '4px',\r\n }}\r\n >\r\n {result.correctAnswers} of {result.totalQuestions}\r\n </div>\r\n <div\r\n style={{\r\n fontSize: '20px',\r\n fontWeight: '600',\r\n color: '#6b7280',\r\n marginBottom: '12px',\r\n }}\r\n >\r\n correct answers\r\n </div>\r\n </div>\r\n\r\n {/* Time */}\r\n <div style={{ ...defaultStyles.resultDetails, marginTop: '8px' }}>\r\n Time: {formatTime(result.timeSpentSeconds)}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n // Render intro screen (after quiz is loaded but before requiring currentQuestion)\r\n if (quiz && showIntro) {\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <div style={defaultStyles.intro}>\r\n <div style={defaultStyles.introTitle}>{quiz.title}</div>\r\n <div style={defaultStyles.introSubtitle}>Ready to test your knowledge?</div>\r\n <div style={defaultStyles.introQuestionCount}>\r\n {quiz.questions.length} question{quiz.questions.length !== 1 ? 's' : ''} to answer\r\n </div>\r\n <button\r\n style={defaultStyles.startButton}\r\n onClick={handleStart}\r\n onMouseOver={(e) => {\r\n e.currentTarget.style.transform = 'translateY(-2px)';\r\n e.currentTarget.style.boxShadow = '0 6px 20px rgba(124, 58, 237, 0.5)';\r\n }}\r\n onMouseOut={(e) => {\r\n e.currentTarget.style.transform = 'translateY(0)';\r\n e.currentTarget.style.boxShadow = '0 4px 14px rgba(124, 58, 237, 0.4)';\r\n }}\r\n data-testid=\"button-start-quiz\"\r\n >\r\n Let's Start!\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n // Render quiz - guard for missing data\r\n if (!quiz || !currentQuestion) {\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <div style={defaultStyles.error}>No quiz data available</div>\r\n </div>\r\n );\r\n }\r\n\r\n const selectedAnswer = answers.get(currentQuestion.id);\r\n const isLastQuestion = currentQuestionIndex === totalQuestions - 1;\r\n const progressPercent = ((currentQuestionIndex + 1) / totalQuestions) * 100;\r\n const remainingSlots = maxQuestions - totalQuestions;\r\n const questionsToAdd = Math.min(5, remainingSlots);\r\n const canAddMore = onGenerateMoreQuestions && remainingSlots > 0;\r\n\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n {/* Main horizontal layout: left column + chat panel */}\r\n <div style={defaultStyles.mainLayout}>\r\n {/* Left column: header + quiz content */}\r\n <div style={defaultStyles.quizContent}>\r\n {/* Header - timer hidden to avoid exam pressure */}\r\n <div style={defaultStyles.header}>\r\n <div style={defaultStyles.title}>{quiz.title}</div>\r\n <div style={defaultStyles.progress}>\r\n Question {currentQuestionIndex + 1} of {totalQuestions}\r\n </div>\r\n <div style={defaultStyles.progressBar}>\r\n <div style={{ ...defaultStyles.progressFill, width: `${progressPercent}%` }} />\r\n </div>\r\n </div>\r\n {/* Question */}\r\n <div style={{ ...defaultStyles.question, position: 'relative', paddingBottom: '40px' }}>\r\n <div style={defaultStyles.questionText}>\r\n <TextToSpeech text={currentQuestion.question} inline size=\"md\" />\r\n </div>\r\n\r\n {/* Skip button for extra questions - subtle icon in bottom left */}\r\n {isExtraQuestion && (\r\n <button\r\n onClick={() => setShowSkipModal(true)}\r\n title=\"Skip question\"\r\n style={{\r\n position: 'absolute',\r\n bottom: '8px',\r\n left: '0',\r\n background: 'transparent',\r\n border: 'none',\r\n cursor: 'pointer',\r\n padding: '6px 10px',\r\n borderRadius: '6px',\r\n color: '#9ca3af',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n gap: '4px',\r\n fontSize: '12px',\r\n opacity: 0.6,\r\n transition: 'opacity 0.2s, color 0.2s',\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.opacity = '1';\r\n e.currentTarget.style.color = '#6b7280';\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.opacity = '0.6';\r\n e.currentTarget.style.color = '#9ca3af';\r\n }}\r\n data-testid=\"button-skip-question\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <polygon points=\"5 4 15 12 5 20 5 4\"></polygon>\r\n <line x1=\"19\" y1=\"5\" x2=\"19\" y2=\"19\"></line>\r\n </svg>\r\n <span>Skip</span>\r\n </button>\r\n )}\r\n\r\n {/* Report button for premade questions - subtle icon in bottom left */}\r\n {!isExtraQuestion && (\r\n <button\r\n onClick={() => setShowReportModal(true)}\r\n title=\"Report an issue with this question\"\r\n style={{\r\n position: 'absolute',\r\n bottom: '8px',\r\n left: '0',\r\n background: 'transparent',\r\n border: 'none',\r\n cursor: 'pointer',\r\n padding: '6px 10px',\r\n borderRadius: '6px',\r\n color: '#9ca3af',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n gap: '4px',\r\n fontSize: '12px',\r\n opacity: 0.6,\r\n transition: 'opacity 0.2s, color 0.2s',\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.opacity = '1';\r\n e.currentTarget.style.color = '#ef4444';\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.opacity = '0.6';\r\n e.currentTarget.style.color = '#9ca3af';\r\n }}\r\n data-testid=\"button-report-question\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <path d=\"M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z\"></path>\r\n <line x1=\"4\" y1=\"22\" x2=\"4\" y2=\"15\"></line>\r\n </svg>\r\n <span>Report</span>\r\n </button>\r\n )}\r\n\r\n {/* Render options based on question type */}\r\n {(currentQuestion.type === 'single' || currentQuestion.type === 'true-false') && (\r\n <div style={defaultStyles.options}>\r\n {currentQuestion.options?.map((option, idx) => {\r\n const isSelected = selectedAnswer === option;\r\n const isCorrectOption = currentQuestion.correctAnswer === option;\r\n \r\n let optionStyle = { ...defaultStyles.option };\r\n if (showFeedback) {\r\n if (isCorrectOption) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionCorrect };\r\n } else if (isSelected && !isCorrectOption) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionIncorrect };\r\n }\r\n } else if (isSelected) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };\r\n }\r\n \r\n return (\r\n <div\r\n key={idx}\r\n style={{\r\n ...optionStyle,\r\n cursor: showFeedback ? 'default' : 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n }}\r\n onClick={() => !showFeedback && handleAnswerChange(option)}\r\n >\r\n <span onClick={(e) => e.stopPropagation()}>\r\n <TextToSpeech text={option} size=\"sm\" />\r\n </span>\r\n <span style={{ flex: 1 }}>{option}</span>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {currentQuestion.type === 'multiple' && (\r\n <div style={defaultStyles.options}>\r\n {currentQuestion.options?.map((option, idx) => {\r\n const selected = Array.isArray(selectedAnswer) && selectedAnswer.includes(option);\r\n // Normalize correctAnswer to array (handle both string and array cases)\r\n const correctAnswers = Array.isArray(currentQuestion.correctAnswer) \r\n ? currentQuestion.correctAnswer \r\n : (currentQuestion.correctAnswer ? [currentQuestion.correctAnswer] : []);\r\n const isCorrectOption = correctAnswers.includes(option);\r\n \r\n let optionStyle = { ...defaultStyles.option };\r\n if (showFeedback) {\r\n if (isCorrectOption) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionCorrect };\r\n } else if (selected && !isCorrectOption) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionIncorrect };\r\n }\r\n } else if (selected) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };\r\n }\r\n \r\n return (\r\n <div\r\n key={idx}\r\n style={{\r\n ...optionStyle,\r\n cursor: showFeedback ? 'default' : 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n }}\r\n onClick={() => {\r\n if (showFeedback) return;\r\n const current = Array.isArray(selectedAnswer) ? selectedAnswer : [];\r\n if (selected) {\r\n handleAnswerChange(current.filter(o => o !== option));\r\n } else {\r\n handleAnswerChange([...current, option]);\r\n }\r\n }}\r\n >\r\n <span onClick={(e) => e.stopPropagation()}>\r\n <TextToSpeech text={option} size=\"sm\" />\r\n </span>\r\n <span style={{ flex: 1 }}>{option}</span>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {(currentQuestion.type === 'free' || currentQuestion.type === 'essay') && (\r\n <textarea\r\n style={{ ...defaultStyles.input, minHeight: currentQuestion.type === 'essay' ? '150px' : '60px' }}\r\n value={(selectedAnswer as string) || ''}\r\n onChange={e => handleAnswerChange(e.target.value)}\r\n placeholder=\"Type your answer here...\"\r\n disabled={showFeedback}\r\n />\r\n )}\r\n\r\n {currentQuestion.type === 'fill' && (\r\n <div style={defaultStyles.options}>\r\n {currentQuestion.blanks?.map((_, idx) => (\r\n <input\r\n key={idx}\r\n style={defaultStyles.input}\r\n value={(Array.isArray(selectedAnswer) ? selectedAnswer[idx] : '') || ''}\r\n onChange={e => {\r\n const current = Array.isArray(selectedAnswer) ? [...selectedAnswer] : [];\r\n current[idx] = e.target.value;\r\n handleAnswerChange(current);\r\n }}\r\n placeholder={`Blank ${idx + 1}`}\r\n disabled={showFeedback}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Feedback section */}\r\n {showFeedback && currentAnswerDetail && (\r\n <div style={{\r\n ...defaultStyles.feedback,\r\n ...(currentAnswerDetail.isCorrect ? defaultStyles.feedbackCorrect : defaultStyles.feedbackIncorrect),\r\n }}>\r\n <div style={{\r\n ...defaultStyles.feedbackTitle,\r\n ...(currentAnswerDetail.isCorrect ? defaultStyles.feedbackTitleCorrect : defaultStyles.feedbackTitleIncorrect),\r\n }}>\r\n {currentAnswerDetail.isCorrect ? '✓ Correct!' : '✗ Incorrect'}\r\n </div>\r\n {currentQuestion.explanation && (\r\n <div style={defaultStyles.feedbackExplanation}>\r\n {currentQuestion.explanation}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Skip reason modal */}\r\n {showSkipModal && (\r\n <div style={{\r\n position: 'fixed',\r\n top: 0,\r\n left: 0,\r\n right: 0,\r\n bottom: 0,\r\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n zIndex: 1000,\r\n }}>\r\n <div style={{\r\n backgroundColor: '#ffffff',\r\n borderRadius: '12px',\r\n padding: '24px',\r\n maxWidth: '400px',\r\n width: '90%',\r\n boxShadow: '0 20px 40px rgba(0, 0, 0, 0.2)',\r\n }}>\r\n <h3 style={{ margin: '0 0 8px 0', fontSize: '18px', fontWeight: '600', color: '#1f2937' }}>\r\n Skip Question\r\n </h3>\r\n <p style={{ margin: '0 0 16px 0', fontSize: '14px', color: '#6b7280' }}>\r\n Help us improve by telling us why you're skipping this question.\r\n </p>\r\n \r\n {/* Reason selection */}\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', marginBottom: '16px' }}>\r\n <button\r\n onClick={() => setSelectedSkipReason('question_issue')}\r\n disabled={isSkipping}\r\n style={{\r\n padding: '12px 16px',\r\n borderRadius: '8px',\r\n border: selectedSkipReason === 'question_issue' ? '2px solid #8b5cf6' : '1px solid #e5e7eb',\r\n backgroundColor: selectedSkipReason === 'question_issue' ? '#f5f3ff' : '#f9fafb',\r\n cursor: isSkipping ? 'not-allowed' : 'pointer',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n color: '#374151',\r\n textAlign: 'left',\r\n opacity: isSkipping ? 0.6 : 1,\r\n }}\r\n data-testid=\"button-skip-reason-issue\"\r\n >\r\n Question has an issue\r\n </button>\r\n <button\r\n onClick={() => setSelectedSkipReason('dont_know')}\r\n disabled={isSkipping}\r\n style={{\r\n padding: '12px 16px',\r\n borderRadius: '8px',\r\n border: selectedSkipReason === 'dont_know' ? '2px solid #8b5cf6' : '1px solid #e5e7eb',\r\n backgroundColor: selectedSkipReason === 'dont_know' ? '#f5f3ff' : '#f9fafb',\r\n cursor: isSkipping ? 'not-allowed' : 'pointer',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n color: '#374151',\r\n textAlign: 'left',\r\n opacity: isSkipping ? 0.6 : 1,\r\n }}\r\n data-testid=\"button-skip-reason-dont-know\"\r\n >\r\n I don't know the answer\r\n </button>\r\n </div>\r\n\r\n {/* Optional comment */}\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', fontSize: '13px', fontWeight: '500', color: '#374151', marginBottom: '6px' }}>\r\n Additional details (optional)\r\n </label>\r\n <textarea\r\n value={skipComment}\r\n onChange={(e) => setSkipComment(e.target.value.slice(0, 200))}\r\n placeholder=\"Tell us more about the issue...\"\r\n disabled={isSkipping}\r\n style={{\r\n width: '100%',\r\n minHeight: '80px',\r\n padding: '10px 12px',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n fontSize: '14px',\r\n resize: 'vertical',\r\n fontFamily: 'inherit',\r\n boxSizing: 'border-box',\r\n }}\r\n data-testid=\"input-skip-comment\"\r\n />\r\n <div style={{ fontSize: '12px', color: '#9ca3af', marginTop: '4px', textAlign: 'right' }}>\r\n {skipComment.length}/200\r\n </div>\r\n </div>\r\n\r\n {/* Action buttons */}\r\n <div style={{ display: 'flex', gap: '10px' }}>\r\n <button\r\n onClick={() => {\r\n setShowSkipModal(false);\r\n setSkipComment('');\r\n setSelectedSkipReason(null);\r\n }}\r\n style={{\r\n flex: 1,\r\n padding: '10px 16px',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n backgroundColor: '#ffffff',\r\n cursor: 'pointer',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n color: '#6b7280',\r\n }}\r\n data-testid=\"button-skip-cancel\"\r\n >\r\n Cancel\r\n </button>\r\n <button\r\n onClick={() => selectedSkipReason && handleSkipQuestion(selectedSkipReason, skipComment)}\r\n disabled={isSkipping || !selectedSkipReason}\r\n style={{\r\n flex: 1,\r\n padding: '10px 16px',\r\n borderRadius: '8px',\r\n border: 'none',\r\n backgroundColor: selectedSkipReason ? '#8b5cf6' : '#d1d5db',\r\n cursor: (isSkipping || !selectedSkipReason) ? 'not-allowed' : 'pointer',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n color: '#ffffff',\r\n opacity: isSkipping ? 0.6 : 1,\r\n }}\r\n data-testid=\"button-skip-submit\"\r\n >\r\n {isSkipping ? 'Skipping...' : 'Skip Question'}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Report question modal (for premade questions) */}\r\n {showReportModal && (\r\n <div style={{\r\n position: 'fixed',\r\n top: 0,\r\n left: 0,\r\n right: 0,\r\n bottom: 0,\r\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n zIndex: 1000,\r\n }}>\r\n <div style={{\r\n backgroundColor: '#ffffff',\r\n borderRadius: '12px',\r\n padding: '24px',\r\n maxWidth: '400px',\r\n width: '90%',\r\n boxShadow: '0 20px 40px rgba(0, 0, 0, 0.2)',\r\n }}>\r\n <h3 style={{ margin: '0 0 8px 0', fontSize: '18px', fontWeight: '600', color: '#1f2937' }}>\r\n Report Question\r\n </h3>\r\n <p style={{ margin: '0 0 16px 0', fontSize: '14px', color: '#6b7280' }}>\r\n What's wrong with this question?\r\n </p>\r\n \r\n {/* Comment input */}\r\n <div style={{ marginBottom: '16px' }}>\r\n <textarea\r\n value={reportComment}\r\n onChange={(e) => setReportComment(e.target.value.slice(0, 300))}\r\n placeholder=\"Describe the issue with this question...\"\r\n disabled={isReporting}\r\n style={{\r\n width: '100%',\r\n minHeight: '120px',\r\n padding: '10px 12px',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n fontSize: '14px',\r\n resize: 'vertical',\r\n fontFamily: 'inherit',\r\n boxSizing: 'border-box',\r\n }}\r\n data-testid=\"input-report-comment\"\r\n />\r\n <div style={{ fontSize: '12px', color: '#9ca3af', marginTop: '4px', textAlign: 'right' }}>\r\n {reportComment.length}/300\r\n </div>\r\n </div>\r\n\r\n {/* Action buttons */}\r\n <div style={{ display: 'flex', gap: '10px' }}>\r\n <button\r\n onClick={() => {\r\n setShowReportModal(false);\r\n setReportComment('');\r\n }}\r\n style={{\r\n flex: 1,\r\n padding: '10px 16px',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n backgroundColor: '#ffffff',\r\n cursor: 'pointer',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n color: '#6b7280',\r\n }}\r\n data-testid=\"button-report-cancel\"\r\n >\r\n Cancel\r\n </button>\r\n <button\r\n onClick={() => handleReportQuestion(reportComment)}\r\n disabled={isReporting || !reportComment.trim()}\r\n style={{\r\n flex: 1,\r\n padding: '10px 16px',\r\n borderRadius: '8px',\r\n border: 'none',\r\n backgroundColor: reportComment.trim() ? '#ef4444' : '#d1d5db',\r\n cursor: (isReporting || !reportComment.trim()) ? 'not-allowed' : 'pointer',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n color: '#ffffff',\r\n opacity: isReporting ? 0.6 : 1,\r\n }}\r\n data-testid=\"button-report-submit\"\r\n >\r\n {isReporting ? 'Reporting...' : 'Report'}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Navigation buttons */}\r\n <div style={defaultStyles.buttonsColumn}>\r\n {/* Add More Questions button - shown on last question after feedback, if under 50 questions */}\r\n {showFeedback && isLastQuestion && canAddMore && (\r\n <button\r\n style={{\r\n ...defaultStyles.buttonAddMore,\r\n ...(isGeneratingExtra ? defaultStyles.buttonAddMoreDisabled : {}),\r\n }}\r\n onClick={handleAddMoreQuestions}\r\n disabled={isGeneratingExtra}\r\n data-testid=\"button-add-more-questions\"\r\n >\r\n {isGeneratingExtra ? (\r\n <>\r\n <Spinner size={16} color=\"#9ca3af\" />\r\n Generating Questions...\r\n </>\r\n ) : (\r\n <>+ Add {questionsToAdd} More Question{questionsToAdd !== 1 ? 's' : ''}</>\r\n )}\r\n </button>\r\n )}\r\n\r\n <div style={{ ...defaultStyles.buttons, justifyContent: 'flex-end' }}>\r\n {showFeedback ? (\r\n // After viewing feedback\r\n isLastQuestion ? (\r\n <button\r\n style={{\r\n ...defaultStyles.button,\r\n ...(isSubmitting || isGeneratingExtra ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary),\r\n }}\r\n onClick={handleSubmit}\r\n disabled={isSubmitting || isGeneratingExtra}\r\n data-testid=\"button-submit-quiz\"\r\n >\r\n {isSubmitting ? <Spinner size={16} color=\"#9ca3af\" /> : 'Submit Quiz'}\r\n </button>\r\n ) : (\r\n <button\r\n style={{\r\n ...defaultStyles.button,\r\n ...defaultStyles.buttonPrimary,\r\n }}\r\n onClick={handleContinue}\r\n data-testid=\"button-continue\"\r\n >\r\n Continue\r\n </button>\r\n )\r\n ) : (\r\n // Before checking answer\r\n <button\r\n style={{\r\n ...defaultStyles.button,\r\n ...(isNavigating || selectedAnswer === undefined ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary),\r\n }}\r\n onClick={handleCheckAnswer}\r\n disabled={isNavigating || selectedAnswer === undefined}\r\n data-testid=\"button-check-answer\"\r\n >\r\n {isNavigating ? <Spinner size={16} color=\"#9ca3af\" /> : 'Check Answer'}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n \r\n {/* Chat Panel - always visible on the right */}\r\n <div style={defaultStyles.chatPanel}>\r\n {apiClient.current && (\r\n <QuestionChatPanel\r\n apiClient={apiClient.current}\r\n question={{\r\n id: currentQuestion.id,\r\n question: currentQuestion.question,\r\n type: currentQuestion.type,\r\n options: currentQuestion.options,\r\n correctAnswer: currentQuestion.correctAnswer as string | string[] | undefined,\r\n explanation: currentQuestion.explanation,\r\n } as QuestionContextForChat}\r\n quizId={quiz.id}\r\n childId={childId}\r\n parentId={parentId}\r\n lessonId={lessonId}\r\n courseId={courseId}\r\n answerResult={showFeedback && currentAnswerDetail ? {\r\n wasIncorrect: !currentAnswerDetail.isCorrect,\r\n selectedAnswer: typeof selectedAnswer === 'string' ? selectedAnswer : Array.isArray(selectedAnswer) ? selectedAnswer.join(', ') : undefined,\r\n correctAnswer: typeof currentQuestion.correctAnswer === 'string' ? currentQuestion.correctAnswer : Array.isArray(currentQuestion.correctAnswer) ? currentQuestion.correctAnswer.join(', ') : undefined,\r\n explanation: currentQuestion.explanation,\r\n } : undefined}\r\n />\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import type { Quiz, ExternalQuizAttempt, QuizAnswerDetail, SkipQuestionPayload, ReportQuestionPayload, ChatSession, ChatMessageResponse, QuestionContextForChat, StarterPrompt, ChatMessage } from './types';\r\n\r\nexport interface ApiClientConfig {\r\n baseUrl: string;\r\n authToken?: string;\r\n}\r\n\r\nexport class QuizApiClient {\r\n private baseUrl: string;\r\n private authToken?: string;\r\n\r\n constructor(config: ApiClientConfig) {\r\n this.baseUrl = config.baseUrl.replace(/\\/$/, ''); // Remove trailing slash\r\n this.authToken = config.authToken;\r\n }\r\n\r\n private async request<T>(\r\n method: string,\r\n endpoint: string,\r\n body?: unknown\r\n ): Promise<T> {\r\n const headers: HeadersInit = {\r\n 'Content-Type': 'application/json',\r\n };\r\n\r\n if (this.authToken) {\r\n headers['Authorization'] = `Bearer ${this.authToken}`;\r\n }\r\n\r\n const response = await fetch(`${this.baseUrl}${endpoint}`, {\r\n method,\r\n headers,\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\r\n throw new Error(error.error || `HTTP ${response.status}`);\r\n }\r\n\r\n return response.json();\r\n }\r\n\r\n async getQuiz(quizId: string): Promise<Quiz> {\r\n return this.request<Quiz>('GET', `/api/external/quizzes/${quizId}`);\r\n }\r\n\r\n async createAttempt(params: {\r\n quizId: string;\r\n lessonId: string;\r\n assignLessonId: string;\r\n courseId: string;\r\n childId: string;\r\n parentId: string;\r\n forceNew?: boolean;\r\n }): Promise<ExternalQuizAttempt> {\r\n return this.request<ExternalQuizAttempt>('POST', '/api/external/quiz-attempts', params);\r\n }\r\n\r\n async updateAttempt(\r\n attemptId: string,\r\n data: {\r\n answers?: QuizAnswerDetail[];\r\n status?: 'in_progress' | 'completed' | 'abandoned';\r\n score?: number;\r\n correctAnswers?: number;\r\n totalQuestions?: number;\r\n timeSpentSeconds?: number;\r\n }\r\n ): Promise<ExternalQuizAttempt> {\r\n return this.request<ExternalQuizAttempt>(\r\n 'PATCH',\r\n `/api/external/quiz-attempts/${attemptId}`,\r\n data\r\n );\r\n }\r\n\r\n async getAttempt(attemptId: string): Promise<ExternalQuizAttempt> {\r\n return this.request<ExternalQuizAttempt>('GET', `/api/external/quiz-attempts/${attemptId}`);\r\n }\r\n\r\n async getAttempts(params: {\r\n assignLessonId?: string;\r\n childId?: string;\r\n quizId?: string;\r\n }): Promise<ExternalQuizAttempt[]> {\r\n const queryParams = new URLSearchParams();\r\n if (params.assignLessonId) queryParams.set('assignLessonId', params.assignLessonId);\r\n if (params.childId) queryParams.set('childId', params.childId);\r\n if (params.quizId) queryParams.set('quizId', params.quizId);\r\n\r\n return this.request<ExternalQuizAttempt[]>(\r\n 'GET',\r\n `/api/external/quiz-attempts?${queryParams.toString()}`\r\n );\r\n }\r\n\r\n async skipQuestion(payload: SkipQuestionPayload): Promise<{ success: boolean; id: string; message: string }> {\r\n return this.request<{ success: boolean; id: string; message: string }>(\r\n 'POST',\r\n '/api/external/skip-question',\r\n payload\r\n );\r\n }\r\n\r\n async reportQuestion(payload: ReportQuestionPayload): Promise<{ success: boolean; id: string; message: string }> {\r\n return this.request<{ success: boolean; id: string; message: string }>(\r\n 'POST',\r\n '/api/external/report-question',\r\n payload\r\n );\r\n }\r\n\r\n async getStarterPrompts(): Promise<StarterPrompt[]> {\r\n return this.request<StarterPrompt[]>('GET', '/api/external/question-chat/prompts');\r\n }\r\n\r\n async getOrCreateChatSession(params: {\r\n questionId: string;\r\n questionContent: QuestionContextForChat;\r\n quizId: string;\r\n childId: string;\r\n parentId: string;\r\n lessonId?: string;\r\n courseId?: string;\r\n }): Promise<ChatSession> {\r\n return this.request<ChatSession>('POST', '/api/external/question-chat/session', params);\r\n }\r\n\r\n async sendChatMessage(params: {\r\n chatId: string;\r\n message: string;\r\n questionContext: QuestionContextForChat;\r\n childId: string;\r\n }): Promise<ChatMessageResponse> {\r\n return this.request<ChatMessageResponse>('POST', '/api/external/question-chat/message', params);\r\n }\r\n\r\n async getChatHistory(questionId: string, childId: string): Promise<{ chatId: string | null; messages: ChatMessage[] }> {\r\n return this.request<{ chatId: string | null; messages: ChatMessage[] }>(\r\n 'GET',\r\n `/api/external/question-chat/${questionId}/${childId}`\r\n );\r\n }\r\n\r\n async getChatsByAttempt(attemptId: string): Promise<Record<string, { chatId: string; messages: ChatMessage[] }>> {\r\n return this.request<Record<string, { chatId: string; messages: ChatMessage[] }>>(\r\n 'GET',\r\n `/api/external/quiz-attempts/${attemptId}/chats`\r\n );\r\n }\r\n\r\n async getTextToSpeech(text: string, voice: string = 'nova'): Promise<Blob> {\r\n const headers: HeadersInit = {\r\n 'Content-Type': 'application/json',\r\n };\r\n\r\n if (this.authToken) {\r\n headers['Authorization'] = `Bearer ${this.authToken}`;\r\n }\r\n\r\n const response = await fetch(`${this.baseUrl}/api/external/tts`, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify({ text, voice }),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`TTS request failed: HTTP ${response.status}`);\r\n }\r\n\r\n return response.blob();\r\n }\r\n}\r\n","import type { QuizQuestion, QuizAnswerDetail, QuestionType } from './types';\r\n\r\n// Check if an answer is correct based on question type\r\nexport function checkAnswer(\r\n question: QuizQuestion,\r\n selectedAnswer: unknown\r\n): { isCorrect: boolean; pointsEarned: number } {\r\n const { type, correctAnswer, points } = question;\r\n\r\n switch (type) {\r\n case 'single':\r\n case 'true-false': {\r\n const isCorrect = selectedAnswer === correctAnswer;\r\n return { isCorrect, pointsEarned: isCorrect ? points : 0 };\r\n }\r\n\r\n case 'multiple': {\r\n if (!Array.isArray(selectedAnswer) || !Array.isArray(correctAnswer)) {\r\n return { isCorrect: false, pointsEarned: 0 };\r\n }\r\n const sortedSelected = [...selectedAnswer].sort();\r\n const sortedCorrect = [...correctAnswer].sort();\r\n const isCorrect =\r\n sortedSelected.length === sortedCorrect.length &&\r\n sortedSelected.every((val, idx) => val === sortedCorrect[idx]);\r\n return { isCorrect, pointsEarned: isCorrect ? points : 0 };\r\n }\r\n\r\n case 'fill': {\r\n if (!Array.isArray(selectedAnswer) || !question.blanks) {\r\n return { isCorrect: false, pointsEarned: 0 };\r\n }\r\n const isCorrect = question.blanks.every((blank, idx) =>\r\n selectedAnswer[idx]?.toLowerCase().trim() === blank.toLowerCase().trim()\r\n );\r\n return { isCorrect, pointsEarned: isCorrect ? points : 0 };\r\n }\r\n\r\n case 'sorting': {\r\n if (!Array.isArray(selectedAnswer) || !question.correctOrder) {\r\n return { isCorrect: false, pointsEarned: 0 };\r\n }\r\n const isCorrect =\r\n selectedAnswer.length === question.correctOrder.length &&\r\n selectedAnswer.every((val, idx) => val === question.correctOrder![idx]);\r\n return { isCorrect, pointsEarned: isCorrect ? points : 0 };\r\n }\r\n\r\n case 'matrix': {\r\n if (typeof selectedAnswer !== 'object' || !question.correctMatches) {\r\n return { isCorrect: false, pointsEarned: 0 };\r\n }\r\n const selected = selectedAnswer as Record<string, string>;\r\n const correct = question.correctMatches;\r\n const isCorrect = Object.keys(correct).every(\r\n key => selected[key] === correct[key]\r\n );\r\n return { isCorrect, pointsEarned: isCorrect ? points : 0 };\r\n }\r\n\r\n case 'free': {\r\n // For free-form answers, do a simple case-insensitive comparison\r\n if (typeof selectedAnswer !== 'string' || typeof correctAnswer !== 'string') {\r\n return { isCorrect: false, pointsEarned: 0 };\r\n }\r\n const isCorrect = selectedAnswer.toLowerCase().trim() === correctAnswer.toLowerCase().trim();\r\n return { isCorrect, pointsEarned: isCorrect ? points : 0 };\r\n }\r\n\r\n case 'essay':\r\n case 'assessment':\r\n // These require manual grading or are opinion-based\r\n return { isCorrect: false, pointsEarned: 0 };\r\n\r\n default:\r\n return { isCorrect: false, pointsEarned: 0 };\r\n }\r\n}\r\n\r\n// Create an answer detail object\r\nexport function createAnswerDetail(\r\n question: QuizQuestion,\r\n selectedAnswer: unknown\r\n): QuizAnswerDetail {\r\n const { isCorrect, pointsEarned } = checkAnswer(question, selectedAnswer);\r\n\r\n return {\r\n questionId: question.id,\r\n questionText: question.question,\r\n questionType: question.type,\r\n points: question.points,\r\n pointsEarned,\r\n selectedAnswer: selectedAnswer as QuizAnswerDetail['selectedAnswer'],\r\n correctAnswer: question.correctAnswer as QuizAnswerDetail['correctAnswer'],\r\n isCorrect,\r\n explanation: question.explanation,\r\n hint: question.hint,\r\n };\r\n}\r\n\r\n// Calculate total score percentage\r\nexport function calculateScore(answers: QuizAnswerDetail[]): {\r\n score: number;\r\n correctAnswers: number;\r\n totalPoints: number;\r\n earnedPoints: number;\r\n} {\r\n const totalPoints = answers.reduce((sum, a) => sum + a.points, 0);\r\n const earnedPoints = answers.reduce((sum, a) => sum + a.pointsEarned, 0);\r\n const correctAnswers = answers.filter(a => a.isCorrect).length;\r\n const score = totalPoints > 0 ? Math.round((earnedPoints / totalPoints) * 100) : 0;\r\n\r\n return { score, correctAnswers, totalPoints, earnedPoints };\r\n}\r\n\r\n// Format time in seconds to mm:ss\r\nexport function formatTime(seconds: number): string {\r\n const mins = Math.floor(seconds / 60);\r\n const secs = seconds % 60;\r\n return `${mins}:${secs.toString().padStart(2, '0')}`;\r\n}\r\n","import { useState, useEffect, useRef } from 'react';\r\n\r\ninterface TextToSpeechProps {\r\n text: string;\r\n inline?: boolean;\r\n size?: 'sm' | 'md';\r\n}\r\n\r\nconst styles = {\r\n container: {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n gap: '8px',\r\n },\r\n button: {\r\n display: 'inline-flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n border: 'none',\r\n borderRadius: '6px',\r\n cursor: 'pointer',\r\n transition: 'all 0.2s ease',\r\n flexShrink: 0,\r\n },\r\n buttonSm: {\r\n width: '28px',\r\n height: '28px',\r\n padding: '4px',\r\n backgroundColor: 'transparent',\r\n },\r\n buttonMd: {\r\n width: '32px',\r\n height: '32px',\r\n padding: '6px',\r\n backgroundColor: 'rgba(103, 33, 176, 0.1)',\r\n },\r\n buttonPlaying: {\r\n backgroundColor: 'rgba(103, 33, 176, 0.2)',\r\n },\r\n buttonDisabled: {\r\n opacity: 0.4,\r\n cursor: 'not-allowed',\r\n },\r\n icon: {\r\n width: '16px',\r\n height: '16px',\r\n color: '#6721b0',\r\n },\r\n textContainer: {\r\n flex: 1,\r\n },\r\n highlightedWord: {\r\n backgroundColor: 'rgba(103, 33, 176, 0.25)',\r\n borderRadius: '3px',\r\n padding: '0 2px',\r\n transition: 'background-color 0.15s ease',\r\n fontWeight: 500,\r\n },\r\n};\r\n\r\n// Volume icon SVG\r\nfunction VolumeIcon() {\r\n return (\r\n <svg\r\n style={styles.icon}\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" />\r\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\" />\r\n <path d=\"M19.07 4.93a10 10 0 0 1 0 14.14\" />\r\n </svg>\r\n );\r\n}\r\n\r\n// Stop icon SVG\r\nfunction StopIcon() {\r\n return (\r\n <svg\r\n style={styles.icon}\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <rect x=\"9\" y=\"9\" width=\"6\" height=\"6\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function TextToSpeech({ text, inline = false, size = 'sm' }: TextToSpeechProps) {\r\n const [isPlaying, setIsPlaying] = useState(false);\r\n const [currentWordIndex, setCurrentWordIndex] = useState(-1);\r\n const [isSupported, setIsSupported] = useState(true);\r\n const [bestVoice, setBestVoice] = useState<SpeechSynthesisVoice | null>(null);\r\n const utteranceRef = useRef<SpeechSynthesisUtterance | null>(null);\r\n const wordsRef = useRef<string[]>([]);\r\n\r\n // Extract words from text\r\n useEffect(() => {\r\n wordsRef.current = text.split(/\\s+/).filter(word => word.length > 0);\r\n }, [text]);\r\n\r\n // Check browser support\r\n useEffect(() => {\r\n if (typeof window === 'undefined' || !('speechSynthesis' in window)) {\r\n setIsSupported(false);\r\n }\r\n }, []);\r\n\r\n // Load and select the best quality voice\r\n useEffect(() => {\r\n if (!isSupported || typeof window === 'undefined') return;\r\n\r\n const loadVoices = () => {\r\n const voices = window.speechSynthesis.getVoices();\r\n if (voices.length === 0) return;\r\n\r\n // Premium voice names (in priority order)\r\n const premiumVoices = [\r\n 'samantha', 'victoria', 'karen', 'serena', 'jenny',\r\n 'aria', 'emma', 'moira', 'fiona', 'alice'\r\n ];\r\n\r\n // Filter to English voices\r\n const englishVoices = voices.filter(voice =>\r\n voice.lang.startsWith('en-')\r\n );\r\n\r\n // Score each voice\r\n const scoredVoices = englishVoices.map(voice => {\r\n let score = 0;\r\n const nameLower = voice.name.toLowerCase();\r\n\r\n // Check for premium voice names\r\n premiumVoices.forEach((premiumName, index) => {\r\n if (nameLower.includes(premiumName)) {\r\n score += (premiumVoices.length - index) * 10;\r\n }\r\n });\r\n\r\n // Prefer local voices (higher quality)\r\n if (voice.localService) score += 8;\r\n\r\n // Prefer female voices (tend to sound warmer)\r\n if (!nameLower.includes('male')) score += 6;\r\n\r\n // Prefer US English\r\n if (voice.lang === 'en-US') score += 3;\r\n\r\n // Penalize obviously robotic voices\r\n if (nameLower.includes('google us english') ||\r\n nameLower.includes('microsoft david')) {\r\n score -= 20;\r\n }\r\n\r\n return { voice, score };\r\n });\r\n\r\n // Sort and pick best\r\n scoredVoices.sort((a, b) => b.score - a.score);\r\n\r\n if (scoredVoices.length > 0) {\r\n setBestVoice(scoredVoices[0].voice);\r\n }\r\n };\r\n\r\n loadVoices();\r\n\r\n if (window.speechSynthesis.onvoiceschanged !== undefined) {\r\n window.speechSynthesis.onvoiceschanged = loadVoices;\r\n }\r\n\r\n return () => {\r\n if (window.speechSynthesis.onvoiceschanged !== undefined) {\r\n window.speechSynthesis.onvoiceschanged = null;\r\n }\r\n };\r\n }, [isSupported]);\r\n\r\n const handlePlay = () => {\r\n if (!isSupported || typeof window === 'undefined') return;\r\n\r\n try {\r\n // If playing, stop it\r\n if (isPlaying) {\r\n window.speechSynthesis.cancel();\r\n setIsPlaying(false);\r\n setCurrentWordIndex(-1);\r\n return;\r\n }\r\n\r\n // Create utterance\r\n const utterance = new SpeechSynthesisUtterance(text);\r\n utteranceRef.current = utterance;\r\n\r\n // Use best voice\r\n if (bestVoice) {\r\n utterance.voice = bestVoice;\r\n }\r\n\r\n // Optimized settings for natural sound\r\n utterance.rate = 1.0;\r\n utterance.pitch = 1.0;\r\n utterance.volume = 1.0;\r\n\r\n // Track word boundaries for highlighting\r\n let wordIndex = 0;\r\n utterance.onboundary = (event) => {\r\n if (event.name === 'word') {\r\n setCurrentWordIndex(wordIndex);\r\n wordIndex++;\r\n }\r\n };\r\n\r\n utterance.onstart = () => {\r\n setIsPlaying(true);\r\n setCurrentWordIndex(0);\r\n };\r\n\r\n utterance.onend = () => {\r\n setIsPlaying(false);\r\n setCurrentWordIndex(-1);\r\n };\r\n\r\n utterance.onerror = (event) => {\r\n console.error('Speech error:', event);\r\n setIsPlaying(false);\r\n setCurrentWordIndex(-1);\r\n };\r\n\r\n window.speechSynthesis.speak(utterance);\r\n } catch (error) {\r\n console.error('TTS error:', error);\r\n setIsPlaying(false);\r\n }\r\n };\r\n\r\n // Cleanup on unmount\r\n useEffect(() => {\r\n return () => {\r\n if (typeof window !== 'undefined' && 'speechSynthesis' in window) {\r\n try {\r\n window.speechSynthesis.cancel();\r\n } catch (error) {\r\n // Ignore cleanup errors\r\n }\r\n }\r\n };\r\n }, []);\r\n\r\n const buttonStyle = {\r\n ...styles.button,\r\n ...(size === 'sm' ? styles.buttonSm : styles.buttonMd),\r\n ...(isPlaying ? styles.buttonPlaying : {}),\r\n ...(!isSupported ? styles.buttonDisabled : {}),\r\n };\r\n\r\n // Inline variant with highlighted text\r\n if (inline) {\r\n const words = text.split(/\\s+/);\r\n\r\n return (\r\n <div style={styles.container}>\r\n <button\r\n style={buttonStyle}\r\n onClick={handlePlay}\r\n disabled={!isSupported}\r\n aria-label={isPlaying ? 'Stop reading' : 'Read aloud'}\r\n title={isPlaying ? 'Stop' : 'Read aloud'}\r\n data-testid=\"button-tts\"\r\n >\r\n {isPlaying ? <StopIcon /> : <VolumeIcon />}\r\n </button>\r\n <span style={styles.textContainer}>\r\n {words.map((word, index) => (\r\n <span\r\n key={index}\r\n style={index === currentWordIndex ? styles.highlightedWord : undefined}\r\n >\r\n {word}{index < words.length - 1 ? ' ' : ''}\r\n </span>\r\n ))}\r\n </span>\r\n </div>\r\n );\r\n }\r\n\r\n // Button-only variant\r\n return (\r\n <button\r\n style={buttonStyle}\r\n onClick={handlePlay}\r\n disabled={!isSupported}\r\n aria-label={isPlaying ? 'Stop reading' : 'Read aloud'}\r\n title={isPlaying ? 'Stop' : 'Read aloud'}\r\n data-testid=\"button-tts\"\r\n >\r\n {isPlaying ? <StopIcon /> : <VolumeIcon />}\r\n </button>\r\n );\r\n}\r\n","import { useState, useEffect, useRef, useCallback } from 'react';\r\nimport type { ChatMessage, StarterPrompt, QuestionContextForChat } from './types';\r\nimport { QuizApiClient } from './api';\r\n\r\ninterface SpeechRecognitionEvent {\r\n results: { [key: number]: { [key: number]: { transcript: string; confidence: number } } };\r\n}\r\n\r\ninterface SpeechRecognitionErrorEvent {\r\n error: string;\r\n message?: string;\r\n}\r\n\r\ninterface SpeechRecognitionInstance {\r\n continuous: boolean;\r\n interimResults: boolean;\r\n lang: string;\r\n onstart: (() => void) | null;\r\n onresult: ((event: SpeechRecognitionEvent) => void) | null;\r\n onerror: ((event: SpeechRecognitionErrorEvent) => void) | null;\r\n onend: (() => void) | null;\r\n start: () => void;\r\n stop: () => void;\r\n}\r\n\r\ninterface SpeechRecognitionConstructor {\r\n new(): SpeechRecognitionInstance;\r\n}\r\n\r\ndeclare global {\r\n interface Window {\r\n SpeechRecognition?: SpeechRecognitionConstructor;\r\n webkitSpeechRecognition?: SpeechRecognitionConstructor;\r\n }\r\n}\r\n\r\ninterface AnswerResult {\r\n wasIncorrect: boolean;\r\n selectedAnswer?: string;\r\n correctAnswer?: string;\r\n explanation?: string;\r\n}\r\n\r\ninterface QuestionChatPanelProps {\r\n apiClient: QuizApiClient;\r\n question: QuestionContextForChat;\r\n quizId: string;\r\n childId: string;\r\n parentId: string;\r\n lessonId?: string;\r\n courseId?: string;\r\n answerResult?: AnswerResult;\r\n}\r\n\r\nconst panelStyles = {\r\n container: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n height: '100%',\r\n backgroundColor: '#f8fafc',\r\n borderRadius: '12px',\r\n border: '1px solid #e2e8f0',\r\n overflow: 'hidden',\r\n },\r\n header: {\r\n padding: '12px 16px',\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n fontWeight: '600',\r\n fontSize: '14px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n },\r\n messagesContainer: {\r\n flex: 1,\r\n overflowY: 'auto' as const,\r\n padding: '12px',\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '8px',\r\n },\r\n starterPrompts: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '8px',\r\n padding: '16px',\r\n },\r\n starterButton: {\r\n padding: '10px 14px',\r\n borderRadius: '20px',\r\n border: '1px solid #e2e8f0',\r\n backgroundColor: '#ffffff',\r\n color: '#374151',\r\n fontSize: '13px',\r\n cursor: 'pointer',\r\n textAlign: 'left' as const,\r\n transition: 'all 0.2s ease',\r\n },\r\n starterButtonHover: {\r\n backgroundColor: '#f3e8ff',\r\n borderColor: '#6721b0',\r\n },\r\n messageRow: {\r\n display: 'flex',\r\n },\r\n messageContent: {\r\n display: 'flex',\r\n alignItems: 'flex-end',\r\n gap: '4px',\r\n maxWidth: '85%',\r\n },\r\n userMessage: {\r\n padding: '10px 14px',\r\n borderRadius: '16px 16px 4px 16px',\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n fontSize: '14px',\r\n lineHeight: 1.4,\r\n },\r\n assistantMessage: {\r\n padding: '10px 14px',\r\n borderRadius: '16px 16px 16px 4px',\r\n backgroundColor: '#ffffff',\r\n color: '#1f2937',\r\n fontSize: '14px',\r\n lineHeight: 1.4,\r\n border: '1px solid #e2e8f0',\r\n },\r\n inputContainer: {\r\n padding: '12px',\r\n borderTop: '1px solid #e2e8f0',\r\n backgroundColor: '#ffffff',\r\n display: 'flex',\r\n gap: '8px',\r\n alignItems: 'center',\r\n },\r\n input: {\r\n flex: 1,\r\n padding: '10px 14px',\r\n borderRadius: '20px',\r\n border: '1px solid #e2e8f0',\r\n fontSize: '14px',\r\n outline: 'none',\r\n },\r\n buttonBase: {\r\n width: '40px',\r\n height: '40px',\r\n borderRadius: '50%',\r\n border: 'none',\r\n cursor: 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n fontSize: '16px',\r\n transition: 'all 0.2s ease',\r\n },\r\n sendButton: {\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n },\r\n sendButtonDisabled: {\r\n backgroundColor: '#d1d5db',\r\n cursor: 'not-allowed',\r\n },\r\n micButton: {\r\n backgroundColor: '#ffffff',\r\n border: '1px solid #e2e8f0',\r\n color: '#374151',\r\n },\r\n micButtonActive: {\r\n backgroundColor: '#ef4444',\r\n color: '#ffffff',\r\n border: 'none',\r\n },\r\n speakButton: {\r\n width: '28px',\r\n height: '28px',\r\n borderRadius: '50%',\r\n border: 'none',\r\n backgroundColor: 'transparent',\r\n color: '#9ca3af',\r\n cursor: 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n transition: 'all 0.2s ease',\r\n flexShrink: 0,\r\n },\r\n speakButtonReady: {\r\n color: '#22c55e',\r\n },\r\n speakButtonPlaying: {\r\n color: '#6721b0',\r\n },\r\n speakButtonLoading: {\r\n color: '#f97316',\r\n },\r\n loadingDots: {\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '4px',\r\n padding: '10px 14px',\r\n maxWidth: '85%',\r\n marginRight: 'auto',\r\n },\r\n dot: {\r\n width: '8px',\r\n height: '8px',\r\n backgroundColor: '#9ca3af',\r\n borderRadius: '50%',\r\n animation: 'bounce 1.4s ease-in-out infinite',\r\n },\r\n emptyState: {\r\n flex: 1,\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n padding: '20px',\r\n color: '#6b7280',\r\n textAlign: 'center' as const,\r\n },\r\n helperIcon: {\r\n width: '48px',\r\n height: '48px',\r\n marginBottom: '12px',\r\n fontSize: '32px',\r\n },\r\n};\r\n\r\nconst STARTER_PROMPTS: StarterPrompt[] = [\r\n { id: 'dont_understand', label: \"I don't understand this question\", message: \"I don't understand this question. Can you help me?\" },\r\n { id: 'word_help', label: \"I don't understand a word\", message: \"I don't understand a word in this question. Can you help?\" },\r\n { id: 'explain_again', label: \"Explain this again\", message: \"Can you explain this question to me again in a different way?\" }\r\n];\r\n\r\nconst MicIcon = () => (\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\"/>\r\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\r\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\"/>\r\n </svg>\r\n);\r\n\r\nconst MicOffIcon = () => (\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <line x1=\"2\" x2=\"22\" y1=\"2\" y2=\"22\"/>\r\n <path d=\"M18.89 13.23A7.12 7.12 0 0 0 19 12v-2\"/>\r\n <path d=\"M5 10v2a7 7 0 0 0 12 5\"/>\r\n <path d=\"M15 9.34V5a3 3 0 0 0-5.68-1.33\"/>\r\n <path d=\"M9 9v3a3 3 0 0 0 5.12 2.12\"/>\r\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\"/>\r\n </svg>\r\n);\r\n\r\nconst VolumeIcon = () => (\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\r\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\r\n <path d=\"M19.07 4.93a10 10 0 0 1 0 14.14\"/>\r\n </svg>\r\n);\r\n\r\nconst SendIcon = () => (\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\r\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\r\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\r\n </svg>\r\n);\r\n\r\nconst HelpIcon = () => (\r\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#6721b0\" strokeWidth=\"2\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\" />\r\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\" />\r\n </svg>\r\n);\r\n\r\nexport function QuestionChatPanel({\r\n apiClient,\r\n question,\r\n quizId,\r\n childId,\r\n parentId,\r\n lessonId,\r\n courseId,\r\n answerResult,\r\n}: QuestionChatPanelProps) {\r\n const [messages, setMessages] = useState<ChatMessage[]>([]);\r\n const [inputValue, setInputValue] = useState('');\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [chatId, setChatId] = useState<string | null>(null);\r\n const [hoveredButton, setHoveredButton] = useState<string | null>(null);\r\n const [isListening, setIsListening] = useState(false);\r\n const [speakingIndex, setSpeakingIndex] = useState<number | null>(null);\r\n const [audioReadyMap, setAudioReadyMap] = useState<Map<string, boolean>>(new Map());\r\n const [hasOfferedHelp, setHasOfferedHelp] = useState(false);\r\n \r\n const messagesContainerRef = useRef<HTMLDivElement>(null);\r\n const messagesEndRef = useRef<HTMLDivElement>(null);\r\n const recognitionRef = useRef<SpeechRecognitionInstance | null>(null);\r\n const audioRef = useRef<HTMLAudioElement | null>(null);\r\n const audioCacheRef = useRef<Map<string, Blob>>(new Map());\r\n\r\n const isSpeechSupported = typeof window !== 'undefined' && \r\n (window.SpeechRecognition || window.webkitSpeechRecognition);\r\n\r\n const scrollToBottom = useCallback(() => {\r\n if (messagesContainerRef.current) {\r\n messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight;\r\n }\r\n }, []);\r\n\r\n const preCacheAudio = useCallback(async (text: string) => {\r\n if (audioCacheRef.current.has(text)) {\r\n setAudioReadyMap(prev => new Map(prev).set(text, true));\r\n return;\r\n }\r\n \r\n setAudioReadyMap(prev => new Map(prev).set(text, false));\r\n \r\n try {\r\n const audioBlob = await apiClient.getTextToSpeech(text, 'nova');\r\n audioCacheRef.current.set(text, audioBlob);\r\n setAudioReadyMap(prev => new Map(prev).set(text, true));\r\n } catch (error) {\r\n console.error('Pre-cache TTS error:', error);\r\n }\r\n }, [apiClient]);\r\n\r\n const startListening = useCallback(() => {\r\n const SpeechRecognitionAPI = window.SpeechRecognition || window.webkitSpeechRecognition;\r\n if (!SpeechRecognitionAPI) {\r\n console.log('Speech recognition not supported');\r\n return;\r\n }\r\n \r\n const recognition = new SpeechRecognitionAPI();\r\n \r\n recognition.continuous = true;\r\n recognition.interimResults = true;\r\n recognition.lang = 'en-US';\r\n \r\n recognition.onstart = () => {\r\n console.log('Speech recognition started');\r\n setIsListening(true);\r\n };\r\n \r\n recognition.onresult = (event) => {\r\n let finalTranscript = '';\r\n for (let i = 0; i < Object.keys(event.results).length; i++) {\r\n const result = event.results[i];\r\n if (result && result[0]) {\r\n finalTranscript += result[0].transcript;\r\n }\r\n }\r\n if (finalTranscript) {\r\n setInputValue(finalTranscript);\r\n }\r\n };\r\n \r\n recognition.onerror = (event) => {\r\n console.log('Speech recognition error:', event.error);\r\n if (event.error === 'not-allowed') {\r\n alert('Microphone access was denied. Please allow microphone access and try again.');\r\n }\r\n setIsListening(false);\r\n };\r\n \r\n recognition.onend = () => {\r\n console.log('Speech recognition ended');\r\n setIsListening(false);\r\n };\r\n \r\n recognitionRef.current = recognition;\r\n try {\r\n recognition.start();\r\n } catch (e) {\r\n console.log('Failed to start recognition:', e);\r\n setIsListening(false);\r\n }\r\n }, []);\r\n\r\n const stopListening = useCallback(() => {\r\n if (recognitionRef.current) {\r\n recognitionRef.current.stop();\r\n setIsListening(false);\r\n }\r\n }, []);\r\n\r\n const speakMessage = useCallback(async (text: string, index: number) => {\r\n if (audioRef.current) {\r\n audioRef.current.pause();\r\n audioRef.current = null;\r\n }\r\n \r\n if (speakingIndex === index) {\r\n setSpeakingIndex(null);\r\n return;\r\n }\r\n \r\n setSpeakingIndex(index);\r\n \r\n try {\r\n let audioBlob: Blob;\r\n \r\n const cachedBlob = audioCacheRef.current.get(text);\r\n if (cachedBlob) {\r\n audioBlob = cachedBlob;\r\n } else {\r\n audioBlob = await apiClient.getTextToSpeech(text, 'nova');\r\n audioCacheRef.current.set(text, audioBlob);\r\n }\r\n \r\n const audioUrl = URL.createObjectURL(audioBlob);\r\n const audio = new Audio(audioUrl);\r\n audioRef.current = audio;\r\n \r\n audio.onended = () => {\r\n setSpeakingIndex(null);\r\n URL.revokeObjectURL(audioUrl);\r\n };\r\n audio.onerror = () => {\r\n setSpeakingIndex(null);\r\n URL.revokeObjectURL(audioUrl);\r\n };\r\n \r\n await audio.play();\r\n } catch (error) {\r\n console.error('TTS error:', error);\r\n setSpeakingIndex(null);\r\n }\r\n }, [speakingIndex, apiClient]);\r\n\r\n useEffect(() => {\r\n scrollToBottom();\r\n }, [messages, scrollToBottom]);\r\n\r\n useEffect(() => {\r\n setMessages([]);\r\n setChatId(null);\r\n setInputValue('');\r\n setHasOfferedHelp(false);\r\n \r\n const loadHistory = async () => {\r\n try {\r\n const history = await apiClient.getChatHistory(question.id, childId);\r\n if (history.chatId && history.messages.length > 0) {\r\n setChatId(history.chatId);\r\n setMessages(history.messages);\r\n history.messages\r\n .filter(m => m.role === 'assistant')\r\n .forEach(m => preCacheAudio(m.content));\r\n }\r\n } catch (err) {\r\n console.error('Failed to load chat history:', err);\r\n }\r\n };\r\n \r\n loadHistory();\r\n }, [question.id, childId, apiClient, preCacheAudio]);\r\n\r\n // Auto-offer help when student answers incorrectly\r\n useEffect(() => {\r\n if (answerResult?.wasIncorrect && !hasOfferedHelp) {\r\n setHasOfferedHelp(true);\r\n \r\n const selectedAnswerText = answerResult.selectedAnswer || \"that answer\";\r\n const helpMessage = `Looks like you chose \"${selectedAnswerText}\" which was incorrect. Would you like me to help explain the correct answer?`;\r\n \r\n const assistantMessage: ChatMessage = {\r\n role: 'assistant',\r\n content: helpMessage,\r\n timestamp: new Date().toISOString(),\r\n };\r\n setMessages(prev => [...prev, assistantMessage]);\r\n preCacheAudio(helpMessage);\r\n }\r\n }, [answerResult, hasOfferedHelp, preCacheAudio]);\r\n\r\n const initializeChat = async () => {\r\n if (chatId) return chatId;\r\n \r\n try {\r\n const session = await apiClient.getOrCreateChatSession({\r\n questionId: question.id,\r\n questionContent: question,\r\n quizId,\r\n childId,\r\n parentId,\r\n lessonId,\r\n courseId,\r\n });\r\n setChatId(session.chatId);\r\n return session.chatId;\r\n } catch (err) {\r\n console.error('Failed to create chat session:', err);\r\n return null;\r\n }\r\n };\r\n\r\n const sendMessage = async (messageText: string) => {\r\n if (!messageText.trim() || isLoading) return;\r\n \r\n if (isListening) {\r\n stopListening();\r\n }\r\n \r\n setIsLoading(true);\r\n \r\n const userMsg: ChatMessage = {\r\n role: 'user',\r\n content: messageText,\r\n timestamp: new Date().toISOString(),\r\n };\r\n setMessages(prev => [...prev, userMsg]);\r\n setInputValue('');\r\n \r\n try {\r\n const currentChatId = await initializeChat();\r\n if (!currentChatId) {\r\n throw new Error('Failed to initialize chat');\r\n }\r\n \r\n const response = await apiClient.sendChatMessage({\r\n chatId: currentChatId,\r\n message: messageText,\r\n questionContext: question,\r\n childId,\r\n });\r\n \r\n const assistantMessage: ChatMessage = response.assistantMessage || {\r\n role: 'assistant',\r\n content: \"I'm here to help!\",\r\n timestamp: new Date().toISOString(),\r\n };\r\n setMessages(prev => [...prev, assistantMessage]);\r\n preCacheAudio(assistantMessage.content);\r\n } catch (err) {\r\n console.error('Failed to send message:', err);\r\n const content = \"Sorry, I'm having trouble right now. Please try again!\";\r\n const errorMsg: ChatMessage = {\r\n role: 'assistant',\r\n content,\r\n timestamp: new Date().toISOString(),\r\n };\r\n setMessages(prev => [...prev, errorMsg]);\r\n preCacheAudio(content);\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n };\r\n\r\n const handleKeyPress = (e: React.KeyboardEvent) => {\r\n if (e.key === 'Enter' && !e.shiftKey) {\r\n e.preventDefault();\r\n sendMessage(inputValue);\r\n }\r\n };\r\n\r\n return (\r\n <div style={panelStyles.container}>\r\n <style>\r\n {`\r\n @keyframes bounce {\r\n 0%, 60%, 100% { transform: translateY(0); }\r\n 30% { transform: translateY(-4px); }\r\n }\r\n @keyframes pulse {\r\n 0%, 100% { opacity: 1; }\r\n 50% { opacity: 0.5; }\r\n }\r\n `}\r\n </style>\r\n \r\n <div style={panelStyles.header}>\r\n <span>Need Help?</span>\r\n </div>\r\n \r\n <div ref={messagesContainerRef} style={panelStyles.messagesContainer}>\r\n {messages.length === 0 ? (\r\n <div style={panelStyles.emptyState}>\r\n <div style={panelStyles.helperIcon}>\r\n <HelpIcon />\r\n </div>\r\n <div style={{ fontSize: '14px', fontWeight: '500', marginBottom: '8px' }}>\r\n Hi! I'm your question helper\r\n </div>\r\n <div style={{ fontSize: '13px', color: '#9ca3af' }}>\r\n Ask me if you need help understanding this question\r\n </div>\r\n \r\n <div style={{ ...panelStyles.starterPrompts, marginTop: '16px' }}>\r\n {STARTER_PROMPTS.map(prompt => (\r\n <button\r\n key={prompt.id}\r\n style={{\r\n ...panelStyles.starterButton,\r\n ...(hoveredButton === prompt.id ? panelStyles.starterButtonHover : {}),\r\n }}\r\n onMouseEnter={() => setHoveredButton(prompt.id)}\r\n onMouseLeave={() => setHoveredButton(null)}\r\n onClick={() => sendMessage(prompt.message)}\r\n disabled={isLoading}\r\n data-testid={`button-chat-starter-${prompt.id}`}\r\n >\r\n {prompt.label}\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n ) : (\r\n <>\r\n {messages.map((msg, idx) => (\r\n <div \r\n key={idx} \r\n style={{\r\n ...panelStyles.messageRow,\r\n justifyContent: msg.role === 'user' ? 'flex-end' : 'flex-start',\r\n }}\r\n >\r\n <div style={{\r\n ...panelStyles.messageContent,\r\n flexDirection: msg.role === 'user' ? 'row-reverse' : 'row',\r\n }}>\r\n <div style={msg.role === 'user' ? panelStyles.userMessage : panelStyles.assistantMessage}>\r\n {msg.content}\r\n </div>\r\n {msg.role === 'assistant' && (\r\n <button\r\n style={{\r\n ...panelStyles.speakButton,\r\n ...(speakingIndex === idx \r\n ? panelStyles.speakButtonPlaying \r\n : audioReadyMap.get(msg.content) === true\r\n ? panelStyles.speakButtonReady\r\n : audioReadyMap.get(msg.content) === false\r\n ? panelStyles.speakButtonLoading\r\n : {}),\r\n ...(audioReadyMap.get(msg.content) === false ? { animation: 'pulse 1.5s ease-in-out infinite' } : {}),\r\n }}\r\n onClick={() => speakMessage(msg.content, idx)}\r\n data-testid={`button-speak-${idx}`}\r\n title=\"Listen to this message\"\r\n >\r\n <VolumeIcon />\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n ))}\r\n {isLoading && (\r\n <div style={panelStyles.loadingDots}>\r\n <div style={{ ...panelStyles.dot, animationDelay: '0s' }} />\r\n <div style={{ ...panelStyles.dot, animationDelay: '0.2s' }} />\r\n <div style={{ ...panelStyles.dot, animationDelay: '0.4s' }} />\r\n </div>\r\n )}\r\n <div ref={messagesEndRef} />\r\n </>\r\n )}\r\n </div>\r\n \r\n <div style={panelStyles.inputContainer}>\r\n <input\r\n type=\"text\"\r\n value={inputValue}\r\n onChange={(e) => setInputValue(e.target.value)}\r\n onKeyPress={handleKeyPress}\r\n placeholder={isListening ? \"Listening...\" : \"Ask about this question...\"}\r\n style={panelStyles.input}\r\n disabled={isLoading || isListening}\r\n data-testid=\"input-chat-message\"\r\n />\r\n {isSpeechSupported && (\r\n <button\r\n onClick={isListening ? stopListening : startListening}\r\n disabled={isLoading}\r\n style={{\r\n ...panelStyles.buttonBase,\r\n ...(isListening ? panelStyles.micButtonActive : panelStyles.micButton),\r\n }}\r\n data-testid=\"button-voice-input\"\r\n title={isListening ? \"Stop listening\" : \"Speak your question\"}\r\n >\r\n {isListening ? <MicOffIcon /> : <MicIcon />}\r\n </button>\r\n )}\r\n <button\r\n onClick={() => sendMessage(inputValue)}\r\n disabled={isLoading || !inputValue.trim()}\r\n style={{\r\n ...panelStyles.buttonBase,\r\n ...panelStyles.sendButton,\r\n ...(isLoading || !inputValue.trim() ? panelStyles.sendButtonDisabled : {}),\r\n }}\r\n data-testid=\"button-send-chat\"\r\n >\r\n <SendIcon />\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect } from 'react';\r\nimport type {\r\n AttemptViewerProps,\r\n ExternalQuizAttempt,\r\n QuizAnswerDetail,\r\n} from './types';\r\nimport { QuizApiClient } from './api';\r\nimport { formatTime } from './utils';\r\n\r\nconst defaultStyles = {\r\n container: {\r\n fontFamily: 'system-ui, -apple-system, sans-serif',\r\n width: '100%',\r\n padding: '20px',\r\n backgroundColor: '#ffffff',\r\n borderRadius: '12px',\r\n boxSizing: 'border-box' as const,\r\n },\r\n header: {\r\n marginBottom: '24px',\r\n borderBottom: '1px solid #e5e7eb',\r\n paddingBottom: '20px',\r\n },\r\n title: {\r\n fontSize: '24px',\r\n fontWeight: '600',\r\n marginBottom: '16px',\r\n color: '#111827',\r\n },\r\n summaryGrid: {\r\n display: 'grid',\r\n gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))',\r\n gap: '16px',\r\n },\r\n summaryCard: {\r\n padding: '12px',\r\n backgroundColor: '#f9fafb',\r\n borderRadius: '8px',\r\n textAlign: 'center' as const,\r\n },\r\n summaryValue: {\r\n fontSize: '20px',\r\n fontWeight: '600',\r\n color: '#6721b0',\r\n marginBottom: '2px',\r\n },\r\n summaryLabel: {\r\n fontSize: '10px',\r\n color: '#6b7280',\r\n textTransform: 'uppercase' as const,\r\n letterSpacing: '0.05em',\r\n },\r\n questionsList: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '16px',\r\n },\r\n questionCard: {\r\n padding: '16px',\r\n border: '2px solid #e5e7eb',\r\n borderRadius: '8px',\r\n },\r\n questionCardCorrect: {\r\n borderColor: '#22c55e',\r\n backgroundColor: '#f0fdf4',\r\n },\r\n questionCardIncorrect: {\r\n borderColor: '#ef4444',\r\n backgroundColor: '#fef2f2',\r\n },\r\n questionHeader: {\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n alignItems: 'flex-start',\r\n marginBottom: '12px',\r\n },\r\n questionNumber: {\r\n fontSize: '12px',\r\n color: '#6b7280',\r\n fontWeight: '500',\r\n },\r\n questionBadge: {\r\n padding: '4px 8px',\r\n borderRadius: '4px',\r\n fontSize: '12px',\r\n fontWeight: '600',\r\n },\r\n badgeCorrect: {\r\n backgroundColor: '#dcfce7',\r\n color: '#166534',\r\n },\r\n badgeIncorrect: {\r\n backgroundColor: '#fee2e2',\r\n color: '#991b1b',\r\n },\r\n questionText: {\r\n fontSize: '16px',\r\n fontWeight: '500',\r\n marginBottom: '12px',\r\n color: '#111827',\r\n },\r\n answerSection: {\r\n fontSize: '14px',\r\n marginBottom: '8px',\r\n },\r\n answerLabel: {\r\n fontWeight: '600',\r\n color: '#6b7280',\r\n marginRight: '8px',\r\n },\r\n studentAnswer: {\r\n color: '#111827',\r\n },\r\n correctAnswer: {\r\n color: '#166534',\r\n },\r\n points: {\r\n fontSize: '13px',\r\n color: '#6b7280',\r\n marginTop: '8px',\r\n },\r\n explanation: {\r\n marginTop: '12px',\r\n padding: '12px',\r\n backgroundColor: '#f3e8ff',\r\n borderRadius: '6px',\r\n fontSize: '14px',\r\n color: '#581c87',\r\n },\r\n chatHistorySection: {\r\n marginTop: '12px',\r\n borderTop: '1px solid #e5e7eb',\r\n paddingTop: '12px',\r\n },\r\n chatToggleButton: {\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '6px',\r\n padding: '6px 12px',\r\n backgroundColor: '#f3f4f6',\r\n border: 'none',\r\n borderRadius: '6px',\r\n fontSize: '13px',\r\n color: '#6b7280',\r\n cursor: 'pointer',\r\n fontWeight: '500',\r\n },\r\n chatMessages: {\r\n marginTop: '12px',\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '8px',\r\n },\r\n chatMessage: {\r\n padding: '8px 12px',\r\n borderRadius: '8px',\r\n fontSize: '13px',\r\n maxWidth: '85%',\r\n },\r\n chatMessageUser: {\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n alignSelf: 'flex-end' as const,\r\n },\r\n chatMessageAssistant: {\r\n backgroundColor: '#f3f4f6',\r\n color: '#111827',\r\n alignSelf: 'flex-start' as const,\r\n },\r\n loading: {\r\n textAlign: 'center' as const,\r\n padding: '40px 20px',\r\n },\r\n spinner: {\r\n display: 'inline-block',\r\n width: '32px',\r\n height: '32px',\r\n border: '3px solid #e5e7eb',\r\n borderTopColor: '#6721b0',\r\n borderRadius: '50%',\r\n animation: 'spin 1s linear infinite',\r\n },\r\n error: {\r\n textAlign: 'center' as const,\r\n padding: '40px 20px',\r\n color: '#ef4444',\r\n },\r\n retryButton: {\r\n marginTop: '16px',\r\n padding: '12px 24px',\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n border: 'none',\r\n borderRadius: '8px',\r\n fontSize: '16px',\r\n fontWeight: '500',\r\n cursor: 'pointer',\r\n },\r\n};\r\n\r\nconst spinnerKeyframes = `\r\n @keyframes spin {\r\n to { transform: rotate(360deg); }\r\n }\r\n`;\r\n\r\nfunction formatAnswer(answer: unknown): string {\r\n if (answer === null || answer === undefined) {\r\n return 'No answer';\r\n }\r\n if (typeof answer === 'string') {\r\n return answer;\r\n }\r\n if (Array.isArray(answer)) {\r\n return answer.join(', ');\r\n }\r\n if (typeof answer === 'object') {\r\n return Object.entries(answer as Record<string, string>)\r\n .map(([k, v]) => `${k} → ${v}`)\r\n .join(', ');\r\n }\r\n return String(answer);\r\n}\r\n\r\ninterface ChatMessage {\r\n role: 'user' | 'assistant';\r\n content: string;\r\n timestamp?: string;\r\n}\r\n\r\nexport function AttemptViewer({\r\n attemptId,\r\n apiBaseUrl,\r\n authToken,\r\n onError,\r\n className,\r\n showExplanations = true,\r\n showConversation = false,\r\n title,\r\n}: AttemptViewerProps) {\r\n const [attempt, setAttempt] = useState<ExternalQuizAttempt | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n const [error, setError] = useState<string | null>(null);\r\n const [chatHistories, setChatHistories] = useState<Record<string, { chatId: string; messages: ChatMessage[] }>>({});\r\n const [expandedChats, setExpandedChats] = useState<Set<string>>(new Set());\r\n\r\n useEffect(() => {\r\n const apiClient = new QuizApiClient({\r\n baseUrl: apiBaseUrl,\r\n authToken,\r\n });\r\n\r\n async function fetchAttempt() {\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n const response = await fetch(`${apiBaseUrl}/api/external/quiz-attempts/${attemptId}`, {\r\n headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},\r\n });\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch attempt: ${response.statusText}`);\r\n }\r\n const data = await response.json();\r\n setAttempt(data);\r\n\r\n // Fetch chat histories if showConversation is enabled\r\n if (showConversation) {\r\n try {\r\n const chats = await apiClient.getChatsByAttempt(attemptId);\r\n setChatHistories(chats);\r\n } catch (chatErr) {\r\n console.error('Failed to load chat histories:', chatErr);\r\n }\r\n }\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : 'Failed to load attempt';\r\n setError(errorMessage);\r\n onError?.(err instanceof Error ? err : new Error(errorMessage));\r\n } finally {\r\n setLoading(false);\r\n }\r\n }\r\n\r\n fetchAttempt();\r\n }, [attemptId, apiBaseUrl, authToken, onError, showConversation]);\r\n\r\n const toggleChatExpanded = (questionId: string) => {\r\n setExpandedChats(prev => {\r\n const newSet = new Set(prev);\r\n if (newSet.has(questionId)) {\r\n newSet.delete(questionId);\r\n } else {\r\n newSet.add(questionId);\r\n }\r\n return newSet;\r\n });\r\n };\r\n\r\n const handleRetry = () => {\r\n setLoading(true);\r\n setError(null);\r\n window.location.reload();\r\n };\r\n\r\n if (loading) {\r\n return (\r\n <div style={defaultStyles.container} className={className}>\r\n <style>{spinnerKeyframes}</style>\r\n <div style={defaultStyles.loading}>\r\n <div style={defaultStyles.spinner} />\r\n <p style={{ marginTop: '16px', color: '#6b7280' }}>Loading attempt...</p>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n if (error || !attempt) {\r\n return (\r\n <div style={defaultStyles.container} className={className}>\r\n <div style={defaultStyles.error}>\r\n <p style={{ fontSize: '18px', fontWeight: '500' }}>Failed to load attempt</p>\r\n <p style={{ marginTop: '8px', color: '#6b7280' }}>{error}</p>\r\n <button style={defaultStyles.retryButton} onClick={handleRetry}>\r\n Try Again\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n const scorePercentage = attempt.score ?? 0;\r\n const correctCount = attempt.correctAnswers ?? 0;\r\n const totalQuestions = attempt.totalQuestions;\r\n const timeSpent = attempt.timeSpentSeconds ?? 0;\r\n\r\n return (\r\n <div style={defaultStyles.container} className={className}>\r\n <style>{spinnerKeyframes}</style>\r\n \r\n <div style={defaultStyles.header}>\r\n <div style={defaultStyles.summaryGrid}>\r\n <div style={defaultStyles.summaryCard}>\r\n <div style={defaultStyles.summaryValue}>{scorePercentage}%</div>\r\n <div style={defaultStyles.summaryLabel}>Score</div>\r\n </div>\r\n <div style={defaultStyles.summaryCard}>\r\n <div style={defaultStyles.summaryValue}>{correctCount}/{totalQuestions}</div>\r\n <div style={defaultStyles.summaryLabel}>Correct</div>\r\n </div>\r\n <div style={defaultStyles.summaryCard}>\r\n <div style={defaultStyles.summaryValue}>{formatTime(timeSpent)}</div>\r\n <div style={defaultStyles.summaryLabel}>Time</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div style={defaultStyles.questionsList}>\r\n {attempt.answers.map((answer: QuizAnswerDetail, index: number) => (\r\n <div\r\n key={answer.questionId}\r\n style={{\r\n ...defaultStyles.questionCard,\r\n ...(answer.isCorrect ? defaultStyles.questionCardCorrect : defaultStyles.questionCardIncorrect),\r\n }}\r\n >\r\n <div style={defaultStyles.questionHeader}>\r\n <span style={defaultStyles.questionNumber}>Question {index + 1}</span>\r\n <span\r\n style={{\r\n ...defaultStyles.questionBadge,\r\n ...(answer.isCorrect ? defaultStyles.badgeCorrect : defaultStyles.badgeIncorrect),\r\n }}\r\n >\r\n {answer.isCorrect ? 'Correct' : 'Incorrect'}\r\n </span>\r\n </div>\r\n\r\n <div style={defaultStyles.questionText}>{answer.questionText}</div>\r\n\r\n <div style={defaultStyles.answerSection}>\r\n <span style={defaultStyles.answerLabel}>Your answer:</span>\r\n <span style={defaultStyles.studentAnswer}>\r\n {formatAnswer(answer.selectedAnswer)}\r\n </span>\r\n </div>\r\n\r\n {!answer.isCorrect && answer.correctAnswer && (\r\n <div style={defaultStyles.answerSection}>\r\n <span style={defaultStyles.answerLabel}>Correct answer:</span>\r\n <span style={defaultStyles.correctAnswer}>\r\n {formatAnswer(answer.correctAnswer)}\r\n </span>\r\n </div>\r\n )}\r\n\r\n <div style={defaultStyles.points}>\r\n {answer.pointsEarned} / {answer.points} points\r\n </div>\r\n\r\n {showExplanations && answer.explanation && (\r\n <div style={defaultStyles.explanation}>\r\n <strong>Explanation:</strong> {answer.explanation}\r\n </div>\r\n )}\r\n\r\n {/* Chat History Section */}\r\n {showConversation && chatHistories[answer.questionId] && chatHistories[answer.questionId].messages.length > 0 && (\r\n <div style={defaultStyles.chatHistorySection}>\r\n <button\r\n style={defaultStyles.chatToggleButton}\r\n onClick={() => toggleChatExpanded(answer.questionId)}\r\n data-testid={`button-toggle-chat-${answer.questionId}`}\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\r\n </svg>\r\n {expandedChats.has(answer.questionId) ? 'Hide' : 'View'} Chat History ({chatHistories[answer.questionId].messages.length} messages)\r\n </button>\r\n \r\n {expandedChats.has(answer.questionId) && (\r\n <div style={defaultStyles.chatMessages}>\r\n {chatHistories[answer.questionId].messages.map((msg, msgIndex) => (\r\n <div\r\n key={msgIndex}\r\n style={{\r\n ...defaultStyles.chatMessage,\r\n ...(msg.role === 'user' ? defaultStyles.chatMessageUser : defaultStyles.chatMessageAssistant),\r\n }}\r\n >\r\n {msg.content}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","VolumeIcon","import_jsx_runtime","selectedAnswer","result","import_react","import_jsx_runtime","defaultStyles"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/QuizPlayer.tsx","../src/api.ts","../src/utils.ts","../src/TextToSpeech.tsx","../src/QuestionChatPanel.tsx","../src/AttemptViewer.tsx"],"sourcesContent":["// Main components\r\nexport { QuizPlayer } from './QuizPlayer';\r\nexport { AttemptViewer } from './AttemptViewer';\r\nexport { TextToSpeech } from './TextToSpeech';\r\n\r\n// API client for custom implementations\r\nexport { QuizApiClient } from './api';\r\nexport type { ApiClientConfig } from './api';\r\n\r\n// Utility functions\r\nexport { checkAnswer, createAnswerDetail, calculateScore, formatTime } from './utils';\r\n\r\n// Types\r\nexport type {\r\n QuestionType,\r\n QuizQuestion,\r\n Quiz,\r\n QuizAnswerDetail,\r\n AttemptStatus,\r\n ExternalQuizAttempt,\r\n QuizPlayerProps,\r\n QuizResult,\r\n QuizProgress,\r\n QuizPlayerStyles,\r\n AttemptViewerProps,\r\n GenerateMoreQuestionsResult,\r\n} from './types';\r\n","import { useState, useEffect, useCallback, useRef } from 'react';\r\nimport type {\r\n QuizPlayerProps,\r\n Quiz,\r\n QuizQuestion,\r\n QuizAnswerDetail,\r\n ExternalQuizAttempt,\r\n QuizResult,\r\n SkipReason,\r\n QuestionContextForChat,\r\n} from './types';\r\nimport { QuizApiClient } from './api';\r\nimport { createAnswerDetail, calculateScore, formatTime } from './utils';\r\nimport { TextToSpeech } from './TextToSpeech';\r\nimport { QuestionChatPanel } from './QuestionChatPanel';\r\n\r\n// Default styles that can be overridden\r\nconst defaultStyles = {\r\n container: {\r\n fontFamily: 'system-ui, -apple-system, sans-serif',\r\n width: '100%',\r\n height: '100%',\r\n maxHeight: 'calc(100vh - 40px)',\r\n padding: '20px',\r\n backgroundColor: '#ffffff',\r\n borderRadius: '12px',\r\n boxSizing: 'border-box' as const,\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n overflow: 'hidden',\r\n },\r\n header: {\r\n marginBottom: '20px',\r\n borderBottom: '1px solid #e5e7eb',\r\n paddingBottom: '16px',\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n },\r\n headerTop: {\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n alignItems: 'flex-start',\r\n },\r\n headerLeft: {\r\n flex: 1,\r\n },\r\n title: {\r\n fontSize: '24px',\r\n fontWeight: '600',\r\n marginBottom: '8px',\r\n },\r\n progress: {\r\n fontSize: '14px',\r\n color: '#6b7280',\r\n },\r\n progressBar: {\r\n width: '100%',\r\n height: '8px',\r\n backgroundColor: '#e5e7eb',\r\n borderRadius: '4px',\r\n overflow: 'hidden' as const,\r\n marginTop: '8px',\r\n },\r\n progressFill: {\r\n height: '100%',\r\n backgroundColor: '#6721b0',\r\n transition: 'width 0.3s ease',\r\n },\r\n question: {\r\n marginBottom: '24px',\r\n minHeight: '280px',\r\n },\r\n questionText: {\r\n fontSize: '18px',\r\n fontWeight: '500',\r\n marginBottom: '16px',\r\n },\r\n options: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '8px',\r\n },\r\n option: {\r\n width: '100%',\r\n padding: '12px 16px',\r\n border: '2px solid #e5e7eb',\r\n borderRadius: '8px',\r\n cursor: 'pointer',\r\n transition: 'all 0.2s ease',\r\n outline: 'none',\r\n boxShadow: 'none',\r\n backgroundColor: '#ffffff',\r\n WebkitTapHighlightColor: 'transparent',\r\n userSelect: 'none' as const,\r\n boxSizing: 'border-box' as const,\r\n },\r\n optionSelected: {\r\n borderColor: '#6721b0',\r\n backgroundColor: '#f3e8ff',\r\n },\r\n optionCorrect: {\r\n borderColor: '#22c55e',\r\n backgroundColor: '#f0fdf4',\r\n },\r\n optionIncorrect: {\r\n borderColor: '#ef4444',\r\n backgroundColor: '#fef2f2',\r\n },\r\n input: {\r\n width: '100%',\r\n padding: '12px 16px',\r\n border: '2px solid #e5e7eb',\r\n borderRadius: '8px',\r\n fontSize: '16px',\r\n outline: 'none',\r\n boxSizing: 'border-box' as const,\r\n backgroundColor: '#ffffff',\r\n },\r\n buttons: {\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n marginTop: '24px',\r\n },\r\n button: {\r\n padding: '12px 24px',\r\n borderRadius: '8px',\r\n fontSize: '16px',\r\n fontWeight: '500',\r\n cursor: 'pointer',\r\n border: 'none',\r\n transition: 'all 0.2s ease',\r\n },\r\n buttonPrimary: {\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n },\r\n buttonSecondary: {\r\n backgroundColor: '#f3f4f6',\r\n color: '#374151',\r\n },\r\n buttonDisabled: {\r\n backgroundColor: '#e5e7eb',\r\n color: '#9ca3af',\r\n cursor: 'not-allowed',\r\n },\r\n buttonAddMore: {\r\n padding: '12px 24px',\r\n borderRadius: '8px',\r\n fontSize: '16px',\r\n fontWeight: '500',\r\n cursor: 'pointer',\r\n border: '2px solid #6721b0',\r\n backgroundColor: 'transparent',\r\n color: '#6721b0',\r\n transition: 'all 0.2s ease',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n gap: '8px',\r\n },\r\n buttonAddMoreDisabled: {\r\n border: '2px solid #e5e7eb',\r\n color: '#9ca3af',\r\n cursor: 'not-allowed',\r\n },\r\n buttonsColumn: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '12px',\r\n marginTop: '24px',\r\n },\r\n mainLayout: {\r\n display: 'flex',\r\n gap: '24px',\r\n flex: 1,\r\n minHeight: 0,\r\n alignItems: 'stretch',\r\n overflow: 'hidden',\r\n },\r\n quizContent: {\r\n flex: 1,\r\n minWidth: 0,\r\n minHeight: 0,\r\n overflow: 'auto',\r\n },\r\n chatPanel: {\r\n width: '320px',\r\n flexShrink: 0,\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n minHeight: 0,\r\n overflow: 'hidden',\r\n },\r\n timer: {\r\n fontSize: '14px',\r\n color: '#6b7280',\r\n marginLeft: '16px',\r\n },\r\n results: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n padding: '48px 24px',\r\n textAlign: 'center' as const,\r\n minHeight: '400px',\r\n position: 'relative' as const,\r\n overflow: 'hidden' as const,\r\n },\r\n resultsBackground: {\r\n position: 'absolute' as const,\r\n inset: '0',\r\n borderRadius: '16px',\r\n zIndex: 0,\r\n },\r\n resultsContent: {\r\n position: 'relative' as const,\r\n zIndex: 1,\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n alignItems: 'center',\r\n },\r\n resultDetails: {\r\n fontSize: '18px',\r\n color: '#6b7280',\r\n marginBottom: '4px',\r\n },\r\n resultStars: {\r\n display: 'flex',\r\n justifyContent: 'center',\r\n gap: '8px',\r\n marginBottom: '20px',\r\n },\r\n resultStar: {\r\n fontSize: '32px',\r\n animation: 'starPop 0.5s ease-out forwards',\r\n opacity: 0,\r\n },\r\n confettiContainer: {\r\n position: 'absolute' as const,\r\n inset: '0',\r\n pointerEvents: 'none' as const,\r\n overflow: 'hidden' as const,\r\n zIndex: 0,\r\n },\r\n confettiPiece: {\r\n position: 'absolute' as const,\r\n width: '10px',\r\n height: '10px',\r\n top: '-10px',\r\n animation: 'confettiFall 3s ease-out forwards',\r\n },\r\n loading: {\r\n textAlign: 'center' as const,\r\n padding: '40px',\r\n color: '#6b7280',\r\n },\r\n error: {\r\n textAlign: 'center' as const,\r\n padding: '40px',\r\n color: '#ef4444',\r\n },\r\n intro: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n padding: '48px 24px',\r\n textAlign: 'center' as const,\r\n background: 'linear-gradient(135deg, #f3e8ff 0%, #e0e7ff 50%, #fce7f3 100%)',\r\n borderRadius: '16px',\r\n minHeight: '320px',\r\n },\r\n introTitle: {\r\n fontSize: '28px',\r\n fontWeight: '700',\r\n color: '#4c1d95',\r\n marginBottom: '12px',\r\n },\r\n introSubtitle: {\r\n fontSize: '16px',\r\n color: '#6b7280',\r\n marginBottom: '8px',\r\n },\r\n introQuestionCount: {\r\n fontSize: '14px',\r\n color: '#8b5cf6',\r\n marginBottom: '32px',\r\n fontWeight: '500',\r\n },\r\n startButton: {\r\n padding: '16px 48px',\r\n fontSize: '18px',\r\n fontWeight: '600',\r\n backgroundColor: '#7c3aed',\r\n color: '#ffffff',\r\n border: 'none',\r\n borderRadius: '12px',\r\n cursor: 'pointer',\r\n transition: 'all 0.2s ease',\r\n boxShadow: '0 4px 14px rgba(124, 58, 237, 0.4)',\r\n },\r\n feedback: {\r\n marginTop: '16px',\r\n padding: '16px',\r\n borderRadius: '8px',\r\n backgroundColor: '#f9fafb',\r\n border: '1px solid #e5e7eb',\r\n },\r\n feedbackCorrect: {\r\n backgroundColor: '#f0fdf4',\r\n borderColor: '#22c55e',\r\n },\r\n feedbackIncorrect: {\r\n backgroundColor: '#fef2f2',\r\n borderColor: '#ef4444',\r\n },\r\n feedbackTitle: {\r\n fontSize: '16px',\r\n fontWeight: '600',\r\n marginBottom: '8px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n },\r\n feedbackTitleCorrect: {\r\n color: '#16a34a',\r\n },\r\n feedbackTitleIncorrect: {\r\n color: '#dc2626',\r\n },\r\n feedbackExplanation: {\r\n fontSize: '14px',\r\n color: '#4b5563',\r\n lineHeight: '1.5',\r\n },\r\n};\r\n\r\n// Inline spinner component\r\nfunction Spinner({ size = 16, color = '#ffffff' }: { size?: number; color?: string }) {\r\n return (\r\n <span\r\n style={{\r\n display: 'inline-block',\r\n width: size,\r\n height: size,\r\n border: `2px solid ${color}`,\r\n borderTopColor: 'transparent',\r\n borderRadius: '50%',\r\n animation: 'spin 0.8s linear infinite',\r\n }}\r\n >\r\n <style>\r\n {`@keyframes spin { to { transform: rotate(360deg); } }`}\r\n </style>\r\n </span>\r\n );\r\n}\r\n\r\nexport function QuizPlayer({\r\n quizId,\r\n lessonId,\r\n assignLessonId,\r\n courseId,\r\n childId,\r\n parentId,\r\n apiBaseUrl,\r\n authToken,\r\n onComplete,\r\n onError,\r\n onProgress,\r\n onGenerateMoreQuestions,\r\n className,\r\n forceNewAttempt = true,\r\n}: QuizPlayerProps) {\r\n const [quiz, setQuiz] = useState<Quiz | null>(null);\r\n const [attempt, setAttempt] = useState<ExternalQuizAttempt | null>(null);\r\n const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);\r\n const [answers, setAnswers] = useState<Map<string, unknown>>(new Map());\r\n const [answersDetail, setAnswersDetail] = useState<QuizAnswerDetail[]>([]);\r\n const [isSubmitting, setIsSubmitting] = useState(false);\r\n const [isNavigating, setIsNavigating] = useState(false);\r\n const [isCompleted, setIsCompleted] = useState(false);\r\n const [result, setResult] = useState<QuizResult | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n const [isLoading, setIsLoading] = useState(true);\r\n const [elapsedSeconds, setElapsedSeconds] = useState(0);\r\n const [showIntro, setShowIntro] = useState(true);\r\n const [timerStarted, setTimerStarted] = useState(false);\r\n const [showFeedback, setShowFeedback] = useState(false);\r\n const [currentAnswerDetail, setCurrentAnswerDetail] = useState<QuizAnswerDetail | null>(null);\r\n const [extraQuestions, setExtraQuestions] = useState<QuizQuestion[]>([]);\r\n const [isGeneratingExtra, setIsGeneratingExtra] = useState(false);\r\n const [showSkipModal, setShowSkipModal] = useState(false);\r\n const [skippedQuestionIds, setSkippedQuestionIds] = useState<Set<string>>(new Set());\r\n const [isSkipping, setIsSkipping] = useState(false);\r\n const [skipComment, setSkipComment] = useState('');\r\n const [selectedSkipReason, setSelectedSkipReason] = useState<SkipReason | null>(null);\r\n \r\n // Report states (for premade questions)\r\n const [showReportModal, setShowReportModal] = useState(false);\r\n const [isReporting, setIsReporting] = useState(false);\r\n const [reportComment, setReportComment] = useState('');\r\n\r\n const apiClient = useRef<QuizApiClient | null>(null);\r\n const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);\r\n const startTimeRef = useRef<number>(0);\r\n\r\n // Refs for callback props to prevent useEffect re-runs when parent re-renders\r\n const onCompleteRef = useRef(onComplete);\r\n const onErrorRef = useRef(onError);\r\n const onProgressRef = useRef(onProgress);\r\n const onGenerateMoreQuestionsRef = useRef(onGenerateMoreQuestions);\r\n\r\n // Keep refs up to date with latest callbacks\r\n useEffect(() => {\r\n onCompleteRef.current = onComplete;\r\n onErrorRef.current = onError;\r\n onProgressRef.current = onProgress;\r\n onGenerateMoreQuestionsRef.current = onGenerateMoreQuestions;\r\n });\r\n\r\n // Initialize API client\r\n useEffect(() => {\r\n apiClient.current = new QuizApiClient({ baseUrl: apiBaseUrl, authToken });\r\n }, [apiBaseUrl, authToken]);\r\n\r\n // Load quiz and create/resume attempt\r\n useEffect(() => {\r\n async function initialize() {\r\n if (!apiClient.current) return;\r\n\r\n try {\r\n setIsLoading(true);\r\n setError(null);\r\n\r\n // Fetch quiz\r\n const quizData = await apiClient.current.getQuiz(quizId);\r\n setQuiz(quizData);\r\n\r\n // Create attempt (forceNew ensures clean slate for multiple attempts)\r\n const attemptData = await apiClient.current.createAttempt({\r\n quizId,\r\n lessonId,\r\n assignLessonId,\r\n courseId,\r\n childId,\r\n parentId,\r\n forceNew: forceNewAttempt,\r\n });\r\n setAttempt(attemptData);\r\n\r\n // Resume from existing answers if resuming an in-progress attempt (not forcing new)\r\n if (!forceNewAttempt && attemptData.answers && attemptData.answers.length > 0) {\r\n setAnswersDetail(attemptData.answers);\r\n const answersMap = new Map<string, unknown>();\r\n attemptData.answers.forEach(a => {\r\n answersMap.set(a.questionId, a.selectedAnswer);\r\n });\r\n setAnswers(answersMap);\r\n }\r\n\r\n // Check if already completed\r\n if (attemptData.status === 'completed') {\r\n setIsCompleted(true);\r\n const scoreData = calculateScore(attemptData.answers);\r\n setResult({\r\n attemptId: attemptData.id,\r\n score: attemptData.score || scoreData.score,\r\n correctAnswers: attemptData.correctAnswers || scoreData.correctAnswers,\r\n totalQuestions: attemptData.totalQuestions,\r\n answers: attemptData.answers,\r\n timeSpentSeconds: attemptData.timeSpentSeconds || 0,\r\n });\r\n }\r\n\r\n setIsLoading(false);\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : 'Failed to load quiz';\r\n setError(message);\r\n setIsLoading(false);\r\n onErrorRef.current?.(err instanceof Error ? err : new Error(message));\r\n }\r\n }\r\n\r\n initialize();\r\n }, [quizId, lessonId, assignLessonId, courseId, childId, parentId, forceNewAttempt]);\r\n\r\n // Timer - only starts when timerStarted is true (after clicking Start)\r\n useEffect(() => {\r\n if (timerStarted && !isCompleted && !error) {\r\n startTimeRef.current = Date.now();\r\n timerRef.current = setInterval(() => {\r\n setElapsedSeconds(Math.floor((Date.now() - startTimeRef.current) / 1000));\r\n }, 1000);\r\n }\r\n\r\n return () => {\r\n if (timerRef.current) {\r\n clearInterval(timerRef.current);\r\n }\r\n };\r\n }, [timerStarted, isCompleted, error]);\r\n\r\n // Handle start button click\r\n const handleStart = useCallback(() => {\r\n setShowIntro(false);\r\n setTimerStarted(true);\r\n }, []);\r\n\r\n // Reset feedback state when question changes\r\n useEffect(() => {\r\n setShowFeedback(false);\r\n setCurrentAnswerDetail(null);\r\n }, [currentQuestionIndex]);\r\n\r\n // Combine original questions with extra generated questions, excluding skipped ones\r\n const allQuestions = quiz \r\n ? [...quiz.questions, ...extraQuestions].filter(q => !skippedQuestionIds.has(q.id)) \r\n : [];\r\n const totalQuestions = allQuestions.length;\r\n const maxQuestions = 50;\r\n\r\n // Report progress\r\n useEffect(() => {\r\n if (quiz && onProgressRef.current) {\r\n onProgressRef.current({\r\n currentQuestion: currentQuestionIndex + 1,\r\n totalQuestions: totalQuestions,\r\n answeredQuestions: answers.size,\r\n });\r\n }\r\n }, [currentQuestionIndex, answers.size, quiz, totalQuestions]);\r\n\r\n const currentQuestion = allQuestions[currentQuestionIndex];\r\n\r\n const handleAnswerChange = useCallback((value: unknown) => {\r\n if (!currentQuestion) return;\r\n setAnswers(prev => new Map(prev).set(currentQuestion.id, value));\r\n }, [currentQuestion]);\r\n\r\n // Check answer and show feedback\r\n const handleCheckAnswer = useCallback(async () => {\r\n if (!quiz || !attempt || !currentQuestion || !apiClient.current) return;\r\n\r\n const selectedAnswer = answers.get(currentQuestion.id);\r\n if (selectedAnswer === undefined) return;\r\n\r\n setIsNavigating(true);\r\n\r\n // Create answer detail\r\n const answerDetail = createAnswerDetail(currentQuestion, selectedAnswer);\r\n setCurrentAnswerDetail(answerDetail);\r\n \r\n // Update answers detail state\r\n const newAnswersDetail = [...answersDetail];\r\n const existingIdx = newAnswersDetail.findIndex(a => a.questionId === currentQuestion.id);\r\n if (existingIdx >= 0) {\r\n newAnswersDetail[existingIdx] = answerDetail;\r\n } else {\r\n newAnswersDetail.push(answerDetail);\r\n }\r\n setAnswersDetail(newAnswersDetail);\r\n\r\n // Save progress to server\r\n try {\r\n await apiClient.current.updateAttempt(attempt.id, {\r\n answers: newAnswersDetail,\r\n });\r\n } catch (err) {\r\n console.error('Failed to save progress:', err);\r\n } finally {\r\n setIsNavigating(false);\r\n }\r\n\r\n // Show feedback instead of moving to next question\r\n setShowFeedback(true);\r\n }, [quiz, attempt, currentQuestion, answers, answersDetail]);\r\n\r\n // Continue to next question after viewing feedback\r\n const handleContinue = useCallback(() => {\r\n if (!quiz) return;\r\n \r\n setShowFeedback(false);\r\n setCurrentAnswerDetail(null);\r\n \r\n // Move to next question (use totalQuestions which includes extras)\r\n if (currentQuestionIndex < totalQuestions - 1) {\r\n setCurrentQuestionIndex(prev => prev + 1);\r\n }\r\n }, [quiz, currentQuestionIndex, totalQuestions]);\r\n\r\n // Generate more questions handler\r\n const handleAddMoreQuestions = useCallback(async () => {\r\n if (!attempt || !onGenerateMoreQuestions || isGeneratingExtra) return;\r\n \r\n // Check if we've reached the limit\r\n if (totalQuestions >= maxQuestions) return;\r\n \r\n setIsGeneratingExtra(true);\r\n try {\r\n const result = await onGenerateMoreQuestionsRef.current!(attempt.id, totalQuestions);\r\n \r\n if (result.extraQuestions && result.extraQuestions.length > 0) {\r\n // Clamp new questions to not exceed 50 total\r\n const slotsAvailable = maxQuestions - totalQuestions;\r\n const questionsToAppend = result.extraQuestions.slice(0, slotsAvailable);\r\n \r\n if (questionsToAppend.length > 0) {\r\n setExtraQuestions(prev => [...prev, ...questionsToAppend]);\r\n \r\n // Move to the first new question\r\n setCurrentQuestionIndex(totalQuestions);\r\n setShowFeedback(false);\r\n setCurrentAnswerDetail(null);\r\n }\r\n }\r\n } catch (err) {\r\n console.error('Failed to generate extra questions:', err);\r\n onErrorRef.current?.(err instanceof Error ? err : new Error('Failed to generate extra questions'));\r\n } finally {\r\n setIsGeneratingExtra(false);\r\n }\r\n }, [attempt, isGeneratingExtra, totalQuestions, maxQuestions]);\r\n\r\n const handleSubmit = useCallback(async () => {\r\n if (!quiz || !attempt || !apiClient.current) return;\r\n\r\n setIsSubmitting(true);\r\n\r\n try {\r\n // Ensure current answer is saved\r\n const currentAnswer = currentQuestion ? answers.get(currentQuestion.id) : undefined;\r\n let finalAnswersDetail = [...answersDetail];\r\n \r\n if (currentQuestion && currentAnswer !== undefined) {\r\n const answerDetail = createAnswerDetail(currentQuestion, currentAnswer);\r\n const existingIdx = finalAnswersDetail.findIndex(a => a.questionId === currentQuestion.id);\r\n if (existingIdx >= 0) {\r\n finalAnswersDetail[existingIdx] = answerDetail;\r\n } else {\r\n finalAnswersDetail.push(answerDetail);\r\n }\r\n }\r\n\r\n // Calculate final score\r\n const scoreData = calculateScore(finalAnswersDetail);\r\n const timeSpent = timerStarted && startTimeRef.current > 0 \r\n ? Math.floor((Date.now() - startTimeRef.current) / 1000) \r\n : elapsedSeconds;\r\n\r\n // Submit to server (include totalQuestions to account for dynamically added extra questions)\r\n const updatedAttempt = await apiClient.current.updateAttempt(attempt.id, {\r\n answers: finalAnswersDetail,\r\n status: 'completed',\r\n score: scoreData.score,\r\n correctAnswers: scoreData.correctAnswers,\r\n totalQuestions: totalQuestions,\r\n timeSpentSeconds: timeSpent,\r\n });\r\n\r\n // Update state\r\n setIsCompleted(true);\r\n const quizResult: QuizResult = {\r\n attemptId: updatedAttempt.id,\r\n score: scoreData.score,\r\n correctAnswers: scoreData.correctAnswers,\r\n totalQuestions: totalQuestions,\r\n answers: finalAnswersDetail,\r\n timeSpentSeconds: timeSpent,\r\n };\r\n setResult(quizResult);\r\n\r\n // Stop timer\r\n if (timerRef.current) {\r\n clearInterval(timerRef.current);\r\n }\r\n\r\n // Callback\r\n onCompleteRef.current?.(quizResult);\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : 'Failed to submit quiz';\r\n setError(message);\r\n onErrorRef.current?.(err instanceof Error ? err : new Error(message));\r\n } finally {\r\n setIsSubmitting(false);\r\n }\r\n }, [quiz, attempt, currentQuestion, answers, answersDetail, totalQuestions, timerStarted, elapsedSeconds]);\r\n\r\n // Check if current question is an \"extra\" (dynamically generated) question\r\n const isExtraQuestion = currentQuestion && extraQuestions.some(q => q.id === currentQuestion.id);\r\n\r\n // Handle skip question (only for extra questions)\r\n const handleSkipQuestion = useCallback(async (reason: SkipReason, comment?: string) => {\r\n if (!currentQuestion || !apiClient.current || !attempt) return;\r\n \r\n setIsSkipping(true);\r\n try {\r\n // Submit skip to backend\r\n await apiClient.current.skipQuestion({\r\n questionId: currentQuestion.id,\r\n questionContent: currentQuestion,\r\n skipReason: reason,\r\n skipComment: comment?.trim() || undefined,\r\n quizId: quiz?.id,\r\n attemptId: attempt.id,\r\n childId,\r\n parentId,\r\n lessonId,\r\n courseId,\r\n assignLessonId,\r\n });\r\n\r\n // Mark question as skipped (remove from active questions)\r\n const newSkippedIds = new Set(skippedQuestionIds).add(currentQuestion.id);\r\n setSkippedQuestionIds(newSkippedIds);\r\n \r\n // Remove from extraQuestions\r\n const newExtraQuestions = extraQuestions.filter(q => q.id !== currentQuestion.id);\r\n setExtraQuestions(newExtraQuestions);\r\n \r\n // Calculate new total questions after skip\r\n const newAllQuestions = quiz \r\n ? [...quiz.questions, ...newExtraQuestions].filter(q => !newSkippedIds.has(q.id))\r\n : [];\r\n const newTotalQuestions = newAllQuestions.length;\r\n \r\n // Handle navigation after skip\r\n if (newTotalQuestions === 0) {\r\n // All questions skipped - complete the quiz\r\n setIsCompleted(true);\r\n const quizResult: QuizResult = {\r\n attemptId: attempt.id,\r\n score: 0,\r\n correctAnswers: 0,\r\n totalQuestions: 0,\r\n answers: [],\r\n timeSpentSeconds: elapsedSeconds,\r\n };\r\n setResult(quizResult);\r\n onCompleteRef.current?.(quizResult);\r\n } else if (currentQuestionIndex >= newTotalQuestions) {\r\n // We were at the last question, move back to the new last question\r\n setCurrentQuestionIndex(newTotalQuestions - 1);\r\n }\r\n // Otherwise stay at current index (next question slides into place)\r\n \r\n // Close modal and reset state\r\n setShowSkipModal(false);\r\n setSkipComment('');\r\n setSelectedSkipReason(null);\r\n } catch (err) {\r\n console.error('Failed to skip question:', err);\r\n } finally {\r\n setIsSkipping(false);\r\n }\r\n }, [currentQuestion, apiClient, attempt, quiz, childId, parentId, lessonId, courseId, assignLessonId, skippedQuestionIds, extraQuestions, currentQuestionIndex, elapsedSeconds]);\r\n\r\n // Handle report question (only for premade questions - doesn't remove question)\r\n const handleReportQuestion = useCallback(async (comment: string) => {\r\n if (!currentQuestion || !apiClient.current || !attempt || !comment.trim()) return;\r\n \r\n setIsReporting(true);\r\n try {\r\n // Submit report to backend\r\n await apiClient.current.reportQuestion({\r\n questionId: currentQuestion.id,\r\n questionContent: currentQuestion,\r\n reportComment: comment.trim(),\r\n quizId: quiz?.id,\r\n attemptId: attempt.id,\r\n childId,\r\n parentId,\r\n lessonId,\r\n courseId,\r\n assignLessonId,\r\n });\r\n\r\n // Close modal and reset state (question remains - user still answers it)\r\n setShowReportModal(false);\r\n setReportComment('');\r\n } catch (err) {\r\n console.error('Failed to report question:', err);\r\n } finally {\r\n setIsReporting(false);\r\n }\r\n }, [currentQuestion, apiClient, attempt, quiz, childId, parentId, lessonId, courseId, assignLessonId]);\r\n\r\n // Render loading state\r\n if (isLoading) {\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <div style={defaultStyles.loading}>Loading quiz...</div>\r\n </div>\r\n );\r\n }\r\n\r\n // Render error state\r\n if (error) {\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <div style={defaultStyles.error}>\r\n <p>Error: {error}</p>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n // Render completed state\r\n if (isCompleted && result) {\r\n // Calculate percentage based on correct answers (not points)\r\n // Guard against division by zero when all questions were skipped\r\n const percentage = result.totalQuestions > 0 \r\n ? Math.round((result.correctAnswers / result.totalQuestions) * 100)\r\n : 0;\r\n \r\n // Determine theme based on percentage\r\n const getScoreTheme = (pct: number) => {\r\n if (pct >= 80) {\r\n return {\r\n color: '#22c55e',\r\n bgGradient: 'linear-gradient(135deg, #dcfce7 0%, #bbf7d0 50%, #86efac 100%)',\r\n badge: 'Quiz Champion!',\r\n badgeColor: '#fbbf24',\r\n badgeBg: 'linear-gradient(135deg, #fef3c7 0%, #fde68a 100%)',\r\n mascotMood: 'celebrating',\r\n stars: 3,\r\n };\r\n } else if (pct >= 60) {\r\n return {\r\n color: '#f59e0b',\r\n bgGradient: 'linear-gradient(135deg, #fef3c7 0%, #fde68a 50%, #fcd34d 100%)',\r\n badge: 'Rising Star!',\r\n badgeColor: '#f59e0b',\r\n badgeBg: 'linear-gradient(135deg, #fed7aa 0%, #fdba74 100%)',\r\n mascotMood: 'happy',\r\n stars: 2,\r\n };\r\n } else if (pct >= 40) {\r\n return {\r\n color: '#3b82f6',\r\n bgGradient: 'linear-gradient(135deg, #dbeafe 0%, #bfdbfe 50%, #93c5fd 100%)',\r\n badge: 'Great Learner!',\r\n badgeColor: '#3b82f6',\r\n badgeBg: 'linear-gradient(135deg, #bfdbfe 0%, #93c5fd 100%)',\r\n mascotMood: 'encouraging',\r\n stars: 1,\r\n };\r\n } else {\r\n return {\r\n color: '#8b5cf6',\r\n bgGradient: 'linear-gradient(135deg, #f3e8ff 0%, #e9d5ff 50%, #d8b4fe 100%)',\r\n badge: 'Keep Growing!',\r\n badgeColor: '#8b5cf6',\r\n badgeBg: 'linear-gradient(135deg, #e9d5ff 0%, #d8b4fe 100%)',\r\n mascotMood: 'supportive',\r\n stars: 0,\r\n };\r\n }\r\n };\r\n\r\n const theme = getScoreTheme(percentage);\r\n\r\n // Generate confetti pieces\r\n const confettiColors = ['#f43f5e', '#ec4899', '#8b5cf6', '#3b82f6', '#22c55e', '#f59e0b', '#ef4444'];\r\n const confettiPieces = Array.from({ length: 50 }, (_, i) => ({\r\n id: i,\r\n left: `${Math.random() * 100}%`,\r\n delay: `${Math.random() * 2}s`,\r\n duration: `${2 + Math.random() * 2}s`,\r\n color: confettiColors[Math.floor(Math.random() * confettiColors.length)],\r\n rotation: Math.random() * 360,\r\n size: 6 + Math.random() * 8,\r\n }));\r\n\r\n // Star SVG component\r\n const StarIcon = ({ filled, delay }: { filled: boolean; delay: number }) => (\r\n <svg\r\n width=\"36\"\r\n height=\"36\"\r\n viewBox=\"0 0 24 24\"\r\n style={{\r\n animation: 'starPop 0.5s ease-out forwards',\r\n animationDelay: `${delay}s`,\r\n opacity: 0,\r\n }}\r\n >\r\n <path\r\n d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\"\r\n fill={filled ? '#fbbf24' : '#e5e7eb'}\r\n stroke={filled ? '#f59e0b' : '#d1d5db'}\r\n strokeWidth=\"1\"\r\n />\r\n </svg>\r\n );\r\n\r\n // Mascot SVG component - a friendly owl character\r\n const MascotOwl = ({ mood }: { mood: string }) => {\r\n const getEyeExpression = () => {\r\n switch (mood) {\r\n case 'celebrating':\r\n return { leftEye: '>', rightEye: '<', pupilY: 42 }; // Squinting happy\r\n case 'happy':\r\n return { leftEye: null, rightEye: null, pupilY: 42 }; // Normal happy\r\n case 'encouraging':\r\n return { leftEye: null, rightEye: null, pupilY: 44 }; // Looking down warmly\r\n default:\r\n return { leftEye: null, rightEye: null, pupilY: 42 }; // Supportive\r\n }\r\n };\r\n const eyeExpr = getEyeExpression();\r\n\r\n return (\r\n <svg\r\n width=\"120\"\r\n height=\"120\"\r\n viewBox=\"0 0 100 100\"\r\n style={{\r\n animation: mood === 'celebrating' ? 'bounce 0.6s ease-in-out infinite' : 'gentleBob 2s ease-in-out infinite',\r\n }}\r\n >\r\n {/* Body */}\r\n <ellipse cx=\"50\" cy=\"60\" rx=\"35\" ry=\"30\" fill=\"#8b5cf6\" />\r\n {/* Belly */}\r\n <ellipse cx=\"50\" cy=\"65\" rx=\"25\" ry=\"20\" fill=\"#c4b5fd\" />\r\n {/* Head */}\r\n <circle cx=\"50\" cy=\"35\" r=\"28\" fill=\"#a78bfa\" />\r\n {/* Ear tufts */}\r\n <polygon points=\"28,15 35,30 22,28\" fill=\"#7c3aed\" />\r\n <polygon points=\"72,15 65,30 78,28\" fill=\"#7c3aed\" />\r\n {/* Eye whites */}\r\n <ellipse cx=\"38\" cy=\"38\" rx=\"10\" ry=\"12\" fill=\"white\" />\r\n <ellipse cx=\"62\" cy=\"38\" rx=\"10\" ry=\"12\" fill=\"white\" />\r\n {/* Pupils */}\r\n {eyeExpr.leftEye ? (\r\n <text x=\"38\" y=\"44\" textAnchor=\"middle\" fontSize=\"16\" fill=\"#1f2937\">{eyeExpr.leftEye}</text>\r\n ) : (\r\n <circle cx=\"38\" cy={eyeExpr.pupilY} r=\"5\" fill=\"#1f2937\" />\r\n )}\r\n {eyeExpr.rightEye ? (\r\n <text x=\"62\" y=\"44\" textAnchor=\"middle\" fontSize=\"16\" fill=\"#1f2937\">{eyeExpr.rightEye}</text>\r\n ) : (\r\n <circle cx=\"62\" cy={eyeExpr.pupilY} r=\"5\" fill=\"#1f2937\" />\r\n )}\r\n {/* Beak */}\r\n <polygon points=\"50,45 45,52 55,52\" fill=\"#fbbf24\" />\r\n {/* Blush for happy moods */}\r\n {(mood === 'celebrating' || mood === 'happy') && (\r\n <>\r\n <ellipse cx=\"28\" cy=\"45\" rx=\"5\" ry=\"3\" fill=\"#fda4af\" opacity=\"0.6\" />\r\n <ellipse cx=\"72\" cy=\"45\" rx=\"5\" ry=\"3\" fill=\"#fda4af\" opacity=\"0.6\" />\r\n </>\r\n )}\r\n {/* Wings */}\r\n {mood === 'celebrating' ? (\r\n <>\r\n <ellipse cx=\"18\" cy=\"55\" rx=\"8\" ry=\"15\" fill=\"#7c3aed\" transform=\"rotate(-30 18 55)\" />\r\n <ellipse cx=\"82\" cy=\"55\" rx=\"8\" ry=\"15\" fill=\"#7c3aed\" transform=\"rotate(30 82 55)\" />\r\n </>\r\n ) : (\r\n <>\r\n <ellipse cx=\"20\" cy=\"60\" rx=\"8\" ry=\"15\" fill=\"#7c3aed\" />\r\n <ellipse cx=\"80\" cy=\"60\" rx=\"8\" ry=\"15\" fill=\"#7c3aed\" />\r\n </>\r\n )}\r\n {/* Feet */}\r\n <ellipse cx=\"40\" cy=\"88\" rx=\"8\" ry=\"4\" fill=\"#fbbf24\" />\r\n <ellipse cx=\"60\" cy=\"88\" rx=\"8\" ry=\"4\" fill=\"#fbbf24\" />\r\n </svg>\r\n );\r\n };\r\n\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <style>\r\n {`\r\n @keyframes confettiFall {\r\n 0% {\r\n transform: translateY(-10px) rotate(0deg);\r\n opacity: 1;\r\n }\r\n 100% {\r\n transform: translateY(500px) rotate(720deg);\r\n opacity: 0;\r\n }\r\n }\r\n @keyframes starPop {\r\n 0% {\r\n transform: scale(0);\r\n opacity: 0;\r\n }\r\n 50% {\r\n transform: scale(1.3);\r\n }\r\n 100% {\r\n transform: scale(1);\r\n opacity: 1;\r\n }\r\n }\r\n @keyframes bounce {\r\n 0%, 100% {\r\n transform: translateY(0);\r\n }\r\n 50% {\r\n transform: translateY(-10px);\r\n }\r\n }\r\n @keyframes gentleBob {\r\n 0%, 100% {\r\n transform: translateY(0);\r\n }\r\n 50% {\r\n transform: translateY(-5px);\r\n }\r\n }\r\n @keyframes badgePop {\r\n 0% {\r\n transform: scale(0) rotate(-10deg);\r\n opacity: 0;\r\n }\r\n 60% {\r\n transform: scale(1.1) rotate(5deg);\r\n }\r\n 100% {\r\n transform: scale(1) rotate(0deg);\r\n opacity: 1;\r\n }\r\n }\r\n @keyframes scoreSlideIn {\r\n 0% {\r\n transform: translateY(20px);\r\n opacity: 0;\r\n }\r\n 100% {\r\n transform: translateY(0);\r\n opacity: 1;\r\n }\r\n }\r\n `}\r\n </style>\r\n <div style={defaultStyles.results}>\r\n {/* Confetti animation for high scores */}\r\n {percentage >= 60 && (\r\n <div style={defaultStyles.confettiContainer}>\r\n {confettiPieces.map((piece) => (\r\n <div\r\n key={piece.id}\r\n style={{\r\n ...defaultStyles.confettiPiece,\r\n left: piece.left,\r\n width: `${piece.size}px`,\r\n height: `${piece.size}px`,\r\n backgroundColor: piece.color,\r\n borderRadius: Math.random() > 0.5 ? '50%' : '2px',\r\n animationDelay: piece.delay,\r\n animationDuration: piece.duration,\r\n transform: `rotate(${piece.rotation}deg)`,\r\n }}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Background gradient */}\r\n <div style={{ ...defaultStyles.resultsBackground, background: theme.bgGradient }} />\r\n\r\n {/* Content */}\r\n <div style={defaultStyles.resultsContent}>\r\n {/* Stars */}\r\n <div style={defaultStyles.resultStars}>\r\n <StarIcon filled={theme.stars >= 1} delay={0.3} />\r\n <StarIcon filled={theme.stars >= 2} delay={0.5} />\r\n <StarIcon filled={theme.stars >= 3} delay={0.7} />\r\n </div>\r\n\r\n {/* Mascot Character */}\r\n <div style={{ marginBottom: '16px' }}>\r\n <MascotOwl mood={theme.mascotMood} />\r\n </div>\r\n\r\n {/* Achievement Badge */}\r\n <div\r\n style={{\r\n background: theme.badgeBg,\r\n padding: '12px 28px',\r\n borderRadius: '50px',\r\n boxShadow: '0 4px 12px rgba(0,0,0,0.15)',\r\n marginBottom: '20px',\r\n animation: 'badgePop 0.6s ease-out 0.2s forwards',\r\n opacity: 0,\r\n border: `3px solid ${theme.badgeColor}`,\r\n }}\r\n >\r\n <span\r\n style={{\r\n fontSize: '22px',\r\n fontWeight: '700',\r\n color: '#1f2937',\r\n textShadow: '0 1px 2px rgba(255,255,255,0.5)',\r\n }}\r\n >\r\n {theme.badge}\r\n </span>\r\n </div>\r\n\r\n {/* Big Score Display */}\r\n <div\r\n style={{\r\n animation: 'scoreSlideIn 0.5s ease-out 0.4s forwards',\r\n opacity: 0,\r\n }}\r\n >\r\n <div\r\n style={{\r\n fontSize: '48px',\r\n fontWeight: '800',\r\n color: theme.color,\r\n lineHeight: '1',\r\n marginBottom: '4px',\r\n }}\r\n >\r\n {result.correctAnswers} of {result.totalQuestions}\r\n </div>\r\n <div\r\n style={{\r\n fontSize: '20px',\r\n fontWeight: '600',\r\n color: '#6b7280',\r\n marginBottom: '12px',\r\n }}\r\n >\r\n correct answers\r\n </div>\r\n </div>\r\n\r\n {/* Time */}\r\n <div style={{ ...defaultStyles.resultDetails, marginTop: '8px' }}>\r\n Time: {formatTime(result.timeSpentSeconds)}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n // Render intro screen (after quiz is loaded but before requiring currentQuestion)\r\n if (quiz && showIntro) {\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <div style={defaultStyles.intro}>\r\n <div style={defaultStyles.introTitle}>{quiz.title}</div>\r\n <div style={defaultStyles.introSubtitle}>Ready to test your knowledge?</div>\r\n <div style={defaultStyles.introQuestionCount}>\r\n {quiz.questions.length} question{quiz.questions.length !== 1 ? 's' : ''} to answer\r\n </div>\r\n <button\r\n style={defaultStyles.startButton}\r\n onClick={handleStart}\r\n onMouseOver={(e) => {\r\n e.currentTarget.style.transform = 'translateY(-2px)';\r\n e.currentTarget.style.boxShadow = '0 6px 20px rgba(124, 58, 237, 0.5)';\r\n }}\r\n onMouseOut={(e) => {\r\n e.currentTarget.style.transform = 'translateY(0)';\r\n e.currentTarget.style.boxShadow = '0 4px 14px rgba(124, 58, 237, 0.4)';\r\n }}\r\n data-testid=\"button-start-quiz\"\r\n >\r\n Let's Start!\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n // Render quiz - guard for missing data\r\n if (!quiz || !currentQuestion) {\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <div style={defaultStyles.error}>No quiz data available</div>\r\n </div>\r\n );\r\n }\r\n\r\n const selectedAnswer = answers.get(currentQuestion.id);\r\n const isLastQuestion = currentQuestionIndex === totalQuestions - 1;\r\n const progressPercent = ((currentQuestionIndex + 1) / totalQuestions) * 100;\r\n const remainingSlots = maxQuestions - totalQuestions;\r\n const questionsToAdd = Math.min(5, remainingSlots);\r\n const canAddMore = onGenerateMoreQuestions && remainingSlots > 0;\r\n\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n {/* Main horizontal layout: left column + chat panel */}\r\n <div style={defaultStyles.mainLayout}>\r\n {/* Left column: header + quiz content */}\r\n <div style={defaultStyles.quizContent}>\r\n {/* Header - timer hidden to avoid exam pressure */}\r\n <div style={defaultStyles.header}>\r\n <div style={defaultStyles.title}>{quiz.title}</div>\r\n <div style={defaultStyles.progress}>\r\n Question {currentQuestionIndex + 1} of {totalQuestions}\r\n </div>\r\n <div style={defaultStyles.progressBar}>\r\n <div style={{ ...defaultStyles.progressFill, width: `${progressPercent}%` }} />\r\n </div>\r\n </div>\r\n {/* Question */}\r\n <div style={{ ...defaultStyles.question, position: 'relative', paddingBottom: '40px' }}>\r\n <div style={defaultStyles.questionText}>\r\n <TextToSpeech text={currentQuestion.question} inline size=\"md\" />\r\n </div>\r\n\r\n {/* Skip button for extra questions - subtle icon in bottom left */}\r\n {isExtraQuestion && (\r\n <button\r\n onClick={() => setShowSkipModal(true)}\r\n title=\"Skip question\"\r\n style={{\r\n position: 'absolute',\r\n bottom: '8px',\r\n left: '0',\r\n background: 'transparent',\r\n border: 'none',\r\n cursor: 'pointer',\r\n padding: '6px 10px',\r\n borderRadius: '6px',\r\n color: '#9ca3af',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n gap: '4px',\r\n fontSize: '12px',\r\n opacity: 0.6,\r\n transition: 'opacity 0.2s, color 0.2s',\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.opacity = '1';\r\n e.currentTarget.style.color = '#6b7280';\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.opacity = '0.6';\r\n e.currentTarget.style.color = '#9ca3af';\r\n }}\r\n data-testid=\"button-skip-question\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <polygon points=\"5 4 15 12 5 20 5 4\"></polygon>\r\n <line x1=\"19\" y1=\"5\" x2=\"19\" y2=\"19\"></line>\r\n </svg>\r\n <span>Skip</span>\r\n </button>\r\n )}\r\n\r\n {/* Report button for premade questions - subtle icon in bottom left */}\r\n {!isExtraQuestion && (\r\n <button\r\n onClick={() => setShowReportModal(true)}\r\n title=\"Report an issue with this question\"\r\n style={{\r\n position: 'absolute',\r\n bottom: '8px',\r\n left: '0',\r\n background: 'transparent',\r\n border: 'none',\r\n cursor: 'pointer',\r\n padding: '6px 10px',\r\n borderRadius: '6px',\r\n color: '#9ca3af',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n gap: '4px',\r\n fontSize: '12px',\r\n opacity: 0.6,\r\n transition: 'opacity 0.2s, color 0.2s',\r\n }}\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.opacity = '1';\r\n e.currentTarget.style.color = '#ef4444';\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.opacity = '0.6';\r\n e.currentTarget.style.color = '#9ca3af';\r\n }}\r\n data-testid=\"button-report-question\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <path d=\"M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z\"></path>\r\n <line x1=\"4\" y1=\"22\" x2=\"4\" y2=\"15\"></line>\r\n </svg>\r\n <span>Report</span>\r\n </button>\r\n )}\r\n\r\n {/* Render options based on question type */}\r\n {(currentQuestion.type === 'single' || currentQuestion.type === 'true-false') && (\r\n <div style={defaultStyles.options}>\r\n {currentQuestion.options?.map((option, idx) => {\r\n const isSelected = selectedAnswer === option;\r\n const isCorrectOption = currentQuestion.correctAnswer === option;\r\n \r\n let optionStyle = { ...defaultStyles.option };\r\n if (showFeedback) {\r\n if (isCorrectOption) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionCorrect };\r\n } else if (isSelected && !isCorrectOption) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionIncorrect };\r\n }\r\n } else if (isSelected) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };\r\n }\r\n \r\n return (\r\n <div\r\n key={idx}\r\n style={{\r\n ...optionStyle,\r\n cursor: showFeedback ? 'default' : 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n }}\r\n onClick={() => !showFeedback && handleAnswerChange(option)}\r\n >\r\n <span onClick={(e) => e.stopPropagation()}>\r\n <TextToSpeech text={option} size=\"sm\" />\r\n </span>\r\n <span style={{ flex: 1 }}>{option}</span>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {currentQuestion.type === 'multiple' && (\r\n <div style={defaultStyles.options}>\r\n {currentQuestion.options?.map((option, idx) => {\r\n const selected = Array.isArray(selectedAnswer) && selectedAnswer.includes(option);\r\n // Normalize correctAnswer to array (handle both string and array cases)\r\n const correctAnswers = Array.isArray(currentQuestion.correctAnswer) \r\n ? currentQuestion.correctAnswer \r\n : (currentQuestion.correctAnswer ? [currentQuestion.correctAnswer] : []);\r\n const isCorrectOption = correctAnswers.includes(option);\r\n \r\n let optionStyle = { ...defaultStyles.option };\r\n if (showFeedback) {\r\n if (isCorrectOption) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionCorrect };\r\n } else if (selected && !isCorrectOption) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionIncorrect };\r\n }\r\n } else if (selected) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };\r\n }\r\n \r\n return (\r\n <div\r\n key={idx}\r\n style={{\r\n ...optionStyle,\r\n cursor: showFeedback ? 'default' : 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n }}\r\n onClick={() => {\r\n if (showFeedback) return;\r\n const current = Array.isArray(selectedAnswer) ? selectedAnswer : [];\r\n if (selected) {\r\n handleAnswerChange(current.filter(o => o !== option));\r\n } else {\r\n handleAnswerChange([...current, option]);\r\n }\r\n }}\r\n >\r\n <span onClick={(e) => e.stopPropagation()}>\r\n <TextToSpeech text={option} size=\"sm\" />\r\n </span>\r\n <span style={{ flex: 1 }}>{option}</span>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {(currentQuestion.type === 'free' || currentQuestion.type === 'essay') && (\r\n <textarea\r\n style={{ ...defaultStyles.input, minHeight: currentQuestion.type === 'essay' ? '150px' : '60px' }}\r\n value={(selectedAnswer as string) || ''}\r\n onChange={e => handleAnswerChange(e.target.value)}\r\n placeholder=\"Type your answer here...\"\r\n disabled={showFeedback}\r\n />\r\n )}\r\n\r\n {currentQuestion.type === 'fill' && (\r\n <div style={defaultStyles.options}>\r\n {currentQuestion.blanks?.map((_, idx) => (\r\n <input\r\n key={idx}\r\n style={defaultStyles.input}\r\n value={(Array.isArray(selectedAnswer) ? selectedAnswer[idx] : '') || ''}\r\n onChange={e => {\r\n const current = Array.isArray(selectedAnswer) ? [...selectedAnswer] : [];\r\n current[idx] = e.target.value;\r\n handleAnswerChange(current);\r\n }}\r\n placeholder={`Blank ${idx + 1}`}\r\n disabled={showFeedback}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n\r\n {/* Feedback section */}\r\n {showFeedback && currentAnswerDetail && (\r\n <div style={{\r\n ...defaultStyles.feedback,\r\n ...(currentAnswerDetail.isCorrect ? defaultStyles.feedbackCorrect : defaultStyles.feedbackIncorrect),\r\n }}>\r\n <div style={{\r\n ...defaultStyles.feedbackTitle,\r\n ...(currentAnswerDetail.isCorrect ? defaultStyles.feedbackTitleCorrect : defaultStyles.feedbackTitleIncorrect),\r\n }}>\r\n {currentAnswerDetail.isCorrect ? '✓ Correct!' : '✗ Incorrect'}\r\n </div>\r\n {currentQuestion.explanation && (\r\n <div style={defaultStyles.feedbackExplanation}>\r\n {currentQuestion.explanation}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Skip reason modal */}\r\n {showSkipModal && (\r\n <div style={{\r\n position: 'fixed',\r\n top: 0,\r\n left: 0,\r\n right: 0,\r\n bottom: 0,\r\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n zIndex: 1000,\r\n }}>\r\n <div style={{\r\n backgroundColor: '#ffffff',\r\n borderRadius: '12px',\r\n padding: '24px',\r\n maxWidth: '400px',\r\n width: '90%',\r\n boxShadow: '0 20px 40px rgba(0, 0, 0, 0.2)',\r\n }}>\r\n <h3 style={{ margin: '0 0 8px 0', fontSize: '18px', fontWeight: '600', color: '#1f2937' }}>\r\n Skip Question\r\n </h3>\r\n <p style={{ margin: '0 0 16px 0', fontSize: '14px', color: '#6b7280' }}>\r\n Help us improve by telling us why you're skipping this question.\r\n </p>\r\n \r\n {/* Reason selection */}\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '8px', marginBottom: '16px' }}>\r\n <button\r\n onClick={() => setSelectedSkipReason('question_issue')}\r\n disabled={isSkipping}\r\n style={{\r\n padding: '12px 16px',\r\n borderRadius: '8px',\r\n border: selectedSkipReason === 'question_issue' ? '2px solid #8b5cf6' : '1px solid #e5e7eb',\r\n backgroundColor: selectedSkipReason === 'question_issue' ? '#f5f3ff' : '#f9fafb',\r\n cursor: isSkipping ? 'not-allowed' : 'pointer',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n color: '#374151',\r\n textAlign: 'left',\r\n opacity: isSkipping ? 0.6 : 1,\r\n }}\r\n data-testid=\"button-skip-reason-issue\"\r\n >\r\n Question has an issue\r\n </button>\r\n <button\r\n onClick={() => setSelectedSkipReason('dont_know')}\r\n disabled={isSkipping}\r\n style={{\r\n padding: '12px 16px',\r\n borderRadius: '8px',\r\n border: selectedSkipReason === 'dont_know' ? '2px solid #8b5cf6' : '1px solid #e5e7eb',\r\n backgroundColor: selectedSkipReason === 'dont_know' ? '#f5f3ff' : '#f9fafb',\r\n cursor: isSkipping ? 'not-allowed' : 'pointer',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n color: '#374151',\r\n textAlign: 'left',\r\n opacity: isSkipping ? 0.6 : 1,\r\n }}\r\n data-testid=\"button-skip-reason-dont-know\"\r\n >\r\n I don't know the answer\r\n </button>\r\n </div>\r\n\r\n {/* Optional comment */}\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', fontSize: '13px', fontWeight: '500', color: '#374151', marginBottom: '6px' }}>\r\n Additional details (optional)\r\n </label>\r\n <textarea\r\n value={skipComment}\r\n onChange={(e) => setSkipComment(e.target.value.slice(0, 200))}\r\n placeholder=\"Tell us more about the issue...\"\r\n disabled={isSkipping}\r\n style={{\r\n width: '100%',\r\n minHeight: '80px',\r\n padding: '10px 12px',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n fontSize: '14px',\r\n resize: 'vertical',\r\n fontFamily: 'inherit',\r\n boxSizing: 'border-box',\r\n }}\r\n data-testid=\"input-skip-comment\"\r\n />\r\n <div style={{ fontSize: '12px', color: '#9ca3af', marginTop: '4px', textAlign: 'right' }}>\r\n {skipComment.length}/200\r\n </div>\r\n </div>\r\n\r\n {/* Action buttons */}\r\n <div style={{ display: 'flex', gap: '10px' }}>\r\n <button\r\n onClick={() => {\r\n setShowSkipModal(false);\r\n setSkipComment('');\r\n setSelectedSkipReason(null);\r\n }}\r\n style={{\r\n flex: 1,\r\n padding: '10px 16px',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n backgroundColor: '#ffffff',\r\n cursor: 'pointer',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n color: '#6b7280',\r\n }}\r\n data-testid=\"button-skip-cancel\"\r\n >\r\n Cancel\r\n </button>\r\n <button\r\n onClick={() => selectedSkipReason && handleSkipQuestion(selectedSkipReason, skipComment)}\r\n disabled={isSkipping || !selectedSkipReason}\r\n style={{\r\n flex: 1,\r\n padding: '10px 16px',\r\n borderRadius: '8px',\r\n border: 'none',\r\n backgroundColor: selectedSkipReason ? '#8b5cf6' : '#d1d5db',\r\n cursor: (isSkipping || !selectedSkipReason) ? 'not-allowed' : 'pointer',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n color: '#ffffff',\r\n opacity: isSkipping ? 0.6 : 1,\r\n }}\r\n data-testid=\"button-skip-submit\"\r\n >\r\n {isSkipping ? 'Skipping...' : 'Skip Question'}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Report question modal (for premade questions) */}\r\n {showReportModal && (\r\n <div style={{\r\n position: 'fixed',\r\n top: 0,\r\n left: 0,\r\n right: 0,\r\n bottom: 0,\r\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n zIndex: 1000,\r\n }}>\r\n <div style={{\r\n backgroundColor: '#ffffff',\r\n borderRadius: '12px',\r\n padding: '24px',\r\n maxWidth: '400px',\r\n width: '90%',\r\n boxShadow: '0 20px 40px rgba(0, 0, 0, 0.2)',\r\n }}>\r\n <h3 style={{ margin: '0 0 8px 0', fontSize: '18px', fontWeight: '600', color: '#1f2937' }}>\r\n Report Question\r\n </h3>\r\n <p style={{ margin: '0 0 16px 0', fontSize: '14px', color: '#6b7280' }}>\r\n What's wrong with this question?\r\n </p>\r\n \r\n {/* Comment input */}\r\n <div style={{ marginBottom: '16px' }}>\r\n <textarea\r\n value={reportComment}\r\n onChange={(e) => setReportComment(e.target.value.slice(0, 300))}\r\n placeholder=\"Describe the issue with this question...\"\r\n disabled={isReporting}\r\n style={{\r\n width: '100%',\r\n minHeight: '120px',\r\n padding: '10px 12px',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n fontSize: '14px',\r\n resize: 'vertical',\r\n fontFamily: 'inherit',\r\n boxSizing: 'border-box',\r\n }}\r\n data-testid=\"input-report-comment\"\r\n />\r\n <div style={{ fontSize: '12px', color: '#9ca3af', marginTop: '4px', textAlign: 'right' }}>\r\n {reportComment.length}/300\r\n </div>\r\n </div>\r\n\r\n {/* Action buttons */}\r\n <div style={{ display: 'flex', gap: '10px' }}>\r\n <button\r\n onClick={() => {\r\n setShowReportModal(false);\r\n setReportComment('');\r\n }}\r\n style={{\r\n flex: 1,\r\n padding: '10px 16px',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n backgroundColor: '#ffffff',\r\n cursor: 'pointer',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n color: '#6b7280',\r\n }}\r\n data-testid=\"button-report-cancel\"\r\n >\r\n Cancel\r\n </button>\r\n <button\r\n onClick={() => handleReportQuestion(reportComment)}\r\n disabled={isReporting || !reportComment.trim()}\r\n style={{\r\n flex: 1,\r\n padding: '10px 16px',\r\n borderRadius: '8px',\r\n border: 'none',\r\n backgroundColor: reportComment.trim() ? '#ef4444' : '#d1d5db',\r\n cursor: (isReporting || !reportComment.trim()) ? 'not-allowed' : 'pointer',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n color: '#ffffff',\r\n opacity: isReporting ? 0.6 : 1,\r\n }}\r\n data-testid=\"button-report-submit\"\r\n >\r\n {isReporting ? 'Reporting...' : 'Report'}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {/* Navigation buttons */}\r\n <div style={defaultStyles.buttonsColumn}>\r\n {/* Add More Questions button - shown on last question after feedback, if under 50 questions */}\r\n {showFeedback && isLastQuestion && canAddMore && (\r\n <button\r\n style={{\r\n ...defaultStyles.buttonAddMore,\r\n ...(isGeneratingExtra ? defaultStyles.buttonAddMoreDisabled : {}),\r\n }}\r\n onClick={handleAddMoreQuestions}\r\n disabled={isGeneratingExtra}\r\n data-testid=\"button-add-more-questions\"\r\n >\r\n {isGeneratingExtra ? (\r\n <>\r\n <Spinner size={16} color=\"#9ca3af\" />\r\n Generating Questions...\r\n </>\r\n ) : (\r\n <>+ Add {questionsToAdd} More Question{questionsToAdd !== 1 ? 's' : ''}</>\r\n )}\r\n </button>\r\n )}\r\n\r\n <div style={{ ...defaultStyles.buttons, justifyContent: 'flex-end' }}>\r\n {showFeedback ? (\r\n // After viewing feedback\r\n isLastQuestion ? (\r\n <button\r\n style={{\r\n ...defaultStyles.button,\r\n ...(isSubmitting || isGeneratingExtra ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary),\r\n }}\r\n onClick={handleSubmit}\r\n disabled={isSubmitting || isGeneratingExtra}\r\n data-testid=\"button-submit-quiz\"\r\n >\r\n {isSubmitting ? <Spinner size={16} color=\"#9ca3af\" /> : 'Submit Quiz'}\r\n </button>\r\n ) : (\r\n <button\r\n style={{\r\n ...defaultStyles.button,\r\n ...defaultStyles.buttonPrimary,\r\n }}\r\n onClick={handleContinue}\r\n data-testid=\"button-continue\"\r\n >\r\n Continue\r\n </button>\r\n )\r\n ) : (\r\n // Before checking answer\r\n <button\r\n style={{\r\n ...defaultStyles.button,\r\n ...(isNavigating || selectedAnswer === undefined ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary),\r\n }}\r\n onClick={handleCheckAnswer}\r\n disabled={isNavigating || selectedAnswer === undefined}\r\n data-testid=\"button-check-answer\"\r\n >\r\n {isNavigating ? <Spinner size={16} color=\"#9ca3af\" /> : 'Check Answer'}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n \r\n {/* Chat Panel - always visible on the right */}\r\n <div style={defaultStyles.chatPanel}>\r\n {apiClient.current && (\r\n <QuestionChatPanel\r\n apiClient={apiClient.current}\r\n question={{\r\n id: currentQuestion.id,\r\n question: currentQuestion.question,\r\n type: currentQuestion.type,\r\n options: currentQuestion.options,\r\n correctAnswer: currentQuestion.correctAnswer as string | string[] | undefined,\r\n explanation: currentQuestion.explanation,\r\n } as QuestionContextForChat}\r\n quizId={quiz.id}\r\n childId={childId}\r\n parentId={parentId}\r\n lessonId={lessonId}\r\n courseId={courseId}\r\n answerResult={showFeedback && currentAnswerDetail ? {\r\n wasIncorrect: !currentAnswerDetail.isCorrect,\r\n selectedAnswer: typeof selectedAnswer === 'string' ? selectedAnswer : Array.isArray(selectedAnswer) ? selectedAnswer.join(', ') : undefined,\r\n correctAnswer: typeof currentQuestion.correctAnswer === 'string' ? currentQuestion.correctAnswer : Array.isArray(currentQuestion.correctAnswer) ? currentQuestion.correctAnswer.join(', ') : undefined,\r\n explanation: currentQuestion.explanation,\r\n } : undefined}\r\n />\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import type { Quiz, ExternalQuizAttempt, QuizAnswerDetail, SkipQuestionPayload, ReportQuestionPayload, ChatSession, ChatMessageResponse, QuestionContextForChat, StarterPrompt, ChatMessage } from './types';\r\n\r\nexport interface ApiClientConfig {\r\n baseUrl: string;\r\n authToken?: string;\r\n}\r\n\r\nexport class QuizApiClient {\r\n private baseUrl: string;\r\n private authToken?: string;\r\n\r\n constructor(config: ApiClientConfig) {\r\n this.baseUrl = config.baseUrl.replace(/\\/$/, ''); // Remove trailing slash\r\n this.authToken = config.authToken;\r\n }\r\n\r\n private async request<T>(\r\n method: string,\r\n endpoint: string,\r\n body?: unknown\r\n ): Promise<T> {\r\n const headers: HeadersInit = {\r\n 'Content-Type': 'application/json',\r\n };\r\n\r\n if (this.authToken) {\r\n headers['Authorization'] = `Bearer ${this.authToken}`;\r\n }\r\n\r\n const response = await fetch(`${this.baseUrl}${endpoint}`, {\r\n method,\r\n headers,\r\n body: body ? JSON.stringify(body) : undefined,\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.json().catch(() => ({ error: 'Request failed' }));\r\n throw new Error(error.error || `HTTP ${response.status}`);\r\n }\r\n\r\n return response.json();\r\n }\r\n\r\n async getQuiz(quizId: string): Promise<Quiz> {\r\n return this.request<Quiz>('GET', `/api/external/quizzes/${quizId}`);\r\n }\r\n\r\n async createAttempt(params: {\r\n quizId: string;\r\n lessonId: string;\r\n assignLessonId: string;\r\n courseId: string;\r\n childId: string;\r\n parentId: string;\r\n forceNew?: boolean;\r\n }): Promise<ExternalQuizAttempt> {\r\n return this.request<ExternalQuizAttempt>('POST', '/api/external/quiz-attempts', params);\r\n }\r\n\r\n async updateAttempt(\r\n attemptId: string,\r\n data: {\r\n answers?: QuizAnswerDetail[];\r\n status?: 'in_progress' | 'completed' | 'abandoned';\r\n score?: number;\r\n correctAnswers?: number;\r\n totalQuestions?: number;\r\n timeSpentSeconds?: number;\r\n }\r\n ): Promise<ExternalQuizAttempt> {\r\n return this.request<ExternalQuizAttempt>(\r\n 'PATCH',\r\n `/api/external/quiz-attempts/${attemptId}`,\r\n data\r\n );\r\n }\r\n\r\n async getAttempt(attemptId: string): Promise<ExternalQuizAttempt> {\r\n return this.request<ExternalQuizAttempt>('GET', `/api/external/quiz-attempts/${attemptId}`);\r\n }\r\n\r\n async getAttempts(params: {\r\n assignLessonId?: string;\r\n childId?: string;\r\n quizId?: string;\r\n }): Promise<ExternalQuizAttempt[]> {\r\n const queryParams = new URLSearchParams();\r\n if (params.assignLessonId) queryParams.set('assignLessonId', params.assignLessonId);\r\n if (params.childId) queryParams.set('childId', params.childId);\r\n if (params.quizId) queryParams.set('quizId', params.quizId);\r\n\r\n return this.request<ExternalQuizAttempt[]>(\r\n 'GET',\r\n `/api/external/quiz-attempts?${queryParams.toString()}`\r\n );\r\n }\r\n\r\n async skipQuestion(payload: SkipQuestionPayload): Promise<{ success: boolean; id: string; message: string }> {\r\n return this.request<{ success: boolean; id: string; message: string }>(\r\n 'POST',\r\n '/api/external/skip-question',\r\n payload\r\n );\r\n }\r\n\r\n async reportQuestion(payload: ReportQuestionPayload): Promise<{ success: boolean; id: string; message: string }> {\r\n return this.request<{ success: boolean; id: string; message: string }>(\r\n 'POST',\r\n '/api/external/report-question',\r\n payload\r\n );\r\n }\r\n\r\n async getStarterPrompts(): Promise<StarterPrompt[]> {\r\n return this.request<StarterPrompt[]>('GET', '/api/external/question-chat/prompts');\r\n }\r\n\r\n async getOrCreateChatSession(params: {\r\n questionId: string;\r\n questionContent: QuestionContextForChat;\r\n quizId: string;\r\n childId: string;\r\n parentId: string;\r\n lessonId?: string;\r\n courseId?: string;\r\n }): Promise<ChatSession> {\r\n return this.request<ChatSession>('POST', '/api/external/question-chat/session', params);\r\n }\r\n\r\n async sendChatMessage(params: {\r\n chatId: string;\r\n message: string;\r\n questionContext: QuestionContextForChat;\r\n childId: string;\r\n }): Promise<ChatMessageResponse> {\r\n return this.request<ChatMessageResponse>('POST', '/api/external/question-chat/message', params);\r\n }\r\n\r\n async getChatHistory(questionId: string, childId: string): Promise<{ chatId: string | null; messages: ChatMessage[] }> {\r\n return this.request<{ chatId: string | null; messages: ChatMessage[] }>(\r\n 'GET',\r\n `/api/external/question-chat/${questionId}/${childId}`\r\n );\r\n }\r\n\r\n async getChatsByAttempt(attemptId: string): Promise<Record<string, { chatId: string; messages: ChatMessage[] }>> {\r\n return this.request<Record<string, { chatId: string; messages: ChatMessage[] }>>(\r\n 'GET',\r\n `/api/external/quiz-attempts/${attemptId}/chats`\r\n );\r\n }\r\n\r\n async getTextToSpeech(text: string, voice: string = 'nova'): Promise<Blob> {\r\n const headers: HeadersInit = {\r\n 'Content-Type': 'application/json',\r\n };\r\n\r\n if (this.authToken) {\r\n headers['Authorization'] = `Bearer ${this.authToken}`;\r\n }\r\n\r\n const response = await fetch(`${this.baseUrl}/api/external/tts`, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify({ text, voice }),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`TTS request failed: HTTP ${response.status}`);\r\n }\r\n\r\n return response.blob();\r\n }\r\n}\r\n","import type { QuizQuestion, QuizAnswerDetail, QuestionType } from './types';\r\n\r\n// Check if an answer is correct based on question type\r\nexport function checkAnswer(\r\n question: QuizQuestion,\r\n selectedAnswer: unknown\r\n): { isCorrect: boolean; pointsEarned: number } {\r\n const { type, correctAnswer, points } = question;\r\n\r\n switch (type) {\r\n case 'single':\r\n case 'true-false': {\r\n const isCorrect = selectedAnswer === correctAnswer;\r\n return { isCorrect, pointsEarned: isCorrect ? points : 0 };\r\n }\r\n\r\n case 'multiple': {\r\n if (!Array.isArray(selectedAnswer) || !Array.isArray(correctAnswer)) {\r\n return { isCorrect: false, pointsEarned: 0 };\r\n }\r\n const sortedSelected = [...selectedAnswer].sort();\r\n const sortedCorrect = [...correctAnswer].sort();\r\n const isCorrect =\r\n sortedSelected.length === sortedCorrect.length &&\r\n sortedSelected.every((val, idx) => val === sortedCorrect[idx]);\r\n return { isCorrect, pointsEarned: isCorrect ? points : 0 };\r\n }\r\n\r\n case 'fill': {\r\n if (!Array.isArray(selectedAnswer) || !question.blanks) {\r\n return { isCorrect: false, pointsEarned: 0 };\r\n }\r\n const isCorrect = question.blanks.every((blank, idx) =>\r\n selectedAnswer[idx]?.toLowerCase().trim() === blank.toLowerCase().trim()\r\n );\r\n return { isCorrect, pointsEarned: isCorrect ? points : 0 };\r\n }\r\n\r\n case 'sorting': {\r\n if (!Array.isArray(selectedAnswer) || !question.correctOrder) {\r\n return { isCorrect: false, pointsEarned: 0 };\r\n }\r\n const isCorrect =\r\n selectedAnswer.length === question.correctOrder.length &&\r\n selectedAnswer.every((val, idx) => val === question.correctOrder![idx]);\r\n return { isCorrect, pointsEarned: isCorrect ? points : 0 };\r\n }\r\n\r\n case 'matrix': {\r\n if (typeof selectedAnswer !== 'object' || !question.correctMatches) {\r\n return { isCorrect: false, pointsEarned: 0 };\r\n }\r\n const selected = selectedAnswer as Record<string, string>;\r\n const correct = question.correctMatches;\r\n const isCorrect = Object.keys(correct).every(\r\n key => selected[key] === correct[key]\r\n );\r\n return { isCorrect, pointsEarned: isCorrect ? points : 0 };\r\n }\r\n\r\n case 'free': {\r\n // For free-form answers, do a simple case-insensitive comparison\r\n if (typeof selectedAnswer !== 'string' || typeof correctAnswer !== 'string') {\r\n return { isCorrect: false, pointsEarned: 0 };\r\n }\r\n const isCorrect = selectedAnswer.toLowerCase().trim() === correctAnswer.toLowerCase().trim();\r\n return { isCorrect, pointsEarned: isCorrect ? points : 0 };\r\n }\r\n\r\n case 'essay':\r\n case 'assessment':\r\n // These require manual grading or are opinion-based\r\n return { isCorrect: false, pointsEarned: 0 };\r\n\r\n default:\r\n return { isCorrect: false, pointsEarned: 0 };\r\n }\r\n}\r\n\r\n// Create an answer detail object\r\nexport function createAnswerDetail(\r\n question: QuizQuestion,\r\n selectedAnswer: unknown\r\n): QuizAnswerDetail {\r\n const { isCorrect, pointsEarned } = checkAnswer(question, selectedAnswer);\r\n\r\n return {\r\n questionId: question.id,\r\n questionText: question.question,\r\n questionType: question.type,\r\n points: question.points,\r\n pointsEarned,\r\n selectedAnswer: selectedAnswer as QuizAnswerDetail['selectedAnswer'],\r\n correctAnswer: question.correctAnswer as QuizAnswerDetail['correctAnswer'],\r\n isCorrect,\r\n explanation: question.explanation,\r\n hint: question.hint,\r\n };\r\n}\r\n\r\n// Calculate total score percentage\r\nexport function calculateScore(answers: QuizAnswerDetail[]): {\r\n score: number;\r\n correctAnswers: number;\r\n totalPoints: number;\r\n earnedPoints: number;\r\n} {\r\n const totalPoints = answers.reduce((sum, a) => sum + a.points, 0);\r\n const earnedPoints = answers.reduce((sum, a) => sum + a.pointsEarned, 0);\r\n const correctAnswers = answers.filter(a => a.isCorrect).length;\r\n const score = totalPoints > 0 ? Math.round((earnedPoints / totalPoints) * 100) : 0;\r\n\r\n return { score, correctAnswers, totalPoints, earnedPoints };\r\n}\r\n\r\n// Format time in seconds to mm:ss\r\nexport function formatTime(seconds: number): string {\r\n const mins = Math.floor(seconds / 60);\r\n const secs = seconds % 60;\r\n return `${mins}:${secs.toString().padStart(2, '0')}`;\r\n}\r\n","import { useState, useEffect, useRef } from 'react';\r\n\r\ninterface TextToSpeechProps {\r\n text: string;\r\n inline?: boolean;\r\n size?: 'sm' | 'md';\r\n}\r\n\r\nconst styles = {\r\n container: {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n gap: '8px',\r\n },\r\n button: {\r\n display: 'inline-flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n border: 'none',\r\n borderRadius: '6px',\r\n cursor: 'pointer',\r\n transition: 'all 0.2s ease',\r\n flexShrink: 0,\r\n },\r\n buttonSm: {\r\n width: '28px',\r\n height: '28px',\r\n padding: '4px',\r\n backgroundColor: 'transparent',\r\n },\r\n buttonMd: {\r\n width: '32px',\r\n height: '32px',\r\n padding: '6px',\r\n backgroundColor: 'rgba(103, 33, 176, 0.1)',\r\n },\r\n buttonPlaying: {\r\n backgroundColor: 'rgba(103, 33, 176, 0.2)',\r\n },\r\n buttonDisabled: {\r\n opacity: 0.4,\r\n cursor: 'not-allowed',\r\n },\r\n icon: {\r\n width: '16px',\r\n height: '16px',\r\n color: '#6721b0',\r\n },\r\n textContainer: {\r\n flex: 1,\r\n },\r\n highlightedWord: {\r\n backgroundColor: 'rgba(103, 33, 176, 0.25)',\r\n borderRadius: '3px',\r\n padding: '0 2px',\r\n transition: 'background-color 0.15s ease',\r\n fontWeight: 500,\r\n },\r\n};\r\n\r\n// Volume icon SVG\r\nfunction VolumeIcon() {\r\n return (\r\n <svg\r\n style={styles.icon}\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" />\r\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\" />\r\n <path d=\"M19.07 4.93a10 10 0 0 1 0 14.14\" />\r\n </svg>\r\n );\r\n}\r\n\r\n// Stop icon SVG\r\nfunction StopIcon() {\r\n return (\r\n <svg\r\n style={styles.icon}\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"2\"\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n >\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <rect x=\"9\" y=\"9\" width=\"6\" height=\"6\" />\r\n </svg>\r\n );\r\n}\r\n\r\nexport function TextToSpeech({ text, inline = false, size = 'sm' }: TextToSpeechProps) {\r\n const [isPlaying, setIsPlaying] = useState(false);\r\n const [currentWordIndex, setCurrentWordIndex] = useState(-1);\r\n const [isSupported, setIsSupported] = useState(true);\r\n const [bestVoice, setBestVoice] = useState<SpeechSynthesisVoice | null>(null);\r\n const utteranceRef = useRef<SpeechSynthesisUtterance | null>(null);\r\n const wordsRef = useRef<string[]>([]);\r\n\r\n // Extract words from text\r\n useEffect(() => {\r\n wordsRef.current = text.split(/\\s+/).filter(word => word.length > 0);\r\n }, [text]);\r\n\r\n // Check browser support\r\n useEffect(() => {\r\n if (typeof window === 'undefined' || !('speechSynthesis' in window)) {\r\n setIsSupported(false);\r\n }\r\n }, []);\r\n\r\n // Load and select the best quality voice\r\n useEffect(() => {\r\n if (!isSupported || typeof window === 'undefined') return;\r\n\r\n const loadVoices = () => {\r\n const voices = window.speechSynthesis.getVoices();\r\n if (voices.length === 0) return;\r\n\r\n // Premium voice names (in priority order)\r\n const premiumVoices = [\r\n 'samantha', 'victoria', 'karen', 'serena', 'jenny',\r\n 'aria', 'emma', 'moira', 'fiona', 'alice'\r\n ];\r\n\r\n // Filter to English voices\r\n const englishVoices = voices.filter(voice =>\r\n voice.lang.startsWith('en-')\r\n );\r\n\r\n // Score each voice\r\n const scoredVoices = englishVoices.map(voice => {\r\n let score = 0;\r\n const nameLower = voice.name.toLowerCase();\r\n\r\n // Check for premium voice names\r\n premiumVoices.forEach((premiumName, index) => {\r\n if (nameLower.includes(premiumName)) {\r\n score += (premiumVoices.length - index) * 10;\r\n }\r\n });\r\n\r\n // Prefer local voices (higher quality)\r\n if (voice.localService) score += 8;\r\n\r\n // Prefer female voices (tend to sound warmer)\r\n if (!nameLower.includes('male')) score += 6;\r\n\r\n // Prefer US English\r\n if (voice.lang === 'en-US') score += 3;\r\n\r\n // Penalize obviously robotic voices\r\n if (nameLower.includes('google us english') ||\r\n nameLower.includes('microsoft david')) {\r\n score -= 20;\r\n }\r\n\r\n return { voice, score };\r\n });\r\n\r\n // Sort and pick best\r\n scoredVoices.sort((a, b) => b.score - a.score);\r\n\r\n if (scoredVoices.length > 0) {\r\n setBestVoice(scoredVoices[0].voice);\r\n }\r\n };\r\n\r\n loadVoices();\r\n\r\n if (window.speechSynthesis.onvoiceschanged !== undefined) {\r\n window.speechSynthesis.onvoiceschanged = loadVoices;\r\n }\r\n\r\n return () => {\r\n if (window.speechSynthesis.onvoiceschanged !== undefined) {\r\n window.speechSynthesis.onvoiceschanged = null;\r\n }\r\n };\r\n }, [isSupported]);\r\n\r\n const handlePlay = () => {\r\n if (!isSupported || typeof window === 'undefined') return;\r\n\r\n try {\r\n // If playing, stop it\r\n if (isPlaying) {\r\n window.speechSynthesis.cancel();\r\n setIsPlaying(false);\r\n setCurrentWordIndex(-1);\r\n return;\r\n }\r\n\r\n // Create utterance\r\n const utterance = new SpeechSynthesisUtterance(text);\r\n utteranceRef.current = utterance;\r\n\r\n // Use best voice\r\n if (bestVoice) {\r\n utterance.voice = bestVoice;\r\n }\r\n\r\n // Optimized settings for natural sound\r\n utterance.rate = 1.0;\r\n utterance.pitch = 1.0;\r\n utterance.volume = 1.0;\r\n\r\n // Track word boundaries for highlighting\r\n let wordIndex = 0;\r\n utterance.onboundary = (event) => {\r\n if (event.name === 'word') {\r\n setCurrentWordIndex(wordIndex);\r\n wordIndex++;\r\n }\r\n };\r\n\r\n utterance.onstart = () => {\r\n setIsPlaying(true);\r\n setCurrentWordIndex(0);\r\n };\r\n\r\n utterance.onend = () => {\r\n setIsPlaying(false);\r\n setCurrentWordIndex(-1);\r\n };\r\n\r\n utterance.onerror = (event) => {\r\n console.error('Speech error:', event);\r\n setIsPlaying(false);\r\n setCurrentWordIndex(-1);\r\n };\r\n\r\n window.speechSynthesis.speak(utterance);\r\n } catch (error) {\r\n console.error('TTS error:', error);\r\n setIsPlaying(false);\r\n }\r\n };\r\n\r\n // Cleanup on unmount\r\n useEffect(() => {\r\n return () => {\r\n if (typeof window !== 'undefined' && 'speechSynthesis' in window) {\r\n try {\r\n window.speechSynthesis.cancel();\r\n } catch (error) {\r\n // Ignore cleanup errors\r\n }\r\n }\r\n };\r\n }, []);\r\n\r\n const buttonStyle = {\r\n ...styles.button,\r\n ...(size === 'sm' ? styles.buttonSm : styles.buttonMd),\r\n ...(isPlaying ? styles.buttonPlaying : {}),\r\n ...(!isSupported ? styles.buttonDisabled : {}),\r\n };\r\n\r\n // Inline variant with highlighted text\r\n if (inline) {\r\n const words = text.split(/\\s+/);\r\n\r\n return (\r\n <div style={styles.container}>\r\n <button\r\n style={buttonStyle}\r\n onClick={handlePlay}\r\n disabled={!isSupported}\r\n aria-label={isPlaying ? 'Stop reading' : 'Read aloud'}\r\n title={isPlaying ? 'Stop' : 'Read aloud'}\r\n data-testid=\"button-tts\"\r\n >\r\n {isPlaying ? <StopIcon /> : <VolumeIcon />}\r\n </button>\r\n <span style={styles.textContainer}>\r\n {words.map((word, index) => (\r\n <span\r\n key={index}\r\n style={index === currentWordIndex ? styles.highlightedWord : undefined}\r\n >\r\n {word}{index < words.length - 1 ? ' ' : ''}\r\n </span>\r\n ))}\r\n </span>\r\n </div>\r\n );\r\n }\r\n\r\n // Button-only variant\r\n return (\r\n <button\r\n style={buttonStyle}\r\n onClick={handlePlay}\r\n disabled={!isSupported}\r\n aria-label={isPlaying ? 'Stop reading' : 'Read aloud'}\r\n title={isPlaying ? 'Stop' : 'Read aloud'}\r\n data-testid=\"button-tts\"\r\n >\r\n {isPlaying ? <StopIcon /> : <VolumeIcon />}\r\n </button>\r\n );\r\n}\r\n","import { useState, useEffect, useRef, useCallback } from 'react';\r\nimport type { ChatMessage, StarterPrompt, QuestionContextForChat } from './types';\r\nimport { QuizApiClient } from './api';\r\n\r\ninterface SpeechRecognitionEvent {\r\n results: { [key: number]: { [key: number]: { transcript: string; confidence: number } } };\r\n}\r\n\r\ninterface SpeechRecognitionErrorEvent {\r\n error: string;\r\n message?: string;\r\n}\r\n\r\ninterface SpeechRecognitionInstance {\r\n continuous: boolean;\r\n interimResults: boolean;\r\n lang: string;\r\n onstart: (() => void) | null;\r\n onresult: ((event: SpeechRecognitionEvent) => void) | null;\r\n onerror: ((event: SpeechRecognitionErrorEvent) => void) | null;\r\n onend: (() => void) | null;\r\n start: () => void;\r\n stop: () => void;\r\n}\r\n\r\ninterface SpeechRecognitionConstructor {\r\n new(): SpeechRecognitionInstance;\r\n}\r\n\r\ndeclare global {\r\n interface Window {\r\n SpeechRecognition?: SpeechRecognitionConstructor;\r\n webkitSpeechRecognition?: SpeechRecognitionConstructor;\r\n }\r\n}\r\n\r\ninterface AnswerResult {\r\n wasIncorrect: boolean;\r\n selectedAnswer?: string;\r\n correctAnswer?: string;\r\n explanation?: string;\r\n}\r\n\r\ninterface QuestionChatPanelProps {\r\n apiClient: QuizApiClient;\r\n question: QuestionContextForChat;\r\n quizId: string;\r\n childId: string;\r\n parentId: string;\r\n lessonId?: string;\r\n courseId?: string;\r\n answerResult?: AnswerResult;\r\n}\r\n\r\nconst panelStyles = {\r\n container: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n height: '100%',\r\n backgroundColor: '#f8fafc',\r\n borderRadius: '12px',\r\n border: '1px solid #e2e8f0',\r\n overflow: 'hidden',\r\n },\r\n header: {\r\n padding: '12px 16px',\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n fontWeight: '600',\r\n fontSize: '14px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n },\r\n messagesContainer: {\r\n flex: 1,\r\n overflowY: 'auto' as const,\r\n padding: '12px',\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '8px',\r\n },\r\n starterPrompts: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '8px',\r\n padding: '16px',\r\n },\r\n starterButton: {\r\n padding: '10px 14px',\r\n borderRadius: '20px',\r\n border: '1px solid #e2e8f0',\r\n backgroundColor: '#ffffff',\r\n color: '#374151',\r\n fontSize: '13px',\r\n cursor: 'pointer',\r\n textAlign: 'left' as const,\r\n transition: 'all 0.2s ease',\r\n },\r\n starterButtonHover: {\r\n backgroundColor: '#f3e8ff',\r\n borderColor: '#6721b0',\r\n },\r\n messageRow: {\r\n display: 'flex',\r\n },\r\n messageContent: {\r\n display: 'flex',\r\n alignItems: 'flex-end',\r\n gap: '4px',\r\n maxWidth: '85%',\r\n },\r\n userMessage: {\r\n padding: '10px 14px',\r\n borderRadius: '16px 16px 4px 16px',\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n fontSize: '14px',\r\n lineHeight: 1.4,\r\n },\r\n assistantMessage: {\r\n padding: '10px 14px',\r\n borderRadius: '16px 16px 16px 4px',\r\n backgroundColor: '#ffffff',\r\n color: '#1f2937',\r\n fontSize: '14px',\r\n lineHeight: 1.4,\r\n border: '1px solid #e2e8f0',\r\n },\r\n inputContainer: {\r\n padding: '12px',\r\n borderTop: '1px solid #e2e8f0',\r\n backgroundColor: '#ffffff',\r\n display: 'flex',\r\n gap: '8px',\r\n alignItems: 'center',\r\n },\r\n input: {\r\n flex: 1,\r\n padding: '10px 14px',\r\n borderRadius: '20px',\r\n border: '1px solid #e2e8f0',\r\n fontSize: '14px',\r\n outline: 'none',\r\n },\r\n buttonBase: {\r\n width: '40px',\r\n height: '40px',\r\n borderRadius: '50%',\r\n border: 'none',\r\n cursor: 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n fontSize: '16px',\r\n transition: 'all 0.2s ease',\r\n },\r\n sendButton: {\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n },\r\n sendButtonDisabled: {\r\n backgroundColor: '#d1d5db',\r\n cursor: 'not-allowed',\r\n },\r\n micButton: {\r\n backgroundColor: '#ffffff',\r\n border: '1px solid #e2e8f0',\r\n color: '#374151',\r\n },\r\n micButtonActive: {\r\n backgroundColor: '#ef4444',\r\n color: '#ffffff',\r\n border: 'none',\r\n },\r\n speakButton: {\r\n width: '28px',\r\n height: '28px',\r\n borderRadius: '50%',\r\n border: 'none',\r\n backgroundColor: 'transparent',\r\n color: '#9ca3af',\r\n cursor: 'pointer',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n transition: 'all 0.2s ease',\r\n flexShrink: 0,\r\n },\r\n speakButtonReady: {\r\n color: '#22c55e',\r\n },\r\n speakButtonPlaying: {\r\n color: '#6721b0',\r\n },\r\n speakButtonLoading: {\r\n color: '#f97316',\r\n },\r\n loadingDots: {\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '4px',\r\n padding: '10px 14px',\r\n maxWidth: '85%',\r\n marginRight: 'auto',\r\n },\r\n dot: {\r\n width: '8px',\r\n height: '8px',\r\n backgroundColor: '#9ca3af',\r\n borderRadius: '50%',\r\n animation: 'bounce 1.4s ease-in-out infinite',\r\n },\r\n emptyState: {\r\n flex: 1,\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n padding: '20px',\r\n color: '#6b7280',\r\n textAlign: 'center' as const,\r\n },\r\n helperIcon: {\r\n width: '48px',\r\n height: '48px',\r\n marginBottom: '12px',\r\n fontSize: '32px',\r\n },\r\n};\r\n\r\nconst STARTER_PROMPTS: StarterPrompt[] = [\r\n { id: 'dont_understand', label: \"I don't understand this question\", message: \"I don't understand this question. Can you help me?\" },\r\n { id: 'word_help', label: \"I don't understand a word\", message: \"I don't understand a word in this question. Can you help?\" },\r\n { id: 'explain_again', label: \"Explain this again\", message: \"Can you explain this question to me again in a different way?\" }\r\n];\r\n\r\nconst MicIcon = () => (\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\"/>\r\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\r\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\"/>\r\n </svg>\r\n);\r\n\r\nconst MicOffIcon = () => (\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <line x1=\"2\" x2=\"22\" y1=\"2\" y2=\"22\"/>\r\n <path d=\"M18.89 13.23A7.12 7.12 0 0 0 19 12v-2\"/>\r\n <path d=\"M5 10v2a7 7 0 0 0 12 5\"/>\r\n <path d=\"M15 9.34V5a3 3 0 0 0-5.68-1.33\"/>\r\n <path d=\"M9 9v3a3 3 0 0 0 5.12 2.12\"/>\r\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\"/>\r\n </svg>\r\n);\r\n\r\nconst VolumeIcon = () => (\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\r\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\r\n <path d=\"M19.07 4.93a10 10 0 0 1 0 14.14\"/>\r\n </svg>\r\n);\r\n\r\nconst SendIcon = () => (\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\r\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" />\r\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\" />\r\n </svg>\r\n);\r\n\r\nconst HelpIcon = () => (\r\n <svg width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#6721b0\" strokeWidth=\"2\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <path d=\"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\" />\r\n <line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\" />\r\n </svg>\r\n);\r\n\r\nexport function QuestionChatPanel({\r\n apiClient,\r\n question,\r\n quizId,\r\n childId,\r\n parentId,\r\n lessonId,\r\n courseId,\r\n answerResult,\r\n}: QuestionChatPanelProps) {\r\n const [messages, setMessages] = useState<ChatMessage[]>([]);\r\n const [inputValue, setInputValue] = useState('');\r\n const [isLoading, setIsLoading] = useState(false);\r\n const [chatId, setChatId] = useState<string | null>(null);\r\n const [hoveredButton, setHoveredButton] = useState<string | null>(null);\r\n const [isListening, setIsListening] = useState(false);\r\n const [speakingIndex, setSpeakingIndex] = useState<number | null>(null);\r\n const [audioReadyMap, setAudioReadyMap] = useState<Map<string, boolean>>(new Map());\r\n const [hasOfferedHelp, setHasOfferedHelp] = useState(false);\r\n \r\n const messagesContainerRef = useRef<HTMLDivElement>(null);\r\n const messagesEndRef = useRef<HTMLDivElement>(null);\r\n const recognitionRef = useRef<SpeechRecognitionInstance | null>(null);\r\n const audioRef = useRef<HTMLAudioElement | null>(null);\r\n const audioCacheRef = useRef<Map<string, Blob>>(new Map());\r\n\r\n const isSpeechSupported = typeof window !== 'undefined' && \r\n (window.SpeechRecognition || window.webkitSpeechRecognition);\r\n\r\n const scrollToBottom = useCallback(() => {\r\n if (messagesContainerRef.current) {\r\n messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight;\r\n }\r\n }, []);\r\n\r\n const preCacheAudio = useCallback(async (text: string) => {\r\n if (audioCacheRef.current.has(text)) {\r\n setAudioReadyMap(prev => new Map(prev).set(text, true));\r\n return;\r\n }\r\n \r\n setAudioReadyMap(prev => new Map(prev).set(text, false));\r\n \r\n try {\r\n const audioBlob = await apiClient.getTextToSpeech(text, 'nova');\r\n audioCacheRef.current.set(text, audioBlob);\r\n setAudioReadyMap(prev => new Map(prev).set(text, true));\r\n } catch (error) {\r\n console.error('Pre-cache TTS error:', error);\r\n }\r\n }, [apiClient]);\r\n\r\n const startListening = useCallback(() => {\r\n const SpeechRecognitionAPI = window.SpeechRecognition || window.webkitSpeechRecognition;\r\n if (!SpeechRecognitionAPI) {\r\n console.log('Speech recognition not supported');\r\n return;\r\n }\r\n \r\n const recognition = new SpeechRecognitionAPI();\r\n \r\n recognition.continuous = true;\r\n recognition.interimResults = true;\r\n recognition.lang = 'en-US';\r\n \r\n recognition.onstart = () => {\r\n console.log('Speech recognition started');\r\n setIsListening(true);\r\n };\r\n \r\n recognition.onresult = (event) => {\r\n let finalTranscript = '';\r\n for (let i = 0; i < Object.keys(event.results).length; i++) {\r\n const result = event.results[i];\r\n if (result && result[0]) {\r\n finalTranscript += result[0].transcript;\r\n }\r\n }\r\n if (finalTranscript) {\r\n setInputValue(finalTranscript);\r\n }\r\n };\r\n \r\n recognition.onerror = (event) => {\r\n console.log('Speech recognition error:', event.error);\r\n if (event.error === 'not-allowed') {\r\n alert('Microphone access was denied. Please allow microphone access and try again.');\r\n }\r\n setIsListening(false);\r\n };\r\n \r\n recognition.onend = () => {\r\n console.log('Speech recognition ended');\r\n setIsListening(false);\r\n };\r\n \r\n recognitionRef.current = recognition;\r\n try {\r\n recognition.start();\r\n } catch (e) {\r\n console.log('Failed to start recognition:', e);\r\n setIsListening(false);\r\n }\r\n }, []);\r\n\r\n const stopListening = useCallback(() => {\r\n if (recognitionRef.current) {\r\n recognitionRef.current.stop();\r\n setIsListening(false);\r\n }\r\n }, []);\r\n\r\n const speakMessage = useCallback(async (text: string, index: number) => {\r\n if (audioRef.current) {\r\n audioRef.current.pause();\r\n audioRef.current = null;\r\n }\r\n \r\n if (speakingIndex === index) {\r\n setSpeakingIndex(null);\r\n return;\r\n }\r\n \r\n setSpeakingIndex(index);\r\n \r\n try {\r\n let audioBlob: Blob;\r\n \r\n const cachedBlob = audioCacheRef.current.get(text);\r\n if (cachedBlob) {\r\n audioBlob = cachedBlob;\r\n } else {\r\n audioBlob = await apiClient.getTextToSpeech(text, 'nova');\r\n audioCacheRef.current.set(text, audioBlob);\r\n }\r\n \r\n const audioUrl = URL.createObjectURL(audioBlob);\r\n const audio = new Audio(audioUrl);\r\n audioRef.current = audio;\r\n \r\n audio.onended = () => {\r\n setSpeakingIndex(null);\r\n URL.revokeObjectURL(audioUrl);\r\n };\r\n audio.onerror = () => {\r\n setSpeakingIndex(null);\r\n URL.revokeObjectURL(audioUrl);\r\n };\r\n \r\n await audio.play();\r\n } catch (error) {\r\n console.error('TTS error:', error);\r\n setSpeakingIndex(null);\r\n }\r\n }, [speakingIndex, apiClient]);\r\n\r\n useEffect(() => {\r\n scrollToBottom();\r\n }, [messages, scrollToBottom]);\r\n\r\n useEffect(() => {\r\n setMessages([]);\r\n setChatId(null);\r\n setInputValue('');\r\n setHasOfferedHelp(false);\r\n \r\n const loadHistory = async () => {\r\n try {\r\n const history = await apiClient.getChatHistory(question.id, childId);\r\n if (history.chatId && history.messages.length > 0) {\r\n setChatId(history.chatId);\r\n setMessages(history.messages);\r\n history.messages\r\n .filter(m => m.role === 'assistant')\r\n .forEach(m => preCacheAudio(m.content));\r\n }\r\n } catch (err) {\r\n console.error('Failed to load chat history:', err);\r\n }\r\n };\r\n \r\n loadHistory();\r\n }, [question.id, childId, apiClient, preCacheAudio]);\r\n\r\n // Auto-offer help when student answers incorrectly\r\n useEffect(() => {\r\n if (answerResult?.wasIncorrect && !hasOfferedHelp) {\r\n setHasOfferedHelp(true);\r\n \r\n const selectedAnswerText = answerResult.selectedAnswer || \"that answer\";\r\n const helpMessage = `Looks like you chose \"${selectedAnswerText}\" which was incorrect. Would you like me to help explain the correct answer?`;\r\n \r\n const assistantMessage: ChatMessage = {\r\n role: 'assistant',\r\n content: helpMessage,\r\n timestamp: new Date().toISOString(),\r\n };\r\n setMessages(prev => [...prev, assistantMessage]);\r\n preCacheAudio(helpMessage);\r\n }\r\n }, [answerResult, hasOfferedHelp, preCacheAudio]);\r\n\r\n const initializeChat = async () => {\r\n if (chatId) return chatId;\r\n \r\n try {\r\n const session = await apiClient.getOrCreateChatSession({\r\n questionId: question.id,\r\n questionContent: question,\r\n quizId,\r\n childId,\r\n parentId,\r\n lessonId,\r\n courseId,\r\n });\r\n setChatId(session.chatId);\r\n return session.chatId;\r\n } catch (err) {\r\n console.error('Failed to create chat session:', err);\r\n return null;\r\n }\r\n };\r\n\r\n const sendMessage = async (messageText: string) => {\r\n if (!messageText.trim() || isLoading) return;\r\n \r\n if (isListening) {\r\n stopListening();\r\n }\r\n \r\n setIsLoading(true);\r\n \r\n const userMsg: ChatMessage = {\r\n role: 'user',\r\n content: messageText,\r\n timestamp: new Date().toISOString(),\r\n };\r\n setMessages(prev => [...prev, userMsg]);\r\n setInputValue('');\r\n \r\n try {\r\n const currentChatId = await initializeChat();\r\n if (!currentChatId) {\r\n throw new Error('Failed to initialize chat');\r\n }\r\n \r\n const response = await apiClient.sendChatMessage({\r\n chatId: currentChatId,\r\n message: messageText,\r\n questionContext: question,\r\n childId,\r\n });\r\n \r\n const assistantMessage: ChatMessage = response.assistantMessage || {\r\n role: 'assistant',\r\n content: \"I'm here to help!\",\r\n timestamp: new Date().toISOString(),\r\n };\r\n setMessages(prev => [...prev, assistantMessage]);\r\n preCacheAudio(assistantMessage.content);\r\n } catch (err) {\r\n console.error('Failed to send message:', err);\r\n const content = \"Sorry, I'm having trouble right now. Please try again!\";\r\n const errorMsg: ChatMessage = {\r\n role: 'assistant',\r\n content,\r\n timestamp: new Date().toISOString(),\r\n };\r\n setMessages(prev => [...prev, errorMsg]);\r\n preCacheAudio(content);\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n };\r\n\r\n const handleKeyPress = (e: React.KeyboardEvent) => {\r\n if (e.key === 'Enter' && !e.shiftKey) {\r\n e.preventDefault();\r\n sendMessage(inputValue);\r\n }\r\n };\r\n\r\n return (\r\n <div style={panelStyles.container}>\r\n <style>\r\n {`\r\n @keyframes bounce {\r\n 0%, 60%, 100% { transform: translateY(0); }\r\n 30% { transform: translateY(-4px); }\r\n }\r\n @keyframes pulse {\r\n 0%, 100% { opacity: 1; }\r\n 50% { opacity: 0.5; }\r\n }\r\n `}\r\n </style>\r\n \r\n <div style={panelStyles.header}>\r\n <span>Need Help?</span>\r\n </div>\r\n \r\n <div ref={messagesContainerRef} style={panelStyles.messagesContainer}>\r\n {messages.length === 0 ? (\r\n <div style={panelStyles.emptyState}>\r\n <div style={panelStyles.helperIcon}>\r\n <HelpIcon />\r\n </div>\r\n <div style={{ fontSize: '14px', fontWeight: '500', marginBottom: '8px' }}>\r\n Hi! I'm your question helper\r\n </div>\r\n <div style={{ fontSize: '13px', color: '#9ca3af' }}>\r\n Ask me if you need help understanding this question\r\n </div>\r\n \r\n <div style={{ ...panelStyles.starterPrompts, marginTop: '16px' }}>\r\n {STARTER_PROMPTS.map(prompt => (\r\n <button\r\n key={prompt.id}\r\n style={{\r\n ...panelStyles.starterButton,\r\n ...(hoveredButton === prompt.id ? panelStyles.starterButtonHover : {}),\r\n }}\r\n onMouseEnter={() => setHoveredButton(prompt.id)}\r\n onMouseLeave={() => setHoveredButton(null)}\r\n onClick={() => sendMessage(prompt.message)}\r\n disabled={isLoading}\r\n data-testid={`button-chat-starter-${prompt.id}`}\r\n >\r\n {prompt.label}\r\n </button>\r\n ))}\r\n </div>\r\n </div>\r\n ) : (\r\n <>\r\n {messages.map((msg, idx) => (\r\n <div \r\n key={idx} \r\n style={{\r\n ...panelStyles.messageRow,\r\n justifyContent: msg.role === 'user' ? 'flex-end' : 'flex-start',\r\n }}\r\n >\r\n <div style={{\r\n ...panelStyles.messageContent,\r\n flexDirection: msg.role === 'user' ? 'row-reverse' : 'row',\r\n }}>\r\n <div style={msg.role === 'user' ? panelStyles.userMessage : panelStyles.assistantMessage}>\r\n {msg.content}\r\n </div>\r\n {msg.role === 'assistant' && (\r\n <button\r\n style={{\r\n ...panelStyles.speakButton,\r\n ...(speakingIndex === idx \r\n ? panelStyles.speakButtonPlaying \r\n : audioReadyMap.get(msg.content) === true\r\n ? panelStyles.speakButtonReady\r\n : audioReadyMap.get(msg.content) === false\r\n ? panelStyles.speakButtonLoading\r\n : {}),\r\n ...(audioReadyMap.get(msg.content) === false ? { animation: 'pulse 1.5s ease-in-out infinite' } : {}),\r\n }}\r\n onClick={() => speakMessage(msg.content, idx)}\r\n data-testid={`button-speak-${idx}`}\r\n title=\"Listen to this message\"\r\n >\r\n <VolumeIcon />\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n ))}\r\n {isLoading && (\r\n <div style={panelStyles.loadingDots}>\r\n <div style={{ ...panelStyles.dot, animationDelay: '0s' }} />\r\n <div style={{ ...panelStyles.dot, animationDelay: '0.2s' }} />\r\n <div style={{ ...panelStyles.dot, animationDelay: '0.4s' }} />\r\n </div>\r\n )}\r\n <div ref={messagesEndRef} />\r\n </>\r\n )}\r\n </div>\r\n \r\n <div style={panelStyles.inputContainer}>\r\n <input\r\n type=\"text\"\r\n value={inputValue}\r\n onChange={(e) => setInputValue(e.target.value)}\r\n onKeyPress={handleKeyPress}\r\n placeholder={isListening ? \"Listening...\" : \"Ask about this question...\"}\r\n style={panelStyles.input}\r\n disabled={isLoading || isListening}\r\n data-testid=\"input-chat-message\"\r\n />\r\n {isSpeechSupported && (\r\n <button\r\n onClick={isListening ? stopListening : startListening}\r\n disabled={isLoading}\r\n style={{\r\n ...panelStyles.buttonBase,\r\n ...(isListening ? panelStyles.micButtonActive : panelStyles.micButton),\r\n }}\r\n data-testid=\"button-voice-input\"\r\n title={isListening ? \"Stop listening\" : \"Speak your question\"}\r\n >\r\n {isListening ? <MicOffIcon /> : <MicIcon />}\r\n </button>\r\n )}\r\n <button\r\n onClick={() => sendMessage(inputValue)}\r\n disabled={isLoading || !inputValue.trim()}\r\n style={{\r\n ...panelStyles.buttonBase,\r\n ...panelStyles.sendButton,\r\n ...(isLoading || !inputValue.trim() ? panelStyles.sendButtonDisabled : {}),\r\n }}\r\n data-testid=\"button-send-chat\"\r\n >\r\n <SendIcon />\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect } from 'react';\r\nimport type {\r\n AttemptViewerProps,\r\n ExternalQuizAttempt,\r\n QuizAnswerDetail,\r\n} from './types';\r\nimport { QuizApiClient } from './api';\r\nimport { formatTime } from './utils';\r\n\r\nconst defaultStyles = {\r\n container: {\r\n fontFamily: 'system-ui, -apple-system, sans-serif',\r\n width: '100%',\r\n padding: '20px',\r\n backgroundColor: '#ffffff',\r\n borderRadius: '12px',\r\n boxSizing: 'border-box' as const,\r\n },\r\n header: {\r\n marginBottom: '24px',\r\n borderBottom: '1px solid #e5e7eb',\r\n paddingBottom: '20px',\r\n },\r\n title: {\r\n fontSize: '24px',\r\n fontWeight: '600',\r\n marginBottom: '16px',\r\n color: '#111827',\r\n },\r\n summaryGrid: {\r\n display: 'grid',\r\n gridTemplateColumns: 'repeat(auto-fit, minmax(120px, 1fr))',\r\n gap: '16px',\r\n },\r\n summaryCard: {\r\n padding: '12px',\r\n backgroundColor: '#f9fafb',\r\n borderRadius: '8px',\r\n textAlign: 'center' as const,\r\n },\r\n summaryValue: {\r\n fontSize: '20px',\r\n fontWeight: '600',\r\n color: '#6721b0',\r\n marginBottom: '2px',\r\n },\r\n summaryLabel: {\r\n fontSize: '10px',\r\n color: '#6b7280',\r\n textTransform: 'uppercase' as const,\r\n letterSpacing: '0.05em',\r\n },\r\n questionsList: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '16px',\r\n },\r\n questionCard: {\r\n padding: '16px',\r\n border: '2px solid #e5e7eb',\r\n borderRadius: '8px',\r\n },\r\n questionCardCorrect: {\r\n borderColor: '#22c55e',\r\n backgroundColor: '#f0fdf4',\r\n },\r\n questionCardIncorrect: {\r\n borderColor: '#ef4444',\r\n backgroundColor: '#fef2f2',\r\n },\r\n questionHeader: {\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n alignItems: 'flex-start',\r\n marginBottom: '12px',\r\n },\r\n questionNumber: {\r\n fontSize: '12px',\r\n color: '#6b7280',\r\n fontWeight: '500',\r\n },\r\n questionBadge: {\r\n padding: '4px 8px',\r\n borderRadius: '4px',\r\n fontSize: '12px',\r\n fontWeight: '600',\r\n },\r\n badgeCorrect: {\r\n backgroundColor: '#dcfce7',\r\n color: '#166534',\r\n },\r\n badgeIncorrect: {\r\n backgroundColor: '#fee2e2',\r\n color: '#991b1b',\r\n },\r\n questionText: {\r\n fontSize: '16px',\r\n fontWeight: '500',\r\n marginBottom: '12px',\r\n color: '#111827',\r\n },\r\n answerSection: {\r\n fontSize: '14px',\r\n marginBottom: '8px',\r\n },\r\n answerLabel: {\r\n fontWeight: '600',\r\n color: '#6b7280',\r\n marginRight: '8px',\r\n },\r\n studentAnswer: {\r\n color: '#111827',\r\n },\r\n correctAnswer: {\r\n color: '#166534',\r\n },\r\n points: {\r\n fontSize: '13px',\r\n color: '#6b7280',\r\n marginTop: '8px',\r\n },\r\n explanation: {\r\n marginTop: '12px',\r\n padding: '12px',\r\n backgroundColor: '#f3e8ff',\r\n borderRadius: '6px',\r\n fontSize: '14px',\r\n color: '#581c87',\r\n },\r\n chatHistorySection: {\r\n marginTop: '12px',\r\n borderTop: '1px solid #e5e7eb',\r\n paddingTop: '12px',\r\n },\r\n chatToggleButton: {\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '6px',\r\n padding: '6px 12px',\r\n backgroundColor: '#f3f4f6',\r\n border: 'none',\r\n borderRadius: '6px',\r\n fontSize: '13px',\r\n color: '#6b7280',\r\n cursor: 'pointer',\r\n fontWeight: '500',\r\n },\r\n chatMessages: {\r\n marginTop: '12px',\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '8px',\r\n },\r\n chatMessage: {\r\n padding: '8px 12px',\r\n borderRadius: '8px',\r\n fontSize: '13px',\r\n maxWidth: '85%',\r\n },\r\n chatMessageUser: {\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n alignSelf: 'flex-end' as const,\r\n },\r\n chatMessageAssistant: {\r\n backgroundColor: '#f3f4f6',\r\n color: '#111827',\r\n alignSelf: 'flex-start' as const,\r\n },\r\n loading: {\r\n textAlign: 'center' as const,\r\n padding: '40px 20px',\r\n },\r\n spinner: {\r\n display: 'inline-block',\r\n width: '32px',\r\n height: '32px',\r\n border: '3px solid #e5e7eb',\r\n borderTopColor: '#6721b0',\r\n borderRadius: '50%',\r\n animation: 'spin 1s linear infinite',\r\n },\r\n error: {\r\n textAlign: 'center' as const,\r\n padding: '40px 20px',\r\n color: '#ef4444',\r\n },\r\n retryButton: {\r\n marginTop: '16px',\r\n padding: '12px 24px',\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n border: 'none',\r\n borderRadius: '8px',\r\n fontSize: '16px',\r\n fontWeight: '500',\r\n cursor: 'pointer',\r\n },\r\n};\r\n\r\nconst spinnerKeyframes = `\r\n @keyframes spin {\r\n to { transform: rotate(360deg); }\r\n }\r\n`;\r\n\r\nfunction formatAnswer(answer: unknown): string {\r\n if (answer === null || answer === undefined) {\r\n return 'No answer';\r\n }\r\n if (typeof answer === 'string') {\r\n return answer;\r\n }\r\n if (Array.isArray(answer)) {\r\n return answer.join(', ');\r\n }\r\n if (typeof answer === 'object') {\r\n return Object.entries(answer as Record<string, string>)\r\n .map(([k, v]) => `${k} → ${v}`)\r\n .join(', ');\r\n }\r\n return String(answer);\r\n}\r\n\r\ninterface ChatMessage {\r\n role: 'user' | 'assistant';\r\n content: string;\r\n timestamp?: string;\r\n}\r\n\r\nexport function AttemptViewer({\r\n attemptId,\r\n apiBaseUrl,\r\n authToken,\r\n onError,\r\n className,\r\n showExplanations = true,\r\n showConversation = false,\r\n title,\r\n}: AttemptViewerProps) {\r\n const [attempt, setAttempt] = useState<ExternalQuizAttempt | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n const [error, setError] = useState<string | null>(null);\r\n const [chatHistories, setChatHistories] = useState<Record<string, { chatId: string; messages: ChatMessage[] }>>({});\r\n const [expandedChats, setExpandedChats] = useState<Set<string>>(new Set());\r\n\r\n useEffect(() => {\r\n const apiClient = new QuizApiClient({\r\n baseUrl: apiBaseUrl,\r\n authToken,\r\n });\r\n\r\n async function fetchAttempt() {\r\n setLoading(true);\r\n setError(null);\r\n try {\r\n const response = await fetch(`${apiBaseUrl}/api/external/quiz-attempts/${attemptId}`, {\r\n headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},\r\n });\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch attempt: ${response.statusText}`);\r\n }\r\n const data = await response.json();\r\n setAttempt(data);\r\n\r\n // Fetch chat histories if showConversation is enabled\r\n if (showConversation) {\r\n try {\r\n const chats = await apiClient.getChatsByAttempt(attemptId);\r\n setChatHistories(chats);\r\n } catch (chatErr) {\r\n console.error('Failed to load chat histories:', chatErr);\r\n }\r\n }\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : 'Failed to load attempt';\r\n setError(errorMessage);\r\n onError?.(err instanceof Error ? err : new Error(errorMessage));\r\n } finally {\r\n setLoading(false);\r\n }\r\n }\r\n\r\n fetchAttempt();\r\n }, [attemptId, apiBaseUrl, authToken, onError, showConversation]);\r\n\r\n const toggleChatExpanded = (questionId: string) => {\r\n setExpandedChats(prev => {\r\n const newSet = new Set(prev);\r\n if (newSet.has(questionId)) {\r\n newSet.delete(questionId);\r\n } else {\r\n newSet.add(questionId);\r\n }\r\n return newSet;\r\n });\r\n };\r\n\r\n const handleRetry = () => {\r\n setLoading(true);\r\n setError(null);\r\n window.location.reload();\r\n };\r\n\r\n if (loading) {\r\n return (\r\n <div style={defaultStyles.container} className={className}>\r\n <style>{spinnerKeyframes}</style>\r\n <div style={defaultStyles.loading}>\r\n <div style={defaultStyles.spinner} />\r\n <p style={{ marginTop: '16px', color: '#6b7280' }}>Loading attempt...</p>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n if (error || !attempt) {\r\n return (\r\n <div style={defaultStyles.container} className={className}>\r\n <div style={defaultStyles.error}>\r\n <p style={{ fontSize: '18px', fontWeight: '500' }}>Failed to load attempt</p>\r\n <p style={{ marginTop: '8px', color: '#6b7280' }}>{error}</p>\r\n <button style={defaultStyles.retryButton} onClick={handleRetry}>\r\n Try Again\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n const scorePercentage = attempt.score ?? 0;\r\n const correctCount = attempt.correctAnswers ?? 0;\r\n const totalQuestions = attempt.totalQuestions;\r\n const timeSpent = attempt.timeSpentSeconds ?? 0;\r\n\r\n return (\r\n <div style={defaultStyles.container} className={className}>\r\n <style>{spinnerKeyframes}</style>\r\n \r\n <div style={defaultStyles.header}>\r\n <div style={defaultStyles.summaryGrid}>\r\n <div style={defaultStyles.summaryCard}>\r\n <div style={defaultStyles.summaryValue}>{scorePercentage}%</div>\r\n <div style={defaultStyles.summaryLabel}>Score</div>\r\n </div>\r\n <div style={defaultStyles.summaryCard}>\r\n <div style={defaultStyles.summaryValue}>{correctCount}/{totalQuestions}</div>\r\n <div style={defaultStyles.summaryLabel}>Correct</div>\r\n </div>\r\n <div style={defaultStyles.summaryCard}>\r\n <div style={defaultStyles.summaryValue}>{formatTime(timeSpent)}</div>\r\n <div style={defaultStyles.summaryLabel}>Time</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div style={defaultStyles.questionsList}>\r\n {attempt.answers.map((answer: QuizAnswerDetail, index: number) => (\r\n <div\r\n key={answer.questionId}\r\n style={{\r\n ...defaultStyles.questionCard,\r\n ...(answer.isCorrect ? defaultStyles.questionCardCorrect : defaultStyles.questionCardIncorrect),\r\n }}\r\n >\r\n <div style={defaultStyles.questionHeader}>\r\n <span style={defaultStyles.questionNumber}>Question {index + 1}</span>\r\n <span\r\n style={{\r\n ...defaultStyles.questionBadge,\r\n ...(answer.isCorrect ? defaultStyles.badgeCorrect : defaultStyles.badgeIncorrect),\r\n }}\r\n >\r\n {answer.isCorrect ? 'Correct' : 'Incorrect'}\r\n </span>\r\n </div>\r\n\r\n <div style={defaultStyles.questionText}>{answer.questionText}</div>\r\n\r\n <div style={defaultStyles.answerSection}>\r\n <span style={defaultStyles.answerLabel}>Your answer:</span>\r\n <span style={defaultStyles.studentAnswer}>\r\n {formatAnswer(answer.selectedAnswer)}\r\n </span>\r\n </div>\r\n\r\n {!answer.isCorrect && answer.correctAnswer && (\r\n <div style={defaultStyles.answerSection}>\r\n <span style={defaultStyles.answerLabel}>Correct answer:</span>\r\n <span style={defaultStyles.correctAnswer}>\r\n {formatAnswer(answer.correctAnswer)}\r\n </span>\r\n </div>\r\n )}\r\n\r\n <div style={defaultStyles.points}>\r\n {answer.pointsEarned} / {answer.points} points\r\n </div>\r\n\r\n {showExplanations && answer.explanation && (\r\n <div style={defaultStyles.explanation}>\r\n <strong>Explanation:</strong> {answer.explanation}\r\n </div>\r\n )}\r\n\r\n {/* Chat History Section */}\r\n {showConversation && chatHistories[answer.questionId] && chatHistories[answer.questionId].messages.length > 0 && (\r\n <div style={defaultStyles.chatHistorySection}>\r\n <button\r\n style={defaultStyles.chatToggleButton}\r\n onClick={() => toggleChatExpanded(answer.questionId)}\r\n data-testid={`button-toggle-chat-${answer.questionId}`}\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\r\n </svg>\r\n {expandedChats.has(answer.questionId) ? 'Hide' : 'View'} Chat History ({chatHistories[answer.questionId].messages.length} messages)\r\n </button>\r\n \r\n {expandedChats.has(answer.questionId) && (\r\n <div style={defaultStyles.chatMessages}>\r\n {chatHistories[answer.questionId].messages.map((msg, msgIndex) => (\r\n <div\r\n key={msgIndex}\r\n style={{\r\n ...defaultStyles.chatMessage,\r\n ...(msg.role === 'user' ? defaultStyles.chatMessageUser : defaultStyles.chatMessageAssistant),\r\n }}\r\n >\r\n {msg.content}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n ))}\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","VolumeIcon","import_jsx_runtime","selectedAnswer","result","import_react","import_jsx_runtime","defaultStyles"]}