@schoolio/player 1.4.5 → 1.4.6
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 +695 -589
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +695 -589
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/QuizPlayer.tsx","../src/api.ts","../src/utils.ts","../src/TextToSpeech.tsx","../src/QuestionChatPanel.tsx","../src/errors.ts","../src/MaintenanceScreen.tsx","../src/assets/astronautData.ts","../src/AttemptViewer.tsx","../src/ErrorTypesPanel.tsx","../src/ErrorLogsPanel.tsx"],"sourcesContent":["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\nimport { MaintenanceScreen } from './MaintenanceScreen';\r\nimport { ErrorCode, getErrorFromMessage } from './errors';\r\nimport { astronautImage } from './assets/astronautData';\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 feedbackNeutral: {\r\n backgroundColor: '#f0f9ff',\r\n borderColor: '#0ea5e9',\r\n },\r\n feedbackTitleNeutral: {\r\n color: '#0369a1',\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// Sorting drag-and-drop component using HTML5 native drag and drop\r\ninterface SortingDragDropProps {\r\n items: string[];\r\n currentOrder: number[];\r\n correctOrder?: number[];\r\n showFeedback: boolean;\r\n onOrderChange: (newOrder: number[]) => void;\r\n}\r\n\r\nfunction SortingDragDrop({ items, currentOrder, correctOrder, showFeedback, onOrderChange }: SortingDragDropProps) {\r\n const [draggedIndex, setDraggedIndex] = useState<number | null>(null);\r\n const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);\r\n\r\n const handleDragStart = (e: React.DragEvent, position: number) => {\r\n if (showFeedback) return;\r\n setDraggedIndex(position);\r\n e.dataTransfer.effectAllowed = 'move';\r\n e.dataTransfer.setData('text/plain', position.toString());\r\n };\r\n\r\n const handleDragOver = (e: React.DragEvent, position: number) => {\r\n e.preventDefault();\r\n if (showFeedback) return;\r\n e.dataTransfer.dropEffect = 'move';\r\n setDragOverIndex(position);\r\n };\r\n\r\n const handleDragLeave = () => {\r\n setDragOverIndex(null);\r\n };\r\n\r\n const handleDrop = (e: React.DragEvent, toPosition: number) => {\r\n e.preventDefault();\r\n if (showFeedback) return;\r\n const fromPosition = parseInt(e.dataTransfer.getData('text/plain'), 10);\r\n if (fromPosition !== toPosition) {\r\n const newOrder = [...currentOrder];\r\n const [movedItem] = newOrder.splice(fromPosition, 1);\r\n newOrder.splice(toPosition, 0, movedItem);\r\n onOrderChange(newOrder);\r\n }\r\n setDraggedIndex(null);\r\n setDragOverIndex(null);\r\n };\r\n\r\n const handleDragEnd = () => {\r\n setDraggedIndex(null);\r\n setDragOverIndex(null);\r\n };\r\n\r\n return (\r\n <div style={defaultStyles.options}>\r\n {currentOrder.map((itemIndex, position) => {\r\n const isCorrectPosition = correctOrder?.[position] === itemIndex;\r\n const isDragging = draggedIndex === position;\r\n const isDragOver = dragOverIndex === position;\r\n \r\n let itemStyle: React.CSSProperties = {\r\n ...defaultStyles.option,\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '12px',\r\n cursor: showFeedback ? 'default' : 'grab',\r\n opacity: isDragging ? 0.5 : 1,\r\n transition: 'all 0.2s ease',\r\n transform: isDragOver && !showFeedback ? 'scale(1.02)' : 'scale(1)',\r\n };\r\n \r\n if (showFeedback) {\r\n if (isCorrectPosition) {\r\n itemStyle = { ...itemStyle, ...defaultStyles.optionCorrect };\r\n } else {\r\n itemStyle = { ...itemStyle, ...defaultStyles.optionIncorrect };\r\n }\r\n } else if (isDragOver) {\r\n itemStyle = { ...itemStyle, borderColor: '#6366f1', backgroundColor: '#eef2ff' };\r\n }\r\n\r\n return (\r\n <div\r\n key={itemIndex}\r\n style={itemStyle}\r\n data-testid={`sorting-item-${position}`}\r\n draggable={!showFeedback}\r\n onDragStart={(e) => handleDragStart(e, position)}\r\n onDragOver={(e) => handleDragOver(e, position)}\r\n onDragLeave={handleDragLeave}\r\n onDrop={(e) => handleDrop(e, position)}\r\n onDragEnd={handleDragEnd}\r\n >\r\n {!showFeedback && (\r\n <div style={{ \r\n cursor: 'grab', \r\n padding: '4px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n color: '#9ca3af',\r\n }}>\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <circle cx=\"9\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"19\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"19\" r=\"1\"/>\r\n </svg>\r\n </div>\r\n )}\r\n {showFeedback && (\r\n <div style={{ \r\n display: 'flex',\r\n alignItems: 'center',\r\n color: isCorrectPosition ? '#22c55e' : '#ef4444',\r\n }}>\r\n {isCorrectPosition ? (\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/>\r\n <polyline points=\"22 4 12 14.01 9 11.01\"/>\r\n </svg>\r\n ) : (\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\"/>\r\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/>\r\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\r\n </svg>\r\n )}\r\n </div>\r\n )}\r\n <span style={{ flex: 1 }}>{items[itemIndex]}</span>\r\n <span onClick={(e) => e.stopPropagation()}>\r\n <TextToSpeech text={items[itemIndex]} size=\"sm\" />\r\n </span>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n );\r\n}\r\n\r\n// Matching drag-and-drop component using HTML5 native drag and drop\r\ninterface MatchingDragDropProps {\r\n leftItems: string[];\r\n rightItems: string[];\r\n currentMatches: Record<string, string>;\r\n correctMatches?: Record<string, string>;\r\n showFeedback: boolean;\r\n onMatchChange: (newMatches: Record<string, string>) => void;\r\n}\r\n\r\nfunction MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatches, showFeedback, onMatchChange }: MatchingDragDropProps) {\r\n const [draggedItem, setDraggedItem] = useState<string | null>(null);\r\n const [dragOverLeft, setDragOverLeft] = useState<string | null>(null);\r\n\r\n // Get unmatched right items\r\n const matchedRightItems = Object.values(currentMatches);\r\n const unmatchedRightItems = rightItems.filter(item => !matchedRightItems.includes(item));\r\n\r\n const handleDragStart = (e: React.DragEvent, rightItem: string) => {\r\n if (showFeedback) return;\r\n setDraggedItem(rightItem);\r\n e.dataTransfer.effectAllowed = 'move';\r\n e.dataTransfer.setData('text/plain', rightItem);\r\n };\r\n\r\n const handleDragOver = (e: React.DragEvent, leftItem: string) => {\r\n e.preventDefault();\r\n if (showFeedback) return;\r\n e.dataTransfer.dropEffect = 'move';\r\n setDragOverLeft(leftItem);\r\n };\r\n\r\n const handleDragLeave = () => {\r\n setDragOverLeft(null);\r\n };\r\n\r\n const handleDrop = (e: React.DragEvent, leftItem: string) => {\r\n e.preventDefault();\r\n if (showFeedback) return;\r\n const rightItem = e.dataTransfer.getData('text/plain');\r\n if (rightItem) {\r\n // Remove the rightItem from any existing match\r\n const newMatches = { ...currentMatches };\r\n Object.keys(newMatches).forEach(key => {\r\n if (newMatches[key] === rightItem) {\r\n delete newMatches[key];\r\n }\r\n });\r\n // Assign to the new left item\r\n newMatches[leftItem] = rightItem;\r\n onMatchChange(newMatches);\r\n }\r\n setDraggedItem(null);\r\n setDragOverLeft(null);\r\n };\r\n\r\n const handleDragEnd = () => {\r\n setDraggedItem(null);\r\n setDragOverLeft(null);\r\n };\r\n\r\n const handleClearMatch = (leftItem: string) => {\r\n if (showFeedback) return;\r\n const newMatches = { ...currentMatches };\r\n delete newMatches[leftItem];\r\n onMatchChange(newMatches);\r\n };\r\n\r\n return (\r\n <div style={{ display: 'flex', gap: '24px', flexWrap: 'wrap' }}>\r\n {/* Left column - drop targets */}\r\n <div style={{ flex: 1, minWidth: '200px', display: 'flex', flexDirection: 'column', gap: '8px' }}>\r\n <div style={{ fontSize: '14px', fontWeight: '600', color: '#6b7280', marginBottom: '4px' }}>Match these items:</div>\r\n {leftItems.map((leftItem, idx) => {\r\n const matchedRight = currentMatches[leftItem];\r\n const correctMatch = correctMatches?.[leftItem];\r\n const isCorrect = matchedRight === correctMatch;\r\n const isDragOver = dragOverLeft === leftItem;\r\n\r\n let rowStyle: React.CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '12px',\r\n padding: '12px 16px',\r\n border: '2px dashed #e5e7eb',\r\n borderRadius: '8px',\r\n backgroundColor: '#ffffff',\r\n minHeight: '56px',\r\n transition: 'all 0.2s ease',\r\n };\r\n\r\n if (showFeedback) {\r\n rowStyle.borderStyle = 'solid';\r\n if (isCorrect) {\r\n rowStyle = { ...rowStyle, borderColor: '#22c55e', backgroundColor: '#f0fdf4' };\r\n } else {\r\n rowStyle = { ...rowStyle, borderColor: '#ef4444', backgroundColor: '#fef2f2' };\r\n }\r\n } else if (isDragOver) {\r\n rowStyle = { ...rowStyle, borderColor: '#6366f1', backgroundColor: '#eef2ff', borderStyle: 'solid' };\r\n } else if (matchedRight) {\r\n rowStyle = { ...rowStyle, borderStyle: 'solid', borderColor: '#22c55e' };\r\n }\r\n\r\n return (\r\n <div\r\n key={idx}\r\n style={rowStyle}\r\n data-testid={`matrix-row-${idx}`}\r\n onDragOver={(e) => handleDragOver(e, leftItem)}\r\n onDragLeave={handleDragLeave}\r\n onDrop={(e) => handleDrop(e, leftItem)}\r\n >\r\n <span style={{ flex: 1, fontWeight: '500' }}>{leftItem}</span>\r\n <span style={{ color: '#6b7280' }}>→</span>\r\n {matchedRight ? (\r\n <div style={{ \r\n display: 'flex', \r\n alignItems: 'center', \r\n gap: '8px', \r\n padding: '6px 12px',\r\n backgroundColor: showFeedback \r\n ? (isCorrect ? '#dcfce7' : '#fee2e2')\r\n : '#e0e7ff',\r\n borderRadius: '6px',\r\n fontSize: '14px',\r\n }}>\r\n <span>{matchedRight}</span>\r\n {!showFeedback && (\r\n <button\r\n onClick={() => handleClearMatch(leftItem)}\r\n style={{\r\n background: 'none',\r\n border: 'none',\r\n cursor: 'pointer',\r\n padding: '2px',\r\n display: 'flex',\r\n color: '#6b7280',\r\n }}\r\n aria-label=\"Remove match\"\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 <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n </button>\r\n )}\r\n {showFeedback && (\r\n isCorrect ? (\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#22c55e\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <polyline points=\"20 6 9 17 4 12\"/>\r\n </svg>\r\n ) : (\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ef4444\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n )\r\n )}\r\n </div>\r\n ) : (\r\n <span style={{ color: '#9ca3af', fontSize: '14px', fontStyle: 'italic' }}>\r\n Drop here\r\n </span>\r\n )}\r\n {showFeedback && !isCorrect && correctMatch && (\r\n <span style={{ color: '#166534', fontSize: '13px', marginLeft: '8px' }}>\r\n (Correct: {correctMatch})\r\n </span>\r\n )}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n\r\n {/* Right column - draggable items */}\r\n <div style={{ flex: 1, minWidth: '200px', display: 'flex', flexDirection: 'column', gap: '8px' }}>\r\n <div style={{ fontSize: '14px', fontWeight: '600', color: '#6b7280', marginBottom: '4px' }}>Drag to match:</div>\r\n {unmatchedRightItems.length > 0 ? (\r\n unmatchedRightItems.map((rightItem, idx) => {\r\n const isDragging = draggedItem === rightItem;\r\n\r\n return (\r\n <div\r\n key={idx}\r\n style={{\r\n padding: '12px 16px',\r\n border: '2px solid #e5e7eb',\r\n borderRadius: '8px',\r\n backgroundColor: '#ffffff',\r\n cursor: showFeedback ? 'default' : 'grab',\r\n opacity: isDragging ? 0.5 : 1,\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n transition: 'all 0.2s ease',\r\n }}\r\n draggable={!showFeedback}\r\n onDragStart={(e) => handleDragStart(e, rightItem)}\r\n onDragEnd={handleDragEnd}\r\n data-testid={`draggable-right-${idx}`}\r\n >\r\n {!showFeedback && (\r\n <div style={{ color: '#9ca3af', display: 'flex' }}>\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <circle cx=\"9\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"19\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"19\" r=\"1\"/>\r\n </svg>\r\n </div>\r\n )}\r\n <span style={{ flex: 1 }}>{rightItem}</span>\r\n </div>\r\n );\r\n })\r\n ) : (\r\n <div style={{ \r\n padding: '16px', \r\n textAlign: 'center', \r\n color: '#22c55e',\r\n fontSize: '14px',\r\n }}>\r\n All items matched!\r\n </div>\r\n )}\r\n </div>\r\n </div>\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 hideScore = false,\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 [errorCode, setErrorCode] = useState<ErrorCode | 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 [showResumeChoice, setShowResumeChoice] = useState(false);\r\n const [hasExistingProgress, setHasExistingProgress] = useState(false);\r\n const [existingProgressCount, setExistingProgressCount] = useState(0);\r\n const [isStartingFresh, setIsStartingFresh] = useState(false);\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 setErrorCode(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 // Check for existing progress when not forcing new attempt\r\n if (!forceNewAttempt && attemptData.answers && attemptData.answers.length > 0 && attemptData.status === 'in_progress') {\r\n // Mark that we have existing progress - will show choice screen\r\n setHasExistingProgress(true);\r\n setExistingProgressCount(attemptData.answers.length);\r\n setShowResumeChoice(true);\r\n // Pre-load the answers so \"Continue\" can use them\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 const code = getErrorFromMessage(message, 'quiz');\r\n setErrorCode(code);\r\n // Log error to tracking system\r\n apiClient.current?.logError({\r\n errorCode: code,\r\n context: 'quiz',\r\n resourceId: quizId,\r\n component: 'QuizPlayer',\r\n message,\r\n });\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 && !errorCode) {\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, errorCode]);\r\n\r\n // Handle start button click\r\n const handleStart = useCallback(() => {\r\n setShowIntro(false);\r\n setShowResumeChoice(false);\r\n setTimerStarted(true);\r\n }, []);\r\n\r\n // Handle \"Continue Where I Left Off\" - resume from existing progress\r\n const handleResumePrevious = useCallback(() => {\r\n // Find the first unanswered question index\r\n if (quiz && answers.size > 0) {\r\n const answeredIds = new Set(answers.keys());\r\n const allQs = [...quiz.questions, ...extraQuestions].filter(q => !skippedQuestionIds.has(q.id));\r\n let resumeIndex = 0;\r\n for (let i = 0; i < allQs.length; i++) {\r\n if (!answeredIds.has(allQs[i].id)) {\r\n resumeIndex = i;\r\n break;\r\n }\r\n // If all answered, go to last question\r\n resumeIndex = allQs.length - 1;\r\n }\r\n setCurrentQuestionIndex(resumeIndex);\r\n }\r\n setShowIntro(false);\r\n setShowResumeChoice(false);\r\n setTimerStarted(true);\r\n }, [quiz, answers, extraQuestions, skippedQuestionIds]);\r\n\r\n // Handle \"Start Fresh\" - abandon old attempt and create new one\r\n const handleStartFresh = useCallback(async () => {\r\n if (!apiClient.current || !attempt) return;\r\n \r\n setIsStartingFresh(true);\r\n try {\r\n // Abandon the current attempt\r\n await apiClient.current.updateAttempt(attempt.id, {\r\n status: 'abandoned'\r\n });\r\n\r\n // Create a fresh attempt\r\n const newAttemptData = 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: true,\r\n });\r\n \r\n // Reset all state\r\n setAttempt(newAttemptData);\r\n setAnswers(new Map());\r\n setAnswersDetail([]);\r\n setCurrentQuestionIndex(0);\r\n setHasExistingProgress(false);\r\n setExistingProgressCount(0);\r\n setShowResumeChoice(false);\r\n setShowIntro(false);\r\n setTimerStarted(true);\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : 'Failed to start fresh';\r\n onErrorRef.current?.(new Error(message));\r\n } finally {\r\n setIsStartingFresh(false);\r\n }\r\n }, [attempt, quizId, lessonId, assignLessonId, courseId, childId, parentId]);\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 const code = getErrorFromMessage(message, 'quiz');\r\n setErrorCode(code);\r\n // Log error to tracking system\r\n apiClient.current?.logError({\r\n errorCode: code,\r\n context: 'quiz',\r\n resourceId: quizId,\r\n component: 'QuizPlayer',\r\n message,\r\n });\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 - show maintenance screen for server/connection errors\r\n if (errorCode) {\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <MaintenanceScreen errorCode={errorCode} />\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 component - astronaut on rocket image\r\n const Mascot = ({ mood }: { mood: string }) => {\r\n return (\r\n <img\r\n src={astronautImage}\r\n alt=\"Astronaut mascot\"\r\n width=\"180\"\r\n height=\"180\"\r\n style={{\r\n animation: mood === 'celebrating' ? 'bounce 0.6s ease-in-out infinite' : 'gentleBob 2s ease-in-out infinite',\r\n objectFit: 'contain',\r\n }}\r\n />\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 {hideScore ? (\r\n <>\r\n {/* Simple success message when score is hidden */}\r\n <div style={{ marginBottom: '24px' }}>\r\n <Mascot mood=\"happy\" />\r\n </div>\r\n\r\n <div\r\n style={{\r\n background: 'linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%)',\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 #22c55e',\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 All Done!\r\n </span>\r\n </div>\r\n\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: '24px',\r\n fontWeight: '600',\r\n color: '#22c55e',\r\n lineHeight: '1.4',\r\n marginBottom: '12px',\r\n }}\r\n >\r\n The quiz was submitted successfully!\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 </>\r\n ) : (\r\n <>\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 <Mascot 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 </>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n // Render resume choice screen when there's an incomplete attempt\r\n if (quiz && showIntro && showResumeChoice && hasExistingProgress) {\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <div style={defaultStyles.intro}>\r\n <div style={defaultStyles.introTitle}>Welcome Back!</div>\r\n <div style={defaultStyles.introSubtitle}>\r\n You have an unfinished quiz. Would you like to continue or start over?\r\n </div>\r\n <div style={defaultStyles.introQuestionCount}>\r\n {existingProgressCount} of {quiz.questions.length} question{quiz.questions.length !== 1 ? 's' : ''} answered\r\n </div>\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '12px', marginTop: '8px' }}>\r\n <button\r\n style={defaultStyles.startButton}\r\n onClick={handleResumePrevious}\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-continue-quiz\"\r\n >\r\n Continue Where I Left Off\r\n </button>\r\n <button\r\n style={{\r\n ...defaultStyles.startButton,\r\n background: 'transparent',\r\n color: '#7c3aed',\r\n border: '2px solid #7c3aed',\r\n boxShadow: 'none',\r\n }}\r\n onClick={handleStartFresh}\r\n disabled={isStartingFresh}\r\n onMouseOver={(e) => {\r\n if (!isStartingFresh) {\r\n e.currentTarget.style.transform = 'translateY(-2px)';\r\n e.currentTarget.style.background = 'rgba(124, 58, 237, 0.1)';\r\n }\r\n }}\r\n onMouseOut={(e) => {\r\n e.currentTarget.style.transform = 'translateY(0)';\r\n e.currentTarget.style.background = 'transparent';\r\n }}\r\n data-testid=\"button-start-fresh\"\r\n >\r\n {isStartingFresh ? 'Starting...' : 'Start Fresh'}\r\n </button>\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 {/* Sorting question type with drag-and-drop */}\r\n {currentQuestion.type === 'sorting' && currentQuestion.items && (\r\n <SortingDragDrop\r\n items={currentQuestion.items}\r\n currentOrder={Array.isArray(selectedAnswer) ? (selectedAnswer as number[]) : currentQuestion.items.map((_, i) => i)}\r\n correctOrder={currentQuestion.correctOrder}\r\n showFeedback={showFeedback}\r\n onOrderChange={handleAnswerChange}\r\n />\r\n )}\r\n\r\n {/* Matrix/Matching question type with drag-and-drop */}\r\n {currentQuestion.type === 'matrix' && currentQuestion.leftItems && currentQuestion.rightItems && (\r\n <MatchingDragDrop\r\n leftItems={currentQuestion.leftItems}\r\n rightItems={currentQuestion.rightItems}\r\n currentMatches={(typeof selectedAnswer === 'object' && selectedAnswer !== null && !Array.isArray(selectedAnswer))\r\n ? (selectedAnswer as Record<string, string>)\r\n : {}}\r\n correctMatches={currentQuestion.correctMatches}\r\n showFeedback={showFeedback}\r\n onMatchChange={handleAnswerChange}\r\n />\r\n )}\r\n\r\n {/* Assessment question type */}\r\n {currentQuestion.type === 'assessment' && (\r\n <div style={defaultStyles.options}>\r\n {(() => {\r\n const scaleType = currentQuestion.scaleType || 'likert';\r\n \r\n if (scaleType === 'yes-no') {\r\n const options = ['Yes', 'No'];\r\n return options.map((option, idx) => {\r\n const isSelected = selectedAnswer === option;\r\n let optionStyle = { ...defaultStyles.option };\r\n if (isSelected) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };\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 data-testid={`assessment-option-${option.toLowerCase()}`}\r\n >\r\n <span style={{ flex: 1 }}>{option}</span>\r\n </div>\r\n );\r\n });\r\n }\r\n \r\n if (scaleType === 'rating') {\r\n const min = currentQuestion.scaleMin || 1;\r\n const max = currentQuestion.scaleMax || 5;\r\n const ratings = Array.from({ length: max - min + 1 }, (_, i) => min + i);\r\n return (\r\n <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap', justifyContent: 'center' }}>\r\n {ratings.map((rating) => {\r\n const isSelected = selectedAnswer === rating;\r\n return (\r\n <button\r\n key={rating}\r\n onClick={() => !showFeedback && handleAnswerChange(rating)}\r\n disabled={showFeedback}\r\n style={{\r\n width: '48px',\r\n height: '48px',\r\n borderRadius: '50%',\r\n border: isSelected ? '2px solid #6721b0' : '2px solid #e5e7eb',\r\n backgroundColor: isSelected ? '#f3e8ff' : '#ffffff',\r\n cursor: showFeedback ? 'not-allowed' : 'pointer',\r\n fontSize: '18px',\r\n fontWeight: '600',\r\n color: isSelected ? '#6721b0' : '#374151',\r\n }}\r\n data-testid={`assessment-rating-${rating}`}\r\n >\r\n {rating}\r\n </button>\r\n );\r\n })}\r\n </div>\r\n );\r\n }\r\n \r\n // Default: Likert scale\r\n const likertOptions = [\r\n 'Strongly Disagree',\r\n 'Disagree',\r\n 'Neutral',\r\n 'Agree',\r\n 'Strongly Agree',\r\n ];\r\n return likertOptions.map((option, idx) => {\r\n const isSelected = selectedAnswer === option;\r\n let optionStyle = { ...defaultStyles.option };\r\n if (isSelected) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };\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 data-testid={`assessment-likert-${idx}`}\r\n >\r\n <span style={{ flex: 1 }}>{option}</span>\r\n </div>\r\n );\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 ...(currentQuestion.type === 'assessment' \r\n ? defaultStyles.feedbackNeutral\r\n : currentAnswerDetail.isCorrect \r\n ? defaultStyles.feedbackCorrect \r\n : defaultStyles.feedbackIncorrect),\r\n }}>\r\n <div style={{\r\n ...defaultStyles.feedbackTitle,\r\n ...(currentQuestion.type === 'assessment'\r\n ? defaultStyles.feedbackTitleNeutral\r\n : currentAnswerDetail.isCorrect \r\n ? defaultStyles.feedbackTitleCorrect \r\n : defaultStyles.feedbackTitleIncorrect),\r\n }}>\r\n {currentQuestion.type === 'assessment' \r\n ? '✓ Response recorded' \r\n : currentAnswerDetail.isCorrect \r\n ? '✓ Correct!' \r\n : '✗ 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: currentQuestion.type !== 'assessment' && !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 async logError(params: {\r\n errorCode: string;\r\n context: 'quiz' | 'attempt';\r\n resourceId?: string;\r\n component: 'QuizPlayer' | 'AttemptViewer';\r\n message?: string;\r\n }): Promise<void> {\r\n try {\r\n await this.request<{ success: boolean }>('POST', '/api/external/log-error', params);\r\n } catch (e) {\r\n // Silently fail - we don't want error logging to break the user experience\r\n console.warn('[QuizEngine] Failed to log error:', e);\r\n }\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 // Essays require manual grading\r\n return { isCorrect: false, pointsEarned: 0 };\r\n\r\n case 'assessment':\r\n // Assessment/survey questions are opinion-based - always mark as correct\r\n return { isCorrect: true, pointsEarned: points };\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 const detail: QuizAnswerDetail = {\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 // Include type-specific fields for display purposes\r\n if (question.type === 'sorting') {\r\n detail.items = question.items;\r\n detail.correctOrder = question.correctOrder;\r\n } else if (question.type === 'matrix') {\r\n detail.leftItems = question.leftItems;\r\n detail.rightItems = question.rightItems;\r\n }\r\n\r\n return detail;\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","export type ErrorCode = \r\n | 'QUIZ_NOT_FOUND'\r\n | 'ATTEMPT_NOT_FOUND'\r\n | 'QUIZ_EXPIRED'\r\n | 'QUIZ_NOT_STARTED'\r\n | 'NETWORK_ERROR'\r\n | 'SERVER_ERROR'\r\n | 'UNAUTHORIZED'\r\n | 'FORBIDDEN'\r\n | 'TTS_FAILED'\r\n | 'CHAT_FAILED'\r\n | 'SUBMISSION_FAILED'\r\n | 'UNKNOWN_ERROR';\r\n\r\nexport interface ErrorDefinition {\r\n code: ErrorCode;\r\n userMessage: string;\r\n subMessage: string;\r\n cause: string;\r\n isBlocking: boolean;\r\n}\r\n\r\nexport const ERROR_DEFINITIONS: Record<ErrorCode, ErrorDefinition> = {\r\n QUIZ_NOT_FOUND: {\r\n code: 'QUIZ_NOT_FOUND',\r\n userMessage: \"We couldn't find this quiz\",\r\n subMessage: 'The quiz may have been removed or the link is incorrect.',\r\n cause: 'The quiz ID does not exist in the database, or the quiz has been deleted.',\r\n isBlocking: true,\r\n },\r\n ATTEMPT_NOT_FOUND: {\r\n code: 'ATTEMPT_NOT_FOUND',\r\n userMessage: \"We couldn't find this quiz attempt\",\r\n subMessage: 'The attempt may have expired or the link is incorrect.',\r\n cause: 'The attempt ID does not exist, or the attempt has been deleted/archived.',\r\n isBlocking: true,\r\n },\r\n QUIZ_EXPIRED: {\r\n code: 'QUIZ_EXPIRED',\r\n userMessage: 'This quiz has expired',\r\n subMessage: 'The deadline for this quiz has passed.',\r\n cause: 'The quiz end date/time has passed and submissions are no longer accepted.',\r\n isBlocking: true,\r\n },\r\n QUIZ_NOT_STARTED: {\r\n code: 'QUIZ_NOT_STARTED',\r\n userMessage: 'This quiz is not available yet',\r\n subMessage: 'Please check back when the quiz opens.',\r\n cause: 'The quiz start date/time has not yet been reached.',\r\n isBlocking: true,\r\n },\r\n NETWORK_ERROR: {\r\n code: 'NETWORK_ERROR',\r\n userMessage: 'Connection problem',\r\n subMessage: 'Please check your internet connection and try again.',\r\n cause: 'Unable to reach the server due to network connectivity issues.',\r\n isBlocking: true,\r\n },\r\n SERVER_ERROR: {\r\n code: 'SERVER_ERROR',\r\n userMessage: 'Something went wrong on our end',\r\n subMessage: 'Our team has been notified. Please try again later.',\r\n cause: 'The server encountered an internal error (HTTP 500+).',\r\n isBlocking: true,\r\n },\r\n UNAUTHORIZED: {\r\n code: 'UNAUTHORIZED',\r\n userMessage: 'Please sign in to continue',\r\n subMessage: 'You need to be logged in to access this quiz.',\r\n cause: 'The user is not authenticated (HTTP 401).',\r\n isBlocking: true,\r\n },\r\n FORBIDDEN: {\r\n code: 'FORBIDDEN',\r\n userMessage: \"You don't have access to this quiz\",\r\n subMessage: 'Contact your instructor if you believe this is a mistake.',\r\n cause: 'The user does not have permission to access this resource (HTTP 403).',\r\n isBlocking: true,\r\n },\r\n TTS_FAILED: {\r\n code: 'TTS_FAILED',\r\n userMessage: 'Text-to-speech unavailable',\r\n subMessage: 'Audio features are temporarily unavailable.',\r\n cause: 'The text-to-speech service failed or is unreachable.',\r\n isBlocking: false,\r\n },\r\n CHAT_FAILED: {\r\n code: 'CHAT_FAILED',\r\n userMessage: 'Chat assistance unavailable',\r\n subMessage: 'The AI helper is temporarily unavailable.',\r\n cause: 'The chat/AI service failed to initialize or respond.',\r\n isBlocking: false,\r\n },\r\n SUBMISSION_FAILED: {\r\n code: 'SUBMISSION_FAILED',\r\n userMessage: 'Failed to submit your answer',\r\n subMessage: 'Please try again. Your progress has been saved.',\r\n cause: 'The answer submission request failed due to network or server issues.',\r\n isBlocking: false,\r\n },\r\n UNKNOWN_ERROR: {\r\n code: 'UNKNOWN_ERROR',\r\n userMessage: 'Something unexpected happened',\r\n subMessage: 'Please try refreshing the page.',\r\n cause: 'An unclassified error occurred.',\r\n isBlocking: true,\r\n },\r\n};\r\n\r\nexport function getErrorFromHttpStatus(status: number, context?: 'quiz' | 'attempt'): ErrorCode {\r\n switch (status) {\r\n case 401:\r\n return 'UNAUTHORIZED';\r\n case 403:\r\n return 'FORBIDDEN';\r\n case 404:\r\n return context === 'attempt' ? 'ATTEMPT_NOT_FOUND' : 'QUIZ_NOT_FOUND';\r\n case 410:\r\n return 'QUIZ_EXPIRED';\r\n case 500:\r\n case 502:\r\n case 503:\r\n case 504:\r\n return 'SERVER_ERROR';\r\n default:\r\n if (status >= 400 && status < 500) {\r\n return context === 'attempt' ? 'ATTEMPT_NOT_FOUND' : 'QUIZ_NOT_FOUND';\r\n }\r\n return 'UNKNOWN_ERROR';\r\n }\r\n}\r\n\r\nexport function getErrorFromMessage(message: string, context?: 'quiz' | 'attempt'): ErrorCode {\r\n const lowerMessage = message.toLowerCase();\r\n \r\n if (lowerMessage.includes('network') || lowerMessage.includes('fetch') || lowerMessage.includes('connection')) {\r\n return 'NETWORK_ERROR';\r\n }\r\n if (lowerMessage.includes('not found') || lowerMessage.includes('404')) {\r\n return context === 'attempt' ? 'ATTEMPT_NOT_FOUND' : 'QUIZ_NOT_FOUND';\r\n }\r\n if (lowerMessage.includes('unauthorized') || lowerMessage.includes('401')) {\r\n return 'UNAUTHORIZED';\r\n }\r\n if (lowerMessage.includes('forbidden') || lowerMessage.includes('403')) {\r\n return 'FORBIDDEN';\r\n }\r\n if (lowerMessage.includes('expired')) {\r\n return 'QUIZ_EXPIRED';\r\n }\r\n if (lowerMessage.includes('tts') || lowerMessage.includes('speech')) {\r\n return 'TTS_FAILED';\r\n }\r\n if (lowerMessage.includes('chat')) {\r\n return 'CHAT_FAILED';\r\n }\r\n \r\n return 'UNKNOWN_ERROR';\r\n}\r\n","import { ErrorCode, ERROR_DEFINITIONS } from './errors';\r\n\r\ninterface MaintenanceScreenProps {\r\n errorCode?: ErrorCode;\r\n}\r\n\r\nexport function MaintenanceScreen({ errorCode }: MaintenanceScreenProps) {\r\n const errorDef = errorCode ? ERROR_DEFINITIONS[errorCode] : null;\r\n const message = errorDef?.userMessage || 'Your quiz is on its way...';\r\n const subMessage = errorDef?.subMessage || 'Please check back soon!';\r\n\r\n const containerStyle: React.CSSProperties = {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n minHeight: '300px',\r\n padding: '40px',\r\n background: 'linear-gradient(135deg, #f8f7ff 0%, #e8e4f8 50%, #f0ebff 100%)',\r\n borderRadius: '16px',\r\n };\r\n\r\n const iconStyle: React.CSSProperties = {\r\n fontSize: '48px',\r\n marginBottom: '24px',\r\n color: '#8b5cf6',\r\n };\r\n\r\n const messageStyle: React.CSSProperties = {\r\n fontSize: '20px',\r\n fontWeight: '600',\r\n color: '#4c1d95',\r\n textAlign: 'center',\r\n marginBottom: '12px',\r\n };\r\n\r\n const submessageStyle: React.CSSProperties = {\r\n fontSize: '14px',\r\n color: '#7c3aed',\r\n textAlign: 'center',\r\n opacity: 0.8,\r\n };\r\n\r\n return (\r\n <div style={containerStyle} data-testid=\"maintenance-screen\" data-error-code={errorCode || 'none'}>\r\n <div style={iconStyle}>\r\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <path d=\"M12 8v4\" />\r\n <path d=\"M12 16h.01\" />\r\n </svg>\r\n </div>\r\n <div style={messageStyle} data-testid=\"text-error-message\">\r\n {message}\r\n </div>\r\n <div style={submessageStyle} data-testid=\"text-error-submessage\">\r\n {subMessage}\r\n </div>\r\n </div>\r\n );\r\n}\r\n","export const astronautImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB4AAAAQ4CAMAAADfDTFxAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAwBQTFRFYGBgsVEZcHBwq6urhYSEkZGRiomJuJsBMxoHJCAhUFBQQEBAXZu4ATtbnp6ev7+/dDURJnqMdnR1enl5ABoqAm2rVSYMamhpLCkqKCUlz8/PMS0uWksA39/fbmxtAViJEBAQAAAAzunzMDAwPDo6qKioj46OgICAoqKiOC8AOTU2oKCgaq3LNDExibbNQD4+mpqaV1RVRUJCZmRlpqampKSkSEVGlpaWUE5OTElKnJycIm5+mJiYXlxdf35+lJSUXFlaU1FSZGFiWFZWAV+UBGaebtLoWlhZqMjWTMjiS0hJc3FyAUlyidvtbGpraGZmb25ujYyMYF5ed3Z2F0lUFw4CAVB+////AUJnLCgpecXVKXyqfHp75eXlT0xN1dXVNzQ1hai8ksXZPzw9qNLlTn6UsOfywMDAICAgASxFwNzsEz1GgH5/R0RFJ1ZwOjc4JiIjNjM0KicoRmt4tra2HhscMi8vXVtbACU5CwsLLisreJ+xKUhWBHS0gYCBOzg5fnx9YmBghIOD/NQBITlHgH9/PMPgWVdYJyQlMCwtESYyIx8gTUtLgoGBPV5qSUdH8m4jg4KCVVNTAA8XfHt7DwcCAAcLAHW4FRQV7+/vr6+vBAwOOLfSDzE4LZKoHmJwRkNEQj9APjs8CyUqCBgcMZ62i4qLj4+P42chfXx8aWdoDw4OUk9QZWNjNavExVkcAGahGlViKYaal0UWjo2NbWtsiYiI1GAfh4aH7McBfmoBl5eXlZWVk5KSn5+fdHNzpaWlnZ2dfn19cW9viD4UkI+Qjo2OeHd33boBnoUBATNQzawBjncBbl0AnuHw7/b63+/3EBcbFH256urqEkpq+vr6mZmZElJ1GhgYU1xeo6OjGG6fm5ubEh4jRVdejIuM9fX1lpWWnp2elJOTICcrnJuboaGhornEE3WtQU5Wv9HaJzg8h5icQZSmz9jeeo+XY2xucHd7EjtTkJ2iBwYGfYqNGV+HMTtAQoWr8/v9v8bIw8vNIi0yZHyHFygs////mvWEFwAAAQB0Uk5T////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AFP3ByUAAMcVSURBVHja7L3viyRnuf9f9CRCuhgLtAeTlj5TRcdTwSUkRo+bBDXG2SDoMIkubI/g8Sz4wBow5AdnzczAJsfAYGRXgo7MTPWjGA5pNAr7QEXQVNSQE9hnIsoiHvacj99z/oJ9dJ747brv+v2ju7q7qqa79/V6oMlmd3709vSrr+u+rvet/B0AAABqR+EhAAAAQMAAAAAIGAAAABAwAAAAAgYAAAAEDAAAgIABAAAAAQMAACBgAAAAQMAAAAAIGAAAAAEDAAAAAgaA6dE0zTkQKOqQhvzn4a92eGwAEDAAlE1bOzhQVd0YSVdVDhxMDICAAaCMktc5UC1jItTmQR8NAyBgAJjWvQOla0yLrjawMAACBoDJsPsNNb/CFTTNIfIfcytkqzlo82ACIGAAKFb5NjIKX0tVzIGmdXo5aFrf9XFGKdwcUAkDIGAAGE3HaaYKXsXU2r3CaI6ZKomtRp+HFgABA0CefQeJ0lc1+xOoN6bh5Pmxrjg2jzAAAgaAMfa1lMGU7g2wNTPekm46PMwACBgAIthON3Zs63R6JaGZsY+saDzYAAgYACR9JRqnYbZ75WL3lUiEh3XATBYAAgaAv9sHVrRJ3OlVQrsR/SyMZAEgYIDbHE2J2tfuVUjUwdYBE1kACBjg9sUJh6S6g06vcrSwF60rdKIBEDDAbYntWKEN272aiDi/yUAWAAIGuP30exAUo12nVyedRvCZVRQMgIABblf91lf8RsrgLgoGQMAAtyGBfnXT7p0KWhMFAyBggNuM4OzXck5Jv6ITHcxfNxnHAkDAAMuPFuq3d7qEClZYSgJAwADLTUedF/3GFKwf8FcDgIABlhf7YJ70G1OwxVEwAAIGWFb61imPXmUqWOUoGAABAywzgekac6RfMRHtLSXpA/6S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';\r\n","import { useState, useEffect, useRef } 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\nimport { MaintenanceScreen } from './MaintenanceScreen';\r\nimport { ErrorCode, getErrorFromHttpStatus, getErrorFromMessage } from './errors';\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(\r\n answer: unknown, \r\n questionType?: string, \r\n items?: string[], \r\n leftItems?: string[]\r\n): string {\r\n if (answer === null || answer === undefined) {\r\n return 'No answer';\r\n }\r\n \r\n // Handle sorting questions - convert indices to item labels\r\n if (questionType === 'sorting' && Array.isArray(answer)) {\r\n const indices = answer as number[];\r\n if (items && items.length > 0) {\r\n return indices.map((idx, pos) => `${pos + 1}. ${items[idx] ?? `Item ${idx + 1}`}`).join(', ');\r\n }\r\n // Fallback when items not available - just show position numbers\r\n return indices.map((idx, pos) => `Position ${pos + 1}: Item ${idx + 1}`).join(', ');\r\n }\r\n \r\n // Handle matrix/matching questions - show all left items with their matches\r\n if (questionType === 'matrix' && typeof answer === 'object' && !Array.isArray(answer)) {\r\n const matches = answer as Record<string, string>;\r\n // If we have leftItems, show all of them (including unmatched ones)\r\n if (leftItems && leftItems.length > 0) {\r\n return leftItems.map(left => {\r\n const right = matches[left];\r\n return `${left} → ${right || 'No answer'}`;\r\n }).join(', ');\r\n }\r\n // Fallback to just showing what was answered\r\n const entries = Object.entries(matches);\r\n if (entries.length === 0) {\r\n return 'No answer';\r\n }\r\n return entries.map(([left, right]) => `${left} → ${right || 'No answer'}`).join(', ');\r\n }\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\nfunction formatCorrectSortingAnswer(items: string[], correctOrder: number[]): string {\r\n return correctOrder.map((idx, pos) => `${pos + 1}. ${items[idx] ?? `Item ${idx + 1}`}`).join(', ');\r\n}\r\n\r\nfunction formatCorrectMatrixAnswer(correctMatches: Record<string, string>, leftItems?: string[]): string {\r\n if (leftItems && leftItems.length > 0) {\r\n return leftItems.map(left => `${left} → ${correctMatches[left] || 'N/A'}`).join(', ');\r\n }\r\n return Object.entries(correctMatches).map(([left, right]) => `${left} → ${right}`).join(', ');\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 [errorCode, setErrorCode] = useState<ErrorCode | 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 const [fetchedAttemptId, setFetchedAttemptId] = useState<string | null>(null);\r\n\r\n // Use ref for callback to avoid triggering re-fetches\r\n const onErrorRef = useRef(onError);\r\n onErrorRef.current = onError;\r\n\r\n useEffect(() => {\r\n // Only fetch once per attemptId - don't retry on error for same attemptId\r\n if (fetchedAttemptId === attemptId) return;\r\n\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 setErrorCode(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 const code = getErrorFromHttpStatus(response.status, 'attempt');\r\n setErrorCode(code);\r\n // Log error to tracking system\r\n apiClient.logError({\r\n errorCode: code,\r\n context: 'attempt',\r\n resourceId: attemptId,\r\n component: 'AttemptViewer',\r\n message: `HTTP ${response.status}: ${response.statusText}`,\r\n });\r\n onErrorRef.current?.(new Error(`Failed to fetch attempt: ${response.statusText}`));\r\n setLoading(false);\r\n setFetchedAttemptId(attemptId);\r\n return;\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 const code = getErrorFromMessage(errorMessage, 'attempt');\r\n setErrorCode(code);\r\n // Log error to tracking system\r\n apiClient.logError({\r\n errorCode: code,\r\n context: 'attempt',\r\n resourceId: attemptId,\r\n component: 'AttemptViewer',\r\n message: errorMessage,\r\n });\r\n onErrorRef.current?.(err instanceof Error ? err : new Error(errorMessage));\r\n } finally {\r\n setLoading(false);\r\n setFetchedAttemptId(attemptId);\r\n }\r\n }\r\n\r\n fetchAttempt();\r\n }, [attemptId, apiBaseUrl, authToken, showConversation, fetchedAttemptId]);\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 setErrorCode(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 (errorCode || !attempt) {\r\n return (\r\n <div style={defaultStyles.container} className={className}>\r\n <MaintenanceScreen errorCode={errorCode || 'ATTEMPT_NOT_FOUND'} />\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, answer.questionType, answer.items, answer.leftItems)}\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 {answer.questionType === 'sorting' && answer.items && answer.correctOrder\r\n ? formatCorrectSortingAnswer(answer.items, answer.correctOrder)\r\n : answer.questionType === 'matrix' && answer.correctAnswer && typeof answer.correctAnswer === 'object' && !Array.isArray(answer.correctAnswer)\r\n ? formatCorrectMatrixAnswer(answer.correctAnswer as Record<string, string>, answer.leftItems)\r\n : formatAnswer(answer.correctAnswer, answer.questionType, answer.items, answer.leftItems)}\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","import { ERROR_DEFINITIONS, ErrorCode } from './errors';\r\n\r\nconst panelStyles = {\r\n container: {\r\n fontFamily: 'system-ui, -apple-system, sans-serif',\r\n padding: '24px',\r\n backgroundColor: '#ffffff',\r\n borderRadius: '12px',\r\n maxWidth: '800px',\r\n },\r\n header: {\r\n marginBottom: '24px',\r\n },\r\n title: {\r\n fontSize: '20px',\r\n fontWeight: '600',\r\n color: '#111827',\r\n marginBottom: '8px',\r\n },\r\n subtitle: {\r\n fontSize: '14px',\r\n color: '#6b7280',\r\n },\r\n section: {\r\n marginBottom: '24px',\r\n },\r\n sectionTitle: {\r\n fontSize: '14px',\r\n fontWeight: '600',\r\n color: '#374151',\r\n marginBottom: '12px',\r\n textTransform: 'uppercase' as const,\r\n letterSpacing: '0.05em',\r\n },\r\n errorList: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '12px',\r\n },\r\n errorCard: {\r\n padding: '16px',\r\n backgroundColor: '#f9fafb',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n },\r\n errorCardBlocking: {\r\n borderLeft: '4px solid #ef4444',\r\n },\r\n errorCardNonBlocking: {\r\n borderLeft: '4px solid #f59e0b',\r\n },\r\n errorHeader: {\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n alignItems: 'flex-start',\r\n marginBottom: '8px',\r\n },\r\n errorCode: {\r\n fontSize: '13px',\r\n fontWeight: '600',\r\n color: '#1f2937',\r\n fontFamily: 'monospace',\r\n backgroundColor: '#e5e7eb',\r\n padding: '2px 8px',\r\n borderRadius: '4px',\r\n },\r\n errorBadge: {\r\n fontSize: '11px',\r\n fontWeight: '500',\r\n padding: '2px 8px',\r\n borderRadius: '12px',\r\n },\r\n blockingBadge: {\r\n backgroundColor: '#fee2e2',\r\n color: '#dc2626',\r\n },\r\n nonBlockingBadge: {\r\n backgroundColor: '#fef3c7',\r\n color: '#d97706',\r\n },\r\n userMessage: {\r\n fontSize: '15px',\r\n fontWeight: '500',\r\n color: '#111827',\r\n marginBottom: '4px',\r\n },\r\n subMessage: {\r\n fontSize: '13px',\r\n color: '#6b7280',\r\n marginBottom: '8px',\r\n },\r\n causeLabel: {\r\n fontSize: '11px',\r\n fontWeight: '600',\r\n color: '#9ca3af',\r\n textTransform: 'uppercase' as const,\r\n marginBottom: '4px',\r\n },\r\n causeText: {\r\n fontSize: '13px',\r\n color: '#4b5563',\r\n fontStyle: 'italic' as const,\r\n },\r\n};\r\n\r\ninterface ErrorTypesPanelProps {\r\n className?: string;\r\n}\r\n\r\nexport function ErrorTypesPanel({ className }: ErrorTypesPanelProps) {\r\n const blockingErrors = Object.values(ERROR_DEFINITIONS).filter(e => e.isBlocking);\r\n const nonBlockingErrors = Object.values(ERROR_DEFINITIONS).filter(e => !e.isBlocking);\r\n\r\n const renderErrorCard = (error: typeof ERROR_DEFINITIONS[ErrorCode]) => (\r\n <div\r\n key={error.code}\r\n style={{\r\n ...panelStyles.errorCard,\r\n ...(error.isBlocking ? panelStyles.errorCardBlocking : panelStyles.errorCardNonBlocking),\r\n }}\r\n data-testid={`error-card-${error.code}`}\r\n >\r\n <div style={panelStyles.errorHeader}>\r\n <code style={panelStyles.errorCode}>{error.code}</code>\r\n <span\r\n style={{\r\n ...panelStyles.errorBadge,\r\n ...(error.isBlocking ? panelStyles.blockingBadge : panelStyles.nonBlockingBadge),\r\n }}\r\n >\r\n {error.isBlocking ? 'Blocking' : 'Non-Blocking'}\r\n </span>\r\n </div>\r\n <div style={panelStyles.userMessage}>{error.userMessage}</div>\r\n <div style={panelStyles.subMessage}>{error.subMessage}</div>\r\n <div style={panelStyles.causeLabel}>Why this happens:</div>\r\n <div style={panelStyles.causeText}>{error.cause}</div>\r\n </div>\r\n );\r\n\r\n return (\r\n <div style={panelStyles.container} className={className} data-testid=\"error-types-panel\">\r\n <div style={panelStyles.header}>\r\n <h2 style={panelStyles.title}>Error Types Reference</h2>\r\n <p style={panelStyles.subtitle}>\r\n List of all error types that can occur in the quiz components, with user-facing messages and technical causes.\r\n </p>\r\n </div>\r\n\r\n <div style={panelStyles.section}>\r\n <h3 style={panelStyles.sectionTitle}>Blocking Errors ({blockingErrors.length})</h3>\r\n <p style={{ ...panelStyles.subtitle, marginBottom: '12px' }}>\r\n These errors prevent the quiz from loading or continuing. Users see a full-screen error message.\r\n </p>\r\n <div style={panelStyles.errorList}>\r\n {blockingErrors.map(renderErrorCard)}\r\n </div>\r\n </div>\r\n\r\n <div style={panelStyles.section}>\r\n <h3 style={panelStyles.sectionTitle}>Non-Blocking Errors ({nonBlockingErrors.length})</h3>\r\n <p style={{ ...panelStyles.subtitle, marginBottom: '12px' }}>\r\n These errors affect specific features but allow the quiz to continue. Users may see a toast notification.\r\n </p>\r\n <div style={panelStyles.errorList}>\r\n {nonBlockingErrors.map(renderErrorCard)}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect } from 'react';\r\nimport { ERROR_DEFINITIONS, ErrorCode } from './errors';\r\n\r\nexport interface ErrorLog {\r\n id: string;\r\n errorCode: string;\r\n context: 'quiz' | 'attempt';\r\n resourceId: string | null;\r\n component: 'QuizPlayer' | 'AttemptViewer';\r\n count: number;\r\n dismissed: number;\r\n lastMessage: string | null;\r\n firstSeenAt: string;\r\n lastSeenAt: string;\r\n}\r\n\r\nexport interface ErrorLogsPanelProps {\r\n apiBaseUrl: string;\r\n authToken?: string;\r\n onResourceClick?: (resourceId: string, context: 'quiz' | 'attempt') => void;\r\n}\r\n\r\nconst panelStyles = {\r\n container: {\r\n fontFamily: 'system-ui, -apple-system, sans-serif',\r\n padding: '24px',\r\n backgroundColor: '#ffffff',\r\n borderRadius: '12px',\r\n maxWidth: '1000px',\r\n },\r\n header: {\r\n marginBottom: '24px',\r\n },\r\n title: {\r\n fontSize: '20px',\r\n fontWeight: '600',\r\n color: '#111827',\r\n marginBottom: '8px',\r\n },\r\n subtitle: {\r\n fontSize: '14px',\r\n color: '#6b7280',\r\n },\r\n tabs: {\r\n display: 'flex',\r\n gap: '8px',\r\n marginBottom: '16px',\r\n borderBottom: '1px solid #e5e7eb',\r\n paddingBottom: '12px',\r\n },\r\n tab: {\r\n padding: '8px 16px',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n borderRadius: '6px',\r\n cursor: 'pointer',\r\n border: 'none',\r\n backgroundColor: 'transparent',\r\n color: '#6b7280',\r\n },\r\n tabActive: {\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n },\r\n stats: {\r\n display: 'flex',\r\n gap: '16px',\r\n marginBottom: '20px',\r\n },\r\n statCard: {\r\n padding: '12px 16px',\r\n backgroundColor: '#f9fafb',\r\n borderRadius: '8px',\r\n flex: 1,\r\n },\r\n statValue: {\r\n fontSize: '24px',\r\n fontWeight: '700',\r\n color: '#111827',\r\n },\r\n statLabel: {\r\n fontSize: '12px',\r\n color: '#6b7280',\r\n textTransform: 'uppercase' as const,\r\n letterSpacing: '0.05em',\r\n },\r\n errorList: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '12px',\r\n },\r\n errorCard: {\r\n padding: '16px',\r\n backgroundColor: '#f9fafb',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n },\r\n errorCardRecent: {\r\n borderLeft: '4px solid #ef4444',\r\n backgroundColor: '#fef2f2',\r\n },\r\n errorCardOld: {\r\n borderLeft: '4px solid #9ca3af',\r\n opacity: 0.7,\r\n },\r\n errorHeader: {\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n alignItems: 'flex-start',\r\n marginBottom: '8px',\r\n },\r\n errorLeft: {\r\n flex: 1,\r\n },\r\n errorCode: {\r\n fontSize: '13px',\r\n fontWeight: '600',\r\n color: '#1f2937',\r\n fontFamily: 'monospace',\r\n backgroundColor: '#e5e7eb',\r\n padding: '2px 8px',\r\n borderRadius: '4px',\r\n display: 'inline-block',\r\n },\r\n countBadge: {\r\n fontSize: '14px',\r\n fontWeight: '700',\r\n padding: '4px 12px',\r\n borderRadius: '16px',\r\n backgroundColor: '#ef4444',\r\n color: '#ffffff',\r\n },\r\n countBadgeLow: {\r\n backgroundColor: '#f59e0b',\r\n },\r\n contextBadge: {\r\n fontSize: '11px',\r\n fontWeight: '500',\r\n padding: '2px 8px',\r\n borderRadius: '4px',\r\n marginLeft: '8px',\r\n backgroundColor: '#dbeafe',\r\n color: '#1d4ed8',\r\n },\r\n userMessage: {\r\n fontSize: '15px',\r\n fontWeight: '500',\r\n color: '#111827',\r\n marginTop: '8px',\r\n marginBottom: '4px',\r\n },\r\n resourceId: {\r\n fontSize: '12px',\r\n color: '#6b7280',\r\n fontFamily: 'monospace',\r\n marginTop: '4px',\r\n },\r\n resourceLink: {\r\n color: '#6721b0',\r\n textDecoration: 'underline',\r\n cursor: 'pointer',\r\n },\r\n timestamps: {\r\n display: 'flex',\r\n gap: '16px',\r\n marginTop: '8px',\r\n fontSize: '12px',\r\n color: '#9ca3af',\r\n },\r\n dismissButton: {\r\n padding: '6px 12px',\r\n fontSize: '12px',\r\n fontWeight: '500',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n border: '1px solid #e5e7eb',\r\n backgroundColor: '#ffffff',\r\n color: '#6b7280',\r\n marginTop: '8px',\r\n },\r\n dismissButtonHover: {\r\n backgroundColor: '#f3f4f6',\r\n },\r\n emptyState: {\r\n textAlign: 'center' as const,\r\n padding: '40px',\r\n color: '#9ca3af',\r\n fontSize: '14px',\r\n },\r\n loading: {\r\n textAlign: 'center' as const,\r\n padding: '40px',\r\n color: '#6b7280',\r\n fontSize: '14px',\r\n },\r\n pagination: {\r\n display: 'flex',\r\n justifyContent: 'center',\r\n gap: '8px',\r\n marginTop: '20px',\r\n },\r\n pageButton: {\r\n padding: '8px 12px',\r\n fontSize: '14px',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n border: '1px solid #e5e7eb',\r\n backgroundColor: '#ffffff',\r\n color: '#374151',\r\n },\r\n pageButtonDisabled: {\r\n opacity: 0.5,\r\n cursor: 'not-allowed',\r\n },\r\n};\r\n\r\nfunction formatRelativeTime(dateStr: string): string {\r\n const date = new Date(dateStr);\r\n const now = new Date();\r\n const diffMs = now.getTime() - date.getTime();\r\n const diffMins = Math.floor(diffMs / 60000);\r\n const diffHours = Math.floor(diffMs / 3600000);\r\n const diffDays = Math.floor(diffMs / 86400000);\r\n\r\n if (diffMins < 1) return 'Just now';\r\n if (diffMins < 60) return `${diffMins}m ago`;\r\n if (diffHours < 24) return `${diffHours}h ago`;\r\n if (diffDays < 7) return `${diffDays}d ago`;\r\n return date.toLocaleDateString();\r\n}\r\n\r\nfunction isRecent(dateStr: string): boolean {\r\n const date = new Date(dateStr);\r\n const now = new Date();\r\n const diffMs = now.getTime() - date.getTime();\r\n const diffHours = diffMs / 3600000;\r\n return diffHours < 24;\r\n}\r\n\r\nexport function ErrorLogsPanel({ apiBaseUrl, authToken, onResourceClick }: ErrorLogsPanelProps) {\r\n const [logs, setLogs] = useState<ErrorLog[]>([]);\r\n const [loading, setLoading] = useState(true);\r\n const [showDismissed, setShowDismissed] = useState(false);\r\n const [page, setPage] = useState(1);\r\n const [totalPages, setTotalPages] = useState(1);\r\n const [total, setTotal] = useState(0);\r\n\r\n useEffect(() => {\r\n fetchLogs();\r\n }, [showDismissed, page]);\r\n\r\n async function fetchLogs() {\r\n setLoading(true);\r\n try {\r\n const params = new URLSearchParams();\r\n params.set('dismissed', showDismissed ? 'true' : 'false');\r\n params.set('page', page.toString());\r\n params.set('limit', '20');\r\n\r\n const response = await fetch(`${apiBaseUrl}/api/admin/error-logs?${params}`, {\r\n headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},\r\n });\r\n if (response.ok) {\r\n const data = await response.json();\r\n setLogs(data.items || []);\r\n setTotalPages(data.totalPages || 1);\r\n setTotal(data.total || 0);\r\n }\r\n } catch (err) {\r\n console.error('Failed to fetch error logs:', err);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }\r\n\r\n async function handleDismiss(id: string) {\r\n try {\r\n const response = await fetch(`${apiBaseUrl}/api/admin/error-logs/${id}/dismiss`, {\r\n method: 'PATCH',\r\n headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},\r\n });\r\n if (response.ok) {\r\n fetchLogs();\r\n }\r\n } catch (err) {\r\n console.error('Failed to dismiss error:', err);\r\n }\r\n }\r\n\r\n async function handleUndismiss(id: string) {\r\n try {\r\n const response = await fetch(`${apiBaseUrl}/api/admin/error-logs/${id}/undismiss`, {\r\n method: 'PATCH',\r\n headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},\r\n });\r\n if (response.ok) {\r\n fetchLogs();\r\n }\r\n } catch (err) {\r\n console.error('Failed to undismiss error:', err);\r\n }\r\n }\r\n\r\n function getErrorDefinition(code: string) {\r\n return ERROR_DEFINITIONS[code as ErrorCode];\r\n }\r\n\r\n const totalErrors = logs.reduce((sum, log) => sum + log.count, 0);\r\n const recentCount = logs.filter(log => isRecent(log.lastSeenAt)).length;\r\n\r\n return (\r\n <div style={panelStyles.container} data-testid=\"error-logs-panel\">\r\n <div style={panelStyles.header}>\r\n <h2 style={panelStyles.title}>Error Tracking</h2>\r\n <p style={panelStyles.subtitle}>\r\n Aggregated errors from QuizPlayer and AttemptViewer components, sorted by occurrence count\r\n </p>\r\n </div>\r\n\r\n <div style={panelStyles.tabs}>\r\n <button\r\n style={{\r\n ...panelStyles.tab,\r\n ...(showDismissed ? {} : panelStyles.tabActive),\r\n }}\r\n onClick={() => { setShowDismissed(false); setPage(1); }}\r\n data-testid=\"tab-active-errors\"\r\n >\r\n Active Errors\r\n </button>\r\n <button\r\n style={{\r\n ...panelStyles.tab,\r\n ...(showDismissed ? panelStyles.tabActive : {}),\r\n }}\r\n onClick={() => { setShowDismissed(true); setPage(1); }}\r\n data-testid=\"tab-dismissed-errors\"\r\n >\r\n Dismissed\r\n </button>\r\n </div>\r\n\r\n {!showDismissed && (\r\n <div style={panelStyles.stats}>\r\n <div style={panelStyles.statCard}>\r\n <div style={panelStyles.statValue}>{total}</div>\r\n <div style={panelStyles.statLabel}>Unique Errors</div>\r\n </div>\r\n <div style={panelStyles.statCard}>\r\n <div style={panelStyles.statValue}>{totalErrors}</div>\r\n <div style={panelStyles.statLabel}>Total Occurrences</div>\r\n </div>\r\n <div style={panelStyles.statCard}>\r\n <div style={{ ...panelStyles.statValue, color: recentCount > 0 ? '#ef4444' : '#22c55e' }}>\r\n {recentCount}\r\n </div>\r\n <div style={panelStyles.statLabel}>Last 24h</div>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {loading ? (\r\n <div style={panelStyles.loading}>Loading...</div>\r\n ) : logs.length === 0 ? (\r\n <div style={panelStyles.emptyState}>\r\n {showDismissed ? 'No dismissed errors' : 'No active errors'}\r\n </div>\r\n ) : (\r\n <div style={panelStyles.errorList}>\r\n {logs.map(log => {\r\n const def = getErrorDefinition(log.errorCode);\r\n const recent = isRecent(log.lastSeenAt);\r\n\r\n return (\r\n <div\r\n key={log.id}\r\n style={{\r\n ...panelStyles.errorCard,\r\n ...(recent ? panelStyles.errorCardRecent : panelStyles.errorCardOld),\r\n }}\r\n data-testid={`error-log-${log.id}`}\r\n >\r\n <div style={panelStyles.errorHeader}>\r\n <div style={panelStyles.errorLeft}>\r\n <span style={panelStyles.errorCode}>{log.errorCode}</span>\r\n <span style={panelStyles.contextBadge}>{log.context}</span>\r\n <span style={{ ...panelStyles.contextBadge, backgroundColor: '#f3e8ff', color: '#7c3aed' }}>\r\n {log.component}\r\n </span>\r\n </div>\r\n <span\r\n style={{\r\n ...panelStyles.countBadge,\r\n ...(log.count < 10 ? panelStyles.countBadgeLow : {}),\r\n }}\r\n >\r\n {log.count}x\r\n </span>\r\n </div>\r\n\r\n <div style={panelStyles.userMessage}>\r\n {def?.userMessage || log.lastMessage || 'Unknown error'}\r\n </div>\r\n\r\n {log.resourceId && (\r\n <div style={panelStyles.resourceId}>\r\n Resource:{' '}\r\n {onResourceClick ? (\r\n <span\r\n style={panelStyles.resourceLink}\r\n onClick={() => onResourceClick(log.resourceId!, log.context)}\r\n data-testid={`link-resource-${log.id}`}\r\n >\r\n {log.resourceId}\r\n </span>\r\n ) : (\r\n log.resourceId\r\n )}\r\n </div>\r\n )}\r\n\r\n <div style={panelStyles.timestamps}>\r\n <span>First: {formatRelativeTime(log.firstSeenAt)}</span>\r\n <span>Last: {formatRelativeTime(log.lastSeenAt)}</span>\r\n </div>\r\n\r\n <button\r\n style={panelStyles.dismissButton}\r\n onClick={() => showDismissed ? handleUndismiss(log.id) : handleDismiss(log.id)}\r\n data-testid={`button-dismiss-${log.id}`}\r\n >\r\n {showDismissed ? 'Restore' : 'Dismiss'}\r\n </button>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {totalPages > 1 && (\r\n <div style={panelStyles.pagination}>\r\n <button\r\n style={{\r\n ...panelStyles.pageButton,\r\n ...(page <= 1 ? panelStyles.pageButtonDisabled : {}),\r\n }}\r\n onClick={() => setPage(p => Math.max(1, p - 1))}\r\n disabled={page <= 1}\r\n data-testid=\"button-prev-page\"\r\n >\r\n Previous\r\n </button>\r\n <span style={{ padding: '8px 12px', color: '#6b7280' }}>\r\n Page {page} of {totalPages}\r\n </span>\r\n <button\r\n style={{\r\n ...panelStyles.pageButton,\r\n ...(page >= totalPages ? panelStyles.pageButtonDisabled : {}),\r\n }}\r\n onClick={() => setPage(p => Math.min(totalPages, p + 1))}\r\n disabled={page >= totalPages}\r\n data-testid=\"button-next-page\"\r\n >\r\n Next\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n"],"mappings":"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","names":["useState","useEffect","useCallback","useRef","useState","useEffect","useRef","jsx","jsxs","VolumeIcon","jsx","jsxs","Fragment","jsx","jsxs","useState","useRef","useEffect","useCallback","selectedAnswer","result","useState","useEffect","useRef","jsx","jsxs","defaultStyles","useState","useRef","useEffect","jsx","jsxs","panelStyles","useState","useEffect","jsx","jsxs","panelStyles","useState","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/QuizPlayer.tsx","../src/api.ts","../src/utils.ts","../src/TextToSpeech.tsx","../src/QuestionChatPanel.tsx","../src/errors.ts","../src/MaintenanceScreen.tsx","../src/assets/astronautData.ts","../src/AttemptViewer.tsx","../src/ErrorTypesPanel.tsx","../src/ErrorLogsPanel.tsx"],"sourcesContent":["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\nimport { MaintenanceScreen } from './MaintenanceScreen';\r\nimport { ErrorCode, getErrorFromMessage } from './errors';\r\nimport { astronautImage } from './assets/astronautData';\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 borderWidth: '2px',\r\n borderStyle: 'solid',\r\n borderColor: '#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 feedbackNeutral: {\r\n backgroundColor: '#f0f9ff',\r\n borderColor: '#0ea5e9',\r\n },\r\n feedbackTitleNeutral: {\r\n color: '#0369a1',\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// Sorting drag-and-drop component using HTML5 native drag and drop\r\ninterface SortingDragDropProps {\r\n items: string[];\r\n currentOrder: number[];\r\n correctOrder?: number[];\r\n showFeedback: boolean;\r\n onOrderChange: (newOrder: number[]) => void;\r\n}\r\n\r\nfunction SortingDragDrop({ items, currentOrder, correctOrder, showFeedback, onOrderChange }: SortingDragDropProps) {\r\n const [draggedIndex, setDraggedIndex] = useState<number | null>(null);\r\n const [dragOverIndex, setDragOverIndex] = useState<number | null>(null);\r\n\r\n const handleDragStart = (e: React.DragEvent, position: number) => {\r\n if (showFeedback) return;\r\n setDraggedIndex(position);\r\n e.dataTransfer.effectAllowed = 'move';\r\n e.dataTransfer.setData('text/plain', position.toString());\r\n };\r\n\r\n const handleDragOver = (e: React.DragEvent, position: number) => {\r\n e.preventDefault();\r\n if (showFeedback) return;\r\n e.dataTransfer.dropEffect = 'move';\r\n setDragOverIndex(position);\r\n };\r\n\r\n const handleDragLeave = () => {\r\n setDragOverIndex(null);\r\n };\r\n\r\n const handleDrop = (e: React.DragEvent, toPosition: number) => {\r\n e.preventDefault();\r\n if (showFeedback) return;\r\n const fromPosition = parseInt(e.dataTransfer.getData('text/plain'), 10);\r\n if (fromPosition !== toPosition) {\r\n const newOrder = [...currentOrder];\r\n const [movedItem] = newOrder.splice(fromPosition, 1);\r\n newOrder.splice(toPosition, 0, movedItem);\r\n onOrderChange(newOrder);\r\n }\r\n setDraggedIndex(null);\r\n setDragOverIndex(null);\r\n };\r\n\r\n const handleDragEnd = () => {\r\n setDraggedIndex(null);\r\n setDragOverIndex(null);\r\n };\r\n\r\n return (\r\n <div style={defaultStyles.options}>\r\n {currentOrder.map((itemIndex, position) => {\r\n const isCorrectPosition = correctOrder?.[position] === itemIndex;\r\n const isDragging = draggedIndex === position;\r\n const isDragOver = dragOverIndex === position;\r\n \r\n let itemStyle: React.CSSProperties = {\r\n ...defaultStyles.option,\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '12px',\r\n cursor: showFeedback ? 'default' : 'grab',\r\n opacity: isDragging ? 0.5 : 1,\r\n transition: 'all 0.2s ease',\r\n transform: isDragOver && !showFeedback ? 'scale(1.02)' : 'scale(1)',\r\n };\r\n \r\n if (showFeedback) {\r\n if (isCorrectPosition) {\r\n itemStyle = { ...itemStyle, ...defaultStyles.optionCorrect };\r\n } else {\r\n itemStyle = { ...itemStyle, ...defaultStyles.optionIncorrect };\r\n }\r\n } else if (isDragOver) {\r\n itemStyle = { ...itemStyle, borderColor: '#6366f1', backgroundColor: '#eef2ff' };\r\n }\r\n\r\n return (\r\n <div\r\n key={itemIndex}\r\n style={itemStyle}\r\n data-testid={`sorting-item-${position}`}\r\n draggable={!showFeedback}\r\n onDragStart={(e) => handleDragStart(e, position)}\r\n onDragOver={(e) => handleDragOver(e, position)}\r\n onDragLeave={handleDragLeave}\r\n onDrop={(e) => handleDrop(e, position)}\r\n onDragEnd={handleDragEnd}\r\n >\r\n {!showFeedback && (\r\n <div style={{ \r\n cursor: 'grab', \r\n padding: '4px',\r\n display: 'flex',\r\n alignItems: 'center',\r\n color: '#9ca3af',\r\n }}>\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <circle cx=\"9\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"19\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"19\" r=\"1\"/>\r\n </svg>\r\n </div>\r\n )}\r\n {showFeedback && (\r\n <div style={{ \r\n display: 'flex',\r\n alignItems: 'center',\r\n color: isCorrectPosition ? '#22c55e' : '#ef4444',\r\n }}>\r\n {isCorrectPosition ? (\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/>\r\n <polyline points=\"22 4 12 14.01 9 11.01\"/>\r\n </svg>\r\n ) : (\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\"/>\r\n <line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/>\r\n <line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\r\n </svg>\r\n )}\r\n </div>\r\n )}\r\n <span style={{ flex: 1 }}>{items[itemIndex]}</span>\r\n <span onClick={(e) => e.stopPropagation()}>\r\n <TextToSpeech text={items[itemIndex]} size=\"sm\" />\r\n </span>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n );\r\n}\r\n\r\n// Matching drag-and-drop component using HTML5 native drag and drop\r\ninterface MatchingDragDropProps {\r\n leftItems: string[];\r\n rightItems: string[];\r\n currentMatches: Record<string, string>;\r\n correctMatches?: Record<string, string>;\r\n showFeedback: boolean;\r\n onMatchChange: (newMatches: Record<string, string>) => void;\r\n}\r\n\r\nfunction MatchingDragDrop({ leftItems, rightItems, currentMatches, correctMatches, showFeedback, onMatchChange }: MatchingDragDropProps) {\r\n const [draggedItem, setDraggedItem] = useState<string | null>(null);\r\n const [dragOverLeft, setDragOverLeft] = useState<string | null>(null);\r\n\r\n // Get unmatched right items\r\n const matchedRightItems = Object.values(currentMatches);\r\n const unmatchedRightItems = rightItems.filter(item => !matchedRightItems.includes(item));\r\n\r\n const handleDragStart = (e: React.DragEvent, rightItem: string) => {\r\n if (showFeedback) return;\r\n setDraggedItem(rightItem);\r\n e.dataTransfer.effectAllowed = 'move';\r\n e.dataTransfer.setData('text/plain', rightItem);\r\n };\r\n\r\n const handleDragOver = (e: React.DragEvent, leftItem: string) => {\r\n e.preventDefault();\r\n if (showFeedback) return;\r\n e.dataTransfer.dropEffect = 'move';\r\n setDragOverLeft(leftItem);\r\n };\r\n\r\n const handleDragLeave = () => {\r\n setDragOverLeft(null);\r\n };\r\n\r\n const handleDrop = (e: React.DragEvent, leftItem: string) => {\r\n e.preventDefault();\r\n if (showFeedback) return;\r\n const rightItem = e.dataTransfer.getData('text/plain');\r\n if (rightItem) {\r\n // Remove the rightItem from any existing match\r\n const newMatches = { ...currentMatches };\r\n Object.keys(newMatches).forEach(key => {\r\n if (newMatches[key] === rightItem) {\r\n delete newMatches[key];\r\n }\r\n });\r\n // Assign to the new left item\r\n newMatches[leftItem] = rightItem;\r\n onMatchChange(newMatches);\r\n }\r\n setDraggedItem(null);\r\n setDragOverLeft(null);\r\n };\r\n\r\n const handleDragEnd = () => {\r\n setDraggedItem(null);\r\n setDragOverLeft(null);\r\n };\r\n\r\n const handleClearMatch = (leftItem: string) => {\r\n if (showFeedback) return;\r\n const newMatches = { ...currentMatches };\r\n delete newMatches[leftItem];\r\n onMatchChange(newMatches);\r\n };\r\n\r\n return (\r\n <div style={{ display: 'flex', gap: '24px', flexWrap: 'wrap' }}>\r\n {/* Left column - drop targets */}\r\n <div style={{ flex: 1, minWidth: '200px', display: 'flex', flexDirection: 'column', gap: '8px' }}>\r\n <div style={{ fontSize: '14px', fontWeight: '600', color: '#6b7280', marginBottom: '4px' }}>Match these items:</div>\r\n {leftItems.map((leftItem, idx) => {\r\n const matchedRight = currentMatches[leftItem];\r\n const correctMatch = correctMatches?.[leftItem];\r\n const isCorrect = matchedRight === correctMatch;\r\n const isDragOver = dragOverLeft === leftItem;\r\n\r\n let rowStyle: React.CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '12px',\r\n padding: '12px 16px',\r\n borderWidth: '2px',\r\n borderStyle: 'dashed',\r\n borderColor: '#e5e7eb',\r\n borderRadius: '8px',\r\n backgroundColor: '#ffffff',\r\n minHeight: '56px',\r\n transition: 'all 0.2s ease',\r\n };\r\n\r\n if (showFeedback) {\r\n rowStyle.borderStyle = 'solid';\r\n if (isCorrect) {\r\n rowStyle = { ...rowStyle, borderColor: '#22c55e', backgroundColor: '#f0fdf4' };\r\n } else {\r\n rowStyle = { ...rowStyle, borderColor: '#ef4444', backgroundColor: '#fef2f2' };\r\n }\r\n } else if (isDragOver) {\r\n rowStyle = { ...rowStyle, borderColor: '#6366f1', backgroundColor: '#eef2ff', borderStyle: 'solid' };\r\n } else if (matchedRight) {\r\n rowStyle = { ...rowStyle, borderStyle: 'solid', borderColor: '#22c55e' };\r\n }\r\n\r\n return (\r\n <div\r\n key={idx}\r\n style={rowStyle}\r\n data-testid={`matrix-row-${idx}`}\r\n onDragOver={(e) => handleDragOver(e, leftItem)}\r\n onDragLeave={handleDragLeave}\r\n onDrop={(e) => handleDrop(e, leftItem)}\r\n >\r\n <span style={{ flex: 1, fontWeight: '500' }}>{leftItem}</span>\r\n <span style={{ color: '#6b7280' }}>→</span>\r\n {matchedRight ? (\r\n <div style={{ \r\n display: 'flex', \r\n alignItems: 'center', \r\n gap: '8px', \r\n padding: '6px 12px',\r\n backgroundColor: showFeedback \r\n ? (isCorrect ? '#dcfce7' : '#fee2e2')\r\n : '#e0e7ff',\r\n borderRadius: '6px',\r\n fontSize: '14px',\r\n }}>\r\n <span>{matchedRight}</span>\r\n {!showFeedback && (\r\n <button\r\n onClick={() => handleClearMatch(leftItem)}\r\n style={{\r\n background: 'none',\r\n border: 'none',\r\n cursor: 'pointer',\r\n padding: '2px',\r\n display: 'flex',\r\n color: '#6b7280',\r\n }}\r\n aria-label=\"Remove match\"\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 <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n </button>\r\n )}\r\n {showFeedback && (\r\n isCorrect ? (\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#22c55e\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <polyline points=\"20 6 9 17 4 12\"/>\r\n </svg>\r\n ) : (\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#ef4444\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n )\r\n )}\r\n </div>\r\n ) : (\r\n <span style={{ color: '#9ca3af', fontSize: '14px', fontStyle: 'italic' }}>\r\n Drop here\r\n </span>\r\n )}\r\n {showFeedback && !isCorrect && correctMatch && (\r\n <span style={{ color: '#166534', fontSize: '13px', marginLeft: '8px' }}>\r\n (Correct: {correctMatch})\r\n </span>\r\n )}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n\r\n {/* Right column - draggable items */}\r\n <div style={{ flex: 1, minWidth: '200px', display: 'flex', flexDirection: 'column', gap: '8px' }}>\r\n <div style={{ fontSize: '14px', fontWeight: '600', color: '#6b7280', marginBottom: '4px' }}>Drag to match:</div>\r\n {unmatchedRightItems.length > 0 ? (\r\n unmatchedRightItems.map((rightItem, idx) => {\r\n const isDragging = draggedItem === rightItem;\r\n\r\n return (\r\n <div\r\n key={idx}\r\n style={{\r\n padding: '12px 16px',\r\n borderWidth: '2px',\r\n borderStyle: 'solid',\r\n borderColor: '#e5e7eb',\r\n borderRadius: '8px',\r\n backgroundColor: '#ffffff',\r\n cursor: showFeedback ? 'default' : 'grab',\r\n opacity: isDragging ? 0.5 : 1,\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '8px',\r\n transition: 'all 0.2s ease',\r\n }}\r\n draggable={!showFeedback}\r\n onDragStart={(e) => handleDragStart(e, rightItem)}\r\n onDragEnd={handleDragEnd}\r\n data-testid={`draggable-right-${idx}`}\r\n >\r\n {!showFeedback && (\r\n <div style={{ color: '#9ca3af', display: 'flex' }}>\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <circle cx=\"9\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"9\" cy=\"19\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"5\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"12\" r=\"1\"/>\r\n <circle cx=\"15\" cy=\"19\" r=\"1\"/>\r\n </svg>\r\n </div>\r\n )}\r\n <span style={{ flex: 1 }}>{rightItem}</span>\r\n </div>\r\n );\r\n })\r\n ) : (\r\n <div style={{ \r\n padding: '16px', \r\n textAlign: 'center', \r\n color: '#22c55e',\r\n fontSize: '14px',\r\n }}>\r\n All items matched!\r\n </div>\r\n )}\r\n </div>\r\n </div>\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 hideScore = false,\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 [errorCode, setErrorCode] = useState<ErrorCode | 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 [showResumeChoice, setShowResumeChoice] = useState(false);\r\n const [hasExistingProgress, setHasExistingProgress] = useState(false);\r\n const [existingProgressCount, setExistingProgressCount] = useState(0);\r\n const [isStartingFresh, setIsStartingFresh] = useState(false);\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 // Retry key - incrementing this triggers re-initialization\r\n const [retryKey, setRetryKey] = useState(0);\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 setErrorCode(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 // Check for existing progress when not forcing new attempt\r\n if (!forceNewAttempt && attemptData.answers && attemptData.answers.length > 0 && attemptData.status === 'in_progress') {\r\n // Mark that we have existing progress - will show choice screen\r\n setHasExistingProgress(true);\r\n setExistingProgressCount(attemptData.answers.length);\r\n setShowResumeChoice(true);\r\n // Pre-load the answers so \"Continue\" can use them\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 const code = getErrorFromMessage(message, 'quiz');\r\n setErrorCode(code);\r\n // Log error to tracking system\r\n apiClient.current?.logError({\r\n errorCode: code,\r\n context: 'quiz',\r\n resourceId: quizId,\r\n component: 'QuizPlayer',\r\n message,\r\n });\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, retryKey]);\r\n\r\n // Timer - only starts when timerStarted is true (after clicking Start)\r\n useEffect(() => {\r\n if (timerStarted && !isCompleted && !errorCode) {\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, errorCode]);\r\n\r\n // Handle start button click\r\n const handleStart = useCallback(() => {\r\n setShowIntro(false);\r\n setShowResumeChoice(false);\r\n setTimerStarted(true);\r\n }, []);\r\n\r\n // Handle \"Continue Where I Left Off\" - resume from existing progress\r\n const handleResumePrevious = useCallback(() => {\r\n // Find the first unanswered question index\r\n if (quiz && answers.size > 0) {\r\n const answeredIds = new Set(answers.keys());\r\n const allQs = [...quiz.questions, ...extraQuestions].filter(q => !skippedQuestionIds.has(q.id));\r\n let resumeIndex = 0;\r\n for (let i = 0; i < allQs.length; i++) {\r\n if (!answeredIds.has(allQs[i].id)) {\r\n resumeIndex = i;\r\n break;\r\n }\r\n // If all answered, go to last question\r\n resumeIndex = allQs.length - 1;\r\n }\r\n setCurrentQuestionIndex(resumeIndex);\r\n }\r\n setShowIntro(false);\r\n setShowResumeChoice(false);\r\n setTimerStarted(true);\r\n }, [quiz, answers, extraQuestions, skippedQuestionIds]);\r\n\r\n // Handle \"Start Fresh\" - abandon old attempt and create new one\r\n const handleStartFresh = useCallback(async () => {\r\n if (!apiClient.current || !attempt) return;\r\n \r\n setIsStartingFresh(true);\r\n try {\r\n // Abandon the current attempt\r\n await apiClient.current.updateAttempt(attempt.id, {\r\n status: 'abandoned'\r\n });\r\n\r\n // Create a fresh attempt\r\n const newAttemptData = 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: true,\r\n });\r\n \r\n // Reset all state\r\n setAttempt(newAttemptData);\r\n setAnswers(new Map());\r\n setAnswersDetail([]);\r\n setCurrentQuestionIndex(0);\r\n setHasExistingProgress(false);\r\n setExistingProgressCount(0);\r\n setShowResumeChoice(false);\r\n setShowIntro(false);\r\n setTimerStarted(true);\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : 'Failed to start fresh';\r\n onErrorRef.current?.(new Error(message));\r\n } finally {\r\n setIsStartingFresh(false);\r\n }\r\n }, [attempt, quizId, lessonId, assignLessonId, courseId, childId, parentId]);\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 const code = getErrorFromMessage(message, 'quiz');\r\n setErrorCode(code);\r\n // Log error to tracking system\r\n apiClient.current?.logError({\r\n errorCode: code,\r\n context: 'quiz',\r\n resourceId: quizId,\r\n component: 'QuizPlayer',\r\n message,\r\n });\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 // Handle retry quiz - reset all state to start fresh\r\n const handleRetryQuiz = useCallback(() => {\r\n // Reset quiz progress state\r\n setCurrentQuestionIndex(0);\r\n setAnswers(new Map());\r\n setAnswersDetail([]);\r\n setIsCompleted(false);\r\n setResult(null);\r\n setErrorCode(null);\r\n \r\n // Reset UI state\r\n setShowIntro(true);\r\n setShowFeedback(false);\r\n setCurrentAnswerDetail(null);\r\n \r\n // Reset timer\r\n setTimerStarted(false);\r\n setElapsedSeconds(0);\r\n startTimeRef.current = 0;\r\n \r\n // Clear dynamically added questions and skipped questions\r\n setExtraQuestions([]);\r\n setSkippedQuestionIds(new Set());\r\n \r\n // Clear attempt (new one will be created by initialize effect)\r\n setAttempt(null);\r\n \r\n // Reset resume choice state\r\n setShowResumeChoice(false);\r\n setHasExistingProgress(false);\r\n setExistingProgressCount(0);\r\n \r\n // Reset async flags\r\n setIsSubmitting(false);\r\n setIsNavigating(false);\r\n setIsGeneratingExtra(false);\r\n setIsStartingFresh(false);\r\n \r\n // Reset skip modal states\r\n setShowSkipModal(false);\r\n setIsSkipping(false);\r\n setSkipComment('');\r\n setSelectedSkipReason(null);\r\n \r\n // Reset report modal states\r\n setShowReportModal(false);\r\n setIsReporting(false);\r\n setReportComment('');\r\n \r\n // Trigger re-initialization to create new attempt\r\n setRetryKey(prev => prev + 1);\r\n }, []);\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 - show maintenance screen for server/connection errors\r\n if (errorCode) {\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <MaintenanceScreen errorCode={errorCode} />\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 component - astronaut on rocket image\r\n const Mascot = ({ mood }: { mood: string }) => {\r\n return (\r\n <img\r\n src={astronautImage}\r\n alt=\"Astronaut mascot\"\r\n width=\"180\"\r\n height=\"180\"\r\n style={{\r\n animation: mood === 'celebrating' ? 'bounce 0.6s ease-in-out infinite' : 'gentleBob 2s ease-in-out infinite',\r\n objectFit: 'contain',\r\n }}\r\n />\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 @keyframes buttonFadeIn {\r\n 0% {\r\n opacity: 0;\r\n transform: translateY(10px);\r\n }\r\n 100% {\r\n opacity: 1;\r\n transform: translateY(0);\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 {hideScore ? (\r\n <>\r\n {/* Simple success message when score is hidden */}\r\n <div style={{ marginBottom: '24px' }}>\r\n <Mascot mood=\"happy\" />\r\n </div>\r\n\r\n <div\r\n style={{\r\n background: 'linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%)',\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 #22c55e',\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 All Done!\r\n </span>\r\n </div>\r\n\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: '24px',\r\n fontWeight: '600',\r\n color: '#22c55e',\r\n lineHeight: '1.4',\r\n marginBottom: '12px',\r\n }}\r\n >\r\n The quiz was submitted successfully!\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 </>\r\n ) : (\r\n <>\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 <Mascot 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\r\n {/* Try Again Button */}\r\n <button\r\n style={{\r\n marginTop: '24px',\r\n padding: '14px 32px',\r\n fontSize: '16px',\r\n fontWeight: '600',\r\n color: '#7c3aed',\r\n background: 'white',\r\n border: '2px solid #7c3aed',\r\n borderRadius: '12px',\r\n cursor: 'pointer',\r\n transition: 'all 0.2s ease',\r\n animation: 'buttonFadeIn 0.5s ease-out 0.8s forwards',\r\n opacity: 0,\r\n }}\r\n onClick={handleRetryQuiz}\r\n onMouseOver={(e) => {\r\n e.currentTarget.style.background = '#7c3aed';\r\n e.currentTarget.style.color = 'white';\r\n e.currentTarget.style.transform = 'translateY(-2px)';\r\n }}\r\n onMouseOut={(e) => {\r\n e.currentTarget.style.background = 'white';\r\n e.currentTarget.style.color = '#7c3aed';\r\n e.currentTarget.style.transform = 'translateY(0)';\r\n }}\r\n data-testid=\"button-retry-quiz\"\r\n >\r\n Try Again\r\n </button>\r\n </>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n }\r\n\r\n // Render resume choice screen when there's an incomplete attempt\r\n if (quiz && showIntro && showResumeChoice && hasExistingProgress) {\r\n return (\r\n <div className={className} style={defaultStyles.container}>\r\n <div style={defaultStyles.intro}>\r\n <div style={defaultStyles.introTitle}>Welcome Back!</div>\r\n <div style={defaultStyles.introSubtitle}>\r\n You have an unfinished quiz. Would you like to continue or start over?\r\n </div>\r\n <div style={defaultStyles.introQuestionCount}>\r\n {existingProgressCount} of {quiz.questions.length} question{quiz.questions.length !== 1 ? 's' : ''} answered\r\n </div>\r\n <div style={{ display: 'flex', flexDirection: 'column', gap: '12px', marginTop: '8px' }}>\r\n <button\r\n style={defaultStyles.startButton}\r\n onClick={handleResumePrevious}\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-continue-quiz\"\r\n >\r\n Continue Where I Left Off\r\n </button>\r\n <button\r\n style={{\r\n ...defaultStyles.startButton,\r\n background: 'transparent',\r\n color: '#7c3aed',\r\n border: '2px solid #7c3aed',\r\n boxShadow: 'none',\r\n }}\r\n onClick={handleStartFresh}\r\n disabled={isStartingFresh}\r\n onMouseOver={(e) => {\r\n if (!isStartingFresh) {\r\n e.currentTarget.style.transform = 'translateY(-2px)';\r\n e.currentTarget.style.background = 'rgba(124, 58, 237, 0.1)';\r\n }\r\n }}\r\n onMouseOut={(e) => {\r\n e.currentTarget.style.transform = 'translateY(0)';\r\n e.currentTarget.style.background = 'transparent';\r\n }}\r\n data-testid=\"button-start-fresh\"\r\n >\r\n {isStartingFresh ? 'Starting...' : 'Start Fresh'}\r\n </button>\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 {/* CSS Reset for focus/active states on options */}\r\n <style>\r\n {`\r\n .quiz-option:focus,\r\n .quiz-option:active,\r\n .quiz-option:focus-visible,\r\n .quiz-option:focus-within {\r\n outline: none !important;\r\n box-shadow: none !important;\r\n }\r\n .quiz-option {\r\n -webkit-tap-highlight-color: transparent;\r\n }\r\n `}\r\n </style>\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 className=\"quiz-option\"\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 className=\"quiz-option\"\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 {/* Sorting question type with drag-and-drop */}\r\n {currentQuestion.type === 'sorting' && currentQuestion.items && (\r\n <SortingDragDrop\r\n items={currentQuestion.items}\r\n currentOrder={Array.isArray(selectedAnswer) ? (selectedAnswer as number[]) : currentQuestion.items.map((_, i) => i)}\r\n correctOrder={currentQuestion.correctOrder}\r\n showFeedback={showFeedback}\r\n onOrderChange={handleAnswerChange}\r\n />\r\n )}\r\n\r\n {/* Matrix/Matching question type with drag-and-drop */}\r\n {currentQuestion.type === 'matrix' && currentQuestion.leftItems && currentQuestion.rightItems && (\r\n <MatchingDragDrop\r\n leftItems={currentQuestion.leftItems}\r\n rightItems={currentQuestion.rightItems}\r\n currentMatches={(typeof selectedAnswer === 'object' && selectedAnswer !== null && !Array.isArray(selectedAnswer))\r\n ? (selectedAnswer as Record<string, string>)\r\n : {}}\r\n correctMatches={currentQuestion.correctMatches}\r\n showFeedback={showFeedback}\r\n onMatchChange={handleAnswerChange}\r\n />\r\n )}\r\n\r\n {/* Assessment question type */}\r\n {currentQuestion.type === 'assessment' && (\r\n <div style={defaultStyles.options}>\r\n {(() => {\r\n const scaleType = currentQuestion.scaleType || 'likert';\r\n \r\n if (scaleType === 'yes-no') {\r\n const options = ['Yes', 'No'];\r\n return options.map((option, idx) => {\r\n const isSelected = selectedAnswer === option;\r\n let optionStyle = { ...defaultStyles.option };\r\n if (isSelected) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };\r\n }\r\n return (\r\n <div\r\n key={idx}\r\n className=\"quiz-option\"\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 data-testid={`assessment-option-${option.toLowerCase()}`}\r\n >\r\n <span style={{ flex: 1 }}>{option}</span>\r\n </div>\r\n );\r\n });\r\n }\r\n \r\n if (scaleType === 'rating') {\r\n const min = currentQuestion.scaleMin || 1;\r\n const max = currentQuestion.scaleMax || 5;\r\n const ratings = Array.from({ length: max - min + 1 }, (_, i) => min + i);\r\n return (\r\n <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap', justifyContent: 'center' }}>\r\n {ratings.map((rating) => {\r\n const isSelected = selectedAnswer === rating;\r\n return (\r\n <button\r\n key={rating}\r\n className=\"quiz-option\"\r\n onClick={() => !showFeedback && handleAnswerChange(rating)}\r\n disabled={showFeedback}\r\n style={{\r\n width: '48px',\r\n height: '48px',\r\n borderRadius: '50%',\r\n border: isSelected ? '2px solid #6721b0' : '2px solid #e5e7eb',\r\n backgroundColor: isSelected ? '#f3e8ff' : '#ffffff',\r\n cursor: showFeedback ? 'not-allowed' : 'pointer',\r\n fontSize: '18px',\r\n fontWeight: '600',\r\n color: isSelected ? '#6721b0' : '#374151',\r\n outline: 'none',\r\n }}\r\n data-testid={`assessment-rating-${rating}`}\r\n >\r\n {rating}\r\n </button>\r\n );\r\n })}\r\n </div>\r\n );\r\n }\r\n \r\n // Default: Likert scale\r\n const likertOptions = [\r\n 'Strongly Disagree',\r\n 'Disagree',\r\n 'Neutral',\r\n 'Agree',\r\n 'Strongly Agree',\r\n ];\r\n return likertOptions.map((option, idx) => {\r\n const isSelected = selectedAnswer === option;\r\n let optionStyle = { ...defaultStyles.option };\r\n if (isSelected) {\r\n optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };\r\n }\r\n return (\r\n <div\r\n key={idx}\r\n className=\"quiz-option\"\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 data-testid={`assessment-likert-${idx}`}\r\n >\r\n <span style={{ flex: 1 }}>{option}</span>\r\n </div>\r\n );\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 ...(currentQuestion.type === 'assessment' \r\n ? defaultStyles.feedbackNeutral\r\n : currentAnswerDetail.isCorrect \r\n ? defaultStyles.feedbackCorrect \r\n : defaultStyles.feedbackIncorrect),\r\n }}>\r\n <div style={{\r\n ...defaultStyles.feedbackTitle,\r\n ...(currentQuestion.type === 'assessment'\r\n ? defaultStyles.feedbackTitleNeutral\r\n : currentAnswerDetail.isCorrect \r\n ? defaultStyles.feedbackTitleCorrect \r\n : defaultStyles.feedbackTitleIncorrect),\r\n }}>\r\n {currentQuestion.type === 'assessment' \r\n ? '✓ Response recorded' \r\n : currentAnswerDetail.isCorrect \r\n ? '✓ Correct!' \r\n : '✗ 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: currentQuestion.type !== 'assessment' && !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 async logError(params: {\r\n errorCode: string;\r\n context: 'quiz' | 'attempt';\r\n resourceId?: string;\r\n component: 'QuizPlayer' | 'AttemptViewer';\r\n message?: string;\r\n }): Promise<void> {\r\n try {\r\n await this.request<{ success: boolean }>('POST', '/api/external/log-error', params);\r\n } catch (e) {\r\n // Silently fail - we don't want error logging to break the user experience\r\n console.warn('[QuizEngine] Failed to log error:', e);\r\n }\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 // Essays require manual grading\r\n return { isCorrect: false, pointsEarned: 0 };\r\n\r\n case 'assessment':\r\n // Assessment/survey questions are opinion-based - always mark as correct\r\n return { isCorrect: true, pointsEarned: points };\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 const detail: QuizAnswerDetail = {\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 // Include type-specific fields for display purposes\r\n if (question.type === 'sorting') {\r\n detail.items = question.items;\r\n detail.correctOrder = question.correctOrder;\r\n } else if (question.type === 'matrix') {\r\n detail.leftItems = question.leftItems;\r\n detail.rightItems = question.rightItems;\r\n }\r\n\r\n return detail;\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","export type ErrorCode = \r\n | 'QUIZ_NOT_FOUND'\r\n | 'ATTEMPT_NOT_FOUND'\r\n | 'QUIZ_EXPIRED'\r\n | 'QUIZ_NOT_STARTED'\r\n | 'NETWORK_ERROR'\r\n | 'SERVER_ERROR'\r\n | 'UNAUTHORIZED'\r\n | 'FORBIDDEN'\r\n | 'TTS_FAILED'\r\n | 'CHAT_FAILED'\r\n | 'SUBMISSION_FAILED'\r\n | 'UNKNOWN_ERROR';\r\n\r\nexport interface ErrorDefinition {\r\n code: ErrorCode;\r\n userMessage: string;\r\n subMessage: string;\r\n cause: string;\r\n isBlocking: boolean;\r\n}\r\n\r\nexport const ERROR_DEFINITIONS: Record<ErrorCode, ErrorDefinition> = {\r\n QUIZ_NOT_FOUND: {\r\n code: 'QUIZ_NOT_FOUND',\r\n userMessage: \"We couldn't find this quiz\",\r\n subMessage: 'The quiz may have been removed or the link is incorrect.',\r\n cause: 'The quiz ID does not exist in the database, or the quiz has been deleted.',\r\n isBlocking: true,\r\n },\r\n ATTEMPT_NOT_FOUND: {\r\n code: 'ATTEMPT_NOT_FOUND',\r\n userMessage: \"We couldn't find this quiz attempt\",\r\n subMessage: 'The attempt may have expired or the link is incorrect.',\r\n cause: 'The attempt ID does not exist, or the attempt has been deleted/archived.',\r\n isBlocking: true,\r\n },\r\n QUIZ_EXPIRED: {\r\n code: 'QUIZ_EXPIRED',\r\n userMessage: 'This quiz has expired',\r\n subMessage: 'The deadline for this quiz has passed.',\r\n cause: 'The quiz end date/time has passed and submissions are no longer accepted.',\r\n isBlocking: true,\r\n },\r\n QUIZ_NOT_STARTED: {\r\n code: 'QUIZ_NOT_STARTED',\r\n userMessage: 'This quiz is not available yet',\r\n subMessage: 'Please check back when the quiz opens.',\r\n cause: 'The quiz start date/time has not yet been reached.',\r\n isBlocking: true,\r\n },\r\n NETWORK_ERROR: {\r\n code: 'NETWORK_ERROR',\r\n userMessage: 'Connection problem',\r\n subMessage: 'Please check your internet connection and try again.',\r\n cause: 'Unable to reach the server due to network connectivity issues.',\r\n isBlocking: true,\r\n },\r\n SERVER_ERROR: {\r\n code: 'SERVER_ERROR',\r\n userMessage: 'Something went wrong on our end',\r\n subMessage: 'Our team has been notified. Please try again later.',\r\n cause: 'The server encountered an internal error (HTTP 500+).',\r\n isBlocking: true,\r\n },\r\n UNAUTHORIZED: {\r\n code: 'UNAUTHORIZED',\r\n userMessage: 'Please sign in to continue',\r\n subMessage: 'You need to be logged in to access this quiz.',\r\n cause: 'The user is not authenticated (HTTP 401).',\r\n isBlocking: true,\r\n },\r\n FORBIDDEN: {\r\n code: 'FORBIDDEN',\r\n userMessage: \"You don't have access to this quiz\",\r\n subMessage: 'Contact your instructor if you believe this is a mistake.',\r\n cause: 'The user does not have permission to access this resource (HTTP 403).',\r\n isBlocking: true,\r\n },\r\n TTS_FAILED: {\r\n code: 'TTS_FAILED',\r\n userMessage: 'Text-to-speech unavailable',\r\n subMessage: 'Audio features are temporarily unavailable.',\r\n cause: 'The text-to-speech service failed or is unreachable.',\r\n isBlocking: false,\r\n },\r\n CHAT_FAILED: {\r\n code: 'CHAT_FAILED',\r\n userMessage: 'Chat assistance unavailable',\r\n subMessage: 'The AI helper is temporarily unavailable.',\r\n cause: 'The chat/AI service failed to initialize or respond.',\r\n isBlocking: false,\r\n },\r\n SUBMISSION_FAILED: {\r\n code: 'SUBMISSION_FAILED',\r\n userMessage: 'Failed to submit your answer',\r\n subMessage: 'Please try again. Your progress has been saved.',\r\n cause: 'The answer submission request failed due to network or server issues.',\r\n isBlocking: false,\r\n },\r\n UNKNOWN_ERROR: {\r\n code: 'UNKNOWN_ERROR',\r\n userMessage: 'Something unexpected happened',\r\n subMessage: 'Please try refreshing the page.',\r\n cause: 'An unclassified error occurred.',\r\n isBlocking: true,\r\n },\r\n};\r\n\r\nexport function getErrorFromHttpStatus(status: number, context?: 'quiz' | 'attempt'): ErrorCode {\r\n switch (status) {\r\n case 401:\r\n return 'UNAUTHORIZED';\r\n case 403:\r\n return 'FORBIDDEN';\r\n case 404:\r\n return context === 'attempt' ? 'ATTEMPT_NOT_FOUND' : 'QUIZ_NOT_FOUND';\r\n case 410:\r\n return 'QUIZ_EXPIRED';\r\n case 500:\r\n case 502:\r\n case 503:\r\n case 504:\r\n return 'SERVER_ERROR';\r\n default:\r\n if (status >= 400 && status < 500) {\r\n return context === 'attempt' ? 'ATTEMPT_NOT_FOUND' : 'QUIZ_NOT_FOUND';\r\n }\r\n return 'UNKNOWN_ERROR';\r\n }\r\n}\r\n\r\nexport function getErrorFromMessage(message: string, context?: 'quiz' | 'attempt'): ErrorCode {\r\n const lowerMessage = message.toLowerCase();\r\n \r\n if (lowerMessage.includes('network') || lowerMessage.includes('fetch') || lowerMessage.includes('connection')) {\r\n return 'NETWORK_ERROR';\r\n }\r\n if (lowerMessage.includes('not found') || lowerMessage.includes('404')) {\r\n return context === 'attempt' ? 'ATTEMPT_NOT_FOUND' : 'QUIZ_NOT_FOUND';\r\n }\r\n if (lowerMessage.includes('unauthorized') || lowerMessage.includes('401')) {\r\n return 'UNAUTHORIZED';\r\n }\r\n if (lowerMessage.includes('forbidden') || lowerMessage.includes('403')) {\r\n return 'FORBIDDEN';\r\n }\r\n if (lowerMessage.includes('expired')) {\r\n return 'QUIZ_EXPIRED';\r\n }\r\n if (lowerMessage.includes('tts') || lowerMessage.includes('speech')) {\r\n return 'TTS_FAILED';\r\n }\r\n if (lowerMessage.includes('chat')) {\r\n return 'CHAT_FAILED';\r\n }\r\n \r\n return 'UNKNOWN_ERROR';\r\n}\r\n","import { ErrorCode, ERROR_DEFINITIONS } from './errors';\r\n\r\ninterface MaintenanceScreenProps {\r\n errorCode?: ErrorCode;\r\n}\r\n\r\nexport function MaintenanceScreen({ errorCode }: MaintenanceScreenProps) {\r\n const errorDef = errorCode ? ERROR_DEFINITIONS[errorCode] : null;\r\n const message = errorDef?.userMessage || 'Your quiz is on its way...';\r\n const subMessage = errorDef?.subMessage || 'Please check back soon!';\r\n\r\n const containerStyle: React.CSSProperties = {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n minHeight: '300px',\r\n padding: '40px',\r\n background: 'linear-gradient(135deg, #f8f7ff 0%, #e8e4f8 50%, #f0ebff 100%)',\r\n borderRadius: '16px',\r\n };\r\n\r\n const iconStyle: React.CSSProperties = {\r\n fontSize: '48px',\r\n marginBottom: '24px',\r\n color: '#8b5cf6',\r\n };\r\n\r\n const messageStyle: React.CSSProperties = {\r\n fontSize: '20px',\r\n fontWeight: '600',\r\n color: '#4c1d95',\r\n textAlign: 'center',\r\n marginBottom: '12px',\r\n };\r\n\r\n const submessageStyle: React.CSSProperties = {\r\n fontSize: '14px',\r\n color: '#7c3aed',\r\n textAlign: 'center',\r\n opacity: 0.8,\r\n };\r\n\r\n return (\r\n <div style={containerStyle} data-testid=\"maintenance-screen\" data-error-code={errorCode || 'none'}>\r\n <div style={iconStyle}>\r\n <svg width=\"64\" height=\"64\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\r\n <path d=\"M12 8v4\" />\r\n <path d=\"M12 16h.01\" />\r\n </svg>\r\n </div>\r\n <div style={messageStyle} data-testid=\"text-error-message\">\r\n {message}\r\n </div>\r\n <div style={submessageStyle} data-testid=\"text-error-submessage\">\r\n {subMessage}\r\n </div>\r\n </div>\r\n );\r\n}\r\n","export const astronautImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB4AAAAQ4CAMAAADfDTFxAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAwBQTFRFYGBgsVEZcHBwq6urhYSEkZGRiomJuJsBMxoHJCAhUFBQQEBAXZu4ATtbnp6ev7+/dDURJnqMdnR1enl5ABoqAm2rVSYMamhpLCkqKCUlz8/PMS0uWksA39/fbmxtAViJEBAQAAAAzunzMDAwPDo6qKioj46OgICAoqKiOC8AOTU2oKCgaq3LNDExibbNQD4+mpqaV1RVRUJCZmRlpqampKSkSEVGlpaWUE5OTElKnJycIm5+mJiYXlxdf35+lJSUXFlaU1FSZGFiWFZWAV+UBGaebtLoWlhZqMjWTMjiS0hJc3FyAUlyidvtbGpraGZmb25ujYyMYF5ed3Z2F0lUFw4CAVB+////AUJnLCgpecXVKXyqfHp75eXlT0xN1dXVNzQ1hai8ksXZPzw9qNLlTn6UsOfywMDAICAgASxFwNzsEz1GgH5/R0RFJ1ZwOjc4JiIjNjM0KicoRmt4tra2HhscMi8vXVtbACU5CwsLLisreJ+xKUhWBHS0gYCBOzg5fnx9YmBghIOD/NQBITlHgH9/PMPgWVdYJyQlMCwtESYyIx8gTUtLgoGBPV5qSUdH8m4jg4KCVVNTAA8XfHt7DwcCAAcLAHW4FRQV7+/vr6+vBAwOOLfSDzE4LZKoHmJwRkNEQj9APjs8CyUqCBgcMZ62i4qLj4+P42chfXx8aWdoDw4OUk9QZWNjNavExVkcAGahGlViKYaal0UWjo2NbWtsiYiI1GAfh4aH7McBfmoBl5eXlZWVk5KSn5+fdHNzpaWlnZ2dfn19cW9viD4UkI+Qjo2OeHd33boBnoUBATNQzawBjncBbl0AnuHw7/b63+/3EBcbFH256urqEkpq+vr6mZmZElJ1GhgYU1xeo6OjGG6fm5ubEh4jRVdejIuM9fX1lpWWnp2elJOTICcrnJuboaGhornEE3WtQU5Wv9HaJzg8h5icQZSmz9jeeo+XY2xucHd7EjtTkJ2iBwYGfYqNGV+HMTtAQoWr8/v9v8bIw8vNIi0yZHyHFygs////mvWEFwAAAQB0Uk5T////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AFP3ByUAAMcVSURBVHja7L3viyRnuf9f9CRCuhgLtAeTlj5TRcdTwSUkRo+bBDXG2SDoMIkubI/g8Sz4wBow5AdnzczAJsfAYGRXgo7MTPWjGA5pNAr7QEXQVNSQE9hnIsoiHvacj99z/oJ9dJ747brv+v2ju7q7qqa79/V6oMlmd3709vSrr+u+rvet/B0AAABqR+EhAAAAQMAAAAAIGAAAABAwAAAAAgYAAAAEDAAAgIABAAAAAQMAACBgAAAAQMAAAAAIGAAAAAEDAAAAAgaA6dE0zTkQKOqQhvzn4a92eGwAEDAAlE1bOzhQVd0YSVdVDhxMDICAAaCMktc5UC1jItTmQR8NAyBgAJjWvQOla0yLrjawMAACBoDJsPsNNb/CFTTNIfIfcytkqzlo82ACIGAAKFb5NjIKX0tVzIGmdXo5aFrf9XFGKdwcUAkDIGAAGE3HaaYKXsXU2r3CaI6ZKomtRp+HFgABA0CefQeJ0lc1+xOoN6bh5Pmxrjg2jzAAAgaAMfa1lMGU7g2wNTPekm46PMwACBgAIthON3Zs63R6JaGZsY+saDzYAAgYACR9JRqnYbZ75WL3lUiEh3XATBYAAgaAv9sHVrRJ3OlVQrsR/SyMZAEgYIDbHE2J2tfuVUjUwdYBE1kACBjg9sUJh6S6g06vcrSwF60rdKIBEDDAbYntWKEN272aiDi/yUAWAAIGuP30exAUo12nVyedRvCZVRQMgIABblf91lf8RsrgLgoGQMAAtyGBfnXT7p0KWhMFAyBggNuM4OzXck5Jv6ITHcxfNxnHAkDAAMuPFuq3d7qEClZYSgJAwADLTUedF/3GFKwf8FcDgIABlhf7YJ70G1OwxVEwAAIGWFb61imPXmUqWOUoGAABAywzgekac6RfMRHtLSXpA/6S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';\r\n","import { useState, useEffect, useRef } 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\nimport { MaintenanceScreen } from './MaintenanceScreen';\r\nimport { ErrorCode, getErrorFromHttpStatus, getErrorFromMessage } from './errors';\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 backgroundColor: '#ffffff',\r\n padding: '16px',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n boxShadow: '0 1px 3px rgba(0, 0, 0, 0.05)',\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(\r\n answer: unknown, \r\n questionType?: string, \r\n items?: string[], \r\n leftItems?: string[]\r\n): string {\r\n if (answer === null || answer === undefined) {\r\n return 'No answer';\r\n }\r\n \r\n // Handle sorting questions - convert indices to item labels\r\n if (questionType === 'sorting' && Array.isArray(answer)) {\r\n const indices = answer as number[];\r\n if (items && items.length > 0) {\r\n return indices.map((idx, pos) => `${pos + 1}. ${items[idx] ?? `Item ${idx + 1}`}`).join(', ');\r\n }\r\n // Fallback when items not available - just show position numbers\r\n return indices.map((idx, pos) => `Position ${pos + 1}: Item ${idx + 1}`).join(', ');\r\n }\r\n \r\n // Handle matrix/matching questions - show all left items with their matches\r\n if (questionType === 'matrix' && typeof answer === 'object' && !Array.isArray(answer)) {\r\n const matches = answer as Record<string, string>;\r\n // If we have leftItems, show all of them (including unmatched ones)\r\n if (leftItems && leftItems.length > 0) {\r\n return leftItems.map(left => {\r\n const right = matches[left];\r\n return `${left} → ${right || 'No answer'}`;\r\n }).join(', ');\r\n }\r\n // Fallback to just showing what was answered\r\n const entries = Object.entries(matches);\r\n if (entries.length === 0) {\r\n return 'No answer';\r\n }\r\n return entries.map(([left, right]) => `${left} → ${right || 'No answer'}`).join(', ');\r\n }\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\nfunction formatCorrectSortingAnswer(items: string[], correctOrder: number[]): string {\r\n return correctOrder.map((idx, pos) => `${pos + 1}. ${items[idx] ?? `Item ${idx + 1}`}`).join(', ');\r\n}\r\n\r\nfunction formatCorrectMatrixAnswer(correctMatches: Record<string, string>, leftItems?: string[]): string {\r\n if (leftItems && leftItems.length > 0) {\r\n return leftItems.map(left => `${left} → ${correctMatches[left] || 'N/A'}`).join(', ');\r\n }\r\n return Object.entries(correctMatches).map(([left, right]) => `${left} → ${right}`).join(', ');\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 [errorCode, setErrorCode] = useState<ErrorCode | 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 const [fetchedAttemptId, setFetchedAttemptId] = useState<string | null>(null);\r\n\r\n // Use ref for callback to avoid triggering re-fetches\r\n const onErrorRef = useRef(onError);\r\n onErrorRef.current = onError;\r\n\r\n useEffect(() => {\r\n // Only fetch once per attemptId - don't retry on error for same attemptId\r\n if (fetchedAttemptId === attemptId) return;\r\n\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 setErrorCode(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 const code = getErrorFromHttpStatus(response.status, 'attempt');\r\n setErrorCode(code);\r\n // Log error to tracking system\r\n apiClient.logError({\r\n errorCode: code,\r\n context: 'attempt',\r\n resourceId: attemptId,\r\n component: 'AttemptViewer',\r\n message: `HTTP ${response.status}: ${response.statusText}`,\r\n });\r\n onErrorRef.current?.(new Error(`Failed to fetch attempt: ${response.statusText}`));\r\n setLoading(false);\r\n setFetchedAttemptId(attemptId);\r\n return;\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 const code = getErrorFromMessage(errorMessage, 'attempt');\r\n setErrorCode(code);\r\n // Log error to tracking system\r\n apiClient.logError({\r\n errorCode: code,\r\n context: 'attempt',\r\n resourceId: attemptId,\r\n component: 'AttemptViewer',\r\n message: errorMessage,\r\n });\r\n onErrorRef.current?.(err instanceof Error ? err : new Error(errorMessage));\r\n } finally {\r\n setLoading(false);\r\n setFetchedAttemptId(attemptId);\r\n }\r\n }\r\n\r\n fetchAttempt();\r\n }, [attemptId, apiBaseUrl, authToken, showConversation, fetchedAttemptId]);\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 setErrorCode(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 (errorCode || !attempt) {\r\n return (\r\n <div style={defaultStyles.container} className={className}>\r\n <MaintenanceScreen errorCode={errorCode || 'ATTEMPT_NOT_FOUND'} />\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, answer.questionType, answer.items, answer.leftItems)}\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 {answer.questionType === 'sorting' && answer.items && answer.correctOrder\r\n ? formatCorrectSortingAnswer(answer.items, answer.correctOrder)\r\n : answer.questionType === 'matrix' && answer.correctAnswer && typeof answer.correctAnswer === 'object' && !Array.isArray(answer.correctAnswer)\r\n ? formatCorrectMatrixAnswer(answer.correctAnswer as Record<string, string>, answer.leftItems)\r\n : formatAnswer(answer.correctAnswer, answer.questionType, answer.items, answer.leftItems)}\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","import { ERROR_DEFINITIONS, ErrorCode } from './errors';\r\n\r\nconst panelStyles = {\r\n container: {\r\n fontFamily: 'system-ui, -apple-system, sans-serif',\r\n padding: '24px',\r\n backgroundColor: '#ffffff',\r\n borderRadius: '12px',\r\n maxWidth: '800px',\r\n },\r\n header: {\r\n marginBottom: '24px',\r\n },\r\n title: {\r\n fontSize: '20px',\r\n fontWeight: '600',\r\n color: '#111827',\r\n marginBottom: '8px',\r\n },\r\n subtitle: {\r\n fontSize: '14px',\r\n color: '#6b7280',\r\n },\r\n section: {\r\n marginBottom: '24px',\r\n },\r\n sectionTitle: {\r\n fontSize: '14px',\r\n fontWeight: '600',\r\n color: '#374151',\r\n marginBottom: '12px',\r\n textTransform: 'uppercase' as const,\r\n letterSpacing: '0.05em',\r\n },\r\n errorList: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '12px',\r\n },\r\n errorCard: {\r\n padding: '16px',\r\n backgroundColor: '#f9fafb',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n },\r\n errorCardBlocking: {\r\n borderLeft: '4px solid #ef4444',\r\n },\r\n errorCardNonBlocking: {\r\n borderLeft: '4px solid #f59e0b',\r\n },\r\n errorHeader: {\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n alignItems: 'flex-start',\r\n marginBottom: '8px',\r\n },\r\n errorCode: {\r\n fontSize: '13px',\r\n fontWeight: '600',\r\n color: '#1f2937',\r\n fontFamily: 'monospace',\r\n backgroundColor: '#e5e7eb',\r\n padding: '2px 8px',\r\n borderRadius: '4px',\r\n },\r\n errorBadge: {\r\n fontSize: '11px',\r\n fontWeight: '500',\r\n padding: '2px 8px',\r\n borderRadius: '12px',\r\n },\r\n blockingBadge: {\r\n backgroundColor: '#fee2e2',\r\n color: '#dc2626',\r\n },\r\n nonBlockingBadge: {\r\n backgroundColor: '#fef3c7',\r\n color: '#d97706',\r\n },\r\n userMessage: {\r\n fontSize: '15px',\r\n fontWeight: '500',\r\n color: '#111827',\r\n marginBottom: '4px',\r\n },\r\n subMessage: {\r\n fontSize: '13px',\r\n color: '#6b7280',\r\n marginBottom: '8px',\r\n },\r\n causeLabel: {\r\n fontSize: '11px',\r\n fontWeight: '600',\r\n color: '#9ca3af',\r\n textTransform: 'uppercase' as const,\r\n marginBottom: '4px',\r\n },\r\n causeText: {\r\n fontSize: '13px',\r\n color: '#4b5563',\r\n fontStyle: 'italic' as const,\r\n },\r\n};\r\n\r\ninterface ErrorTypesPanelProps {\r\n className?: string;\r\n}\r\n\r\nexport function ErrorTypesPanel({ className }: ErrorTypesPanelProps) {\r\n const blockingErrors = Object.values(ERROR_DEFINITIONS).filter(e => e.isBlocking);\r\n const nonBlockingErrors = Object.values(ERROR_DEFINITIONS).filter(e => !e.isBlocking);\r\n\r\n const renderErrorCard = (error: typeof ERROR_DEFINITIONS[ErrorCode]) => (\r\n <div\r\n key={error.code}\r\n style={{\r\n ...panelStyles.errorCard,\r\n ...(error.isBlocking ? panelStyles.errorCardBlocking : panelStyles.errorCardNonBlocking),\r\n }}\r\n data-testid={`error-card-${error.code}`}\r\n >\r\n <div style={panelStyles.errorHeader}>\r\n <code style={panelStyles.errorCode}>{error.code}</code>\r\n <span\r\n style={{\r\n ...panelStyles.errorBadge,\r\n ...(error.isBlocking ? panelStyles.blockingBadge : panelStyles.nonBlockingBadge),\r\n }}\r\n >\r\n {error.isBlocking ? 'Blocking' : 'Non-Blocking'}\r\n </span>\r\n </div>\r\n <div style={panelStyles.userMessage}>{error.userMessage}</div>\r\n <div style={panelStyles.subMessage}>{error.subMessage}</div>\r\n <div style={panelStyles.causeLabel}>Why this happens:</div>\r\n <div style={panelStyles.causeText}>{error.cause}</div>\r\n </div>\r\n );\r\n\r\n return (\r\n <div style={panelStyles.container} className={className} data-testid=\"error-types-panel\">\r\n <div style={panelStyles.header}>\r\n <h2 style={panelStyles.title}>Error Types Reference</h2>\r\n <p style={panelStyles.subtitle}>\r\n List of all error types that can occur in the quiz components, with user-facing messages and technical causes.\r\n </p>\r\n </div>\r\n\r\n <div style={panelStyles.section}>\r\n <h3 style={panelStyles.sectionTitle}>Blocking Errors ({blockingErrors.length})</h3>\r\n <p style={{ ...panelStyles.subtitle, marginBottom: '12px' }}>\r\n These errors prevent the quiz from loading or continuing. Users see a full-screen error message.\r\n </p>\r\n <div style={panelStyles.errorList}>\r\n {blockingErrors.map(renderErrorCard)}\r\n </div>\r\n </div>\r\n\r\n <div style={panelStyles.section}>\r\n <h3 style={panelStyles.sectionTitle}>Non-Blocking Errors ({nonBlockingErrors.length})</h3>\r\n <p style={{ ...panelStyles.subtitle, marginBottom: '12px' }}>\r\n These errors affect specific features but allow the quiz to continue. Users may see a toast notification.\r\n </p>\r\n <div style={panelStyles.errorList}>\r\n {nonBlockingErrors.map(renderErrorCard)}\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { useState, useEffect } from 'react';\r\nimport { ERROR_DEFINITIONS, ErrorCode } from './errors';\r\n\r\nexport interface ErrorLog {\r\n id: string;\r\n errorCode: string;\r\n context: 'quiz' | 'attempt';\r\n resourceId: string | null;\r\n component: 'QuizPlayer' | 'AttemptViewer';\r\n count: number;\r\n dismissed: number;\r\n lastMessage: string | null;\r\n firstSeenAt: string;\r\n lastSeenAt: string;\r\n}\r\n\r\nexport interface ErrorLogsPanelProps {\r\n apiBaseUrl: string;\r\n authToken?: string;\r\n onResourceClick?: (resourceId: string, context: 'quiz' | 'attempt') => void;\r\n}\r\n\r\nconst panelStyles = {\r\n container: {\r\n fontFamily: 'system-ui, -apple-system, sans-serif',\r\n padding: '24px',\r\n backgroundColor: '#ffffff',\r\n borderRadius: '12px',\r\n maxWidth: '1000px',\r\n },\r\n header: {\r\n marginBottom: '24px',\r\n },\r\n title: {\r\n fontSize: '20px',\r\n fontWeight: '600',\r\n color: '#111827',\r\n marginBottom: '8px',\r\n },\r\n subtitle: {\r\n fontSize: '14px',\r\n color: '#6b7280',\r\n },\r\n tabs: {\r\n display: 'flex',\r\n gap: '8px',\r\n marginBottom: '16px',\r\n borderBottom: '1px solid #e5e7eb',\r\n paddingBottom: '12px',\r\n },\r\n tab: {\r\n padding: '8px 16px',\r\n fontSize: '14px',\r\n fontWeight: '500',\r\n borderRadius: '6px',\r\n cursor: 'pointer',\r\n border: 'none',\r\n backgroundColor: 'transparent',\r\n color: '#6b7280',\r\n },\r\n tabActive: {\r\n backgroundColor: '#6721b0',\r\n color: '#ffffff',\r\n },\r\n stats: {\r\n display: 'flex',\r\n gap: '16px',\r\n marginBottom: '20px',\r\n },\r\n statCard: {\r\n padding: '12px 16px',\r\n backgroundColor: '#f9fafb',\r\n borderRadius: '8px',\r\n flex: 1,\r\n },\r\n statValue: {\r\n fontSize: '24px',\r\n fontWeight: '700',\r\n color: '#111827',\r\n },\r\n statLabel: {\r\n fontSize: '12px',\r\n color: '#6b7280',\r\n textTransform: 'uppercase' as const,\r\n letterSpacing: '0.05em',\r\n },\r\n errorList: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n gap: '12px',\r\n },\r\n errorCard: {\r\n padding: '16px',\r\n backgroundColor: '#f9fafb',\r\n borderRadius: '8px',\r\n border: '1px solid #e5e7eb',\r\n },\r\n errorCardRecent: {\r\n borderLeft: '4px solid #ef4444',\r\n backgroundColor: '#fef2f2',\r\n },\r\n errorCardOld: {\r\n borderLeft: '4px solid #9ca3af',\r\n opacity: 0.7,\r\n },\r\n errorHeader: {\r\n display: 'flex',\r\n justifyContent: 'space-between',\r\n alignItems: 'flex-start',\r\n marginBottom: '8px',\r\n },\r\n errorLeft: {\r\n flex: 1,\r\n },\r\n errorCode: {\r\n fontSize: '13px',\r\n fontWeight: '600',\r\n color: '#1f2937',\r\n fontFamily: 'monospace',\r\n backgroundColor: '#e5e7eb',\r\n padding: '2px 8px',\r\n borderRadius: '4px',\r\n display: 'inline-block',\r\n },\r\n countBadge: {\r\n fontSize: '14px',\r\n fontWeight: '700',\r\n padding: '4px 12px',\r\n borderRadius: '16px',\r\n backgroundColor: '#ef4444',\r\n color: '#ffffff',\r\n },\r\n countBadgeLow: {\r\n backgroundColor: '#f59e0b',\r\n },\r\n contextBadge: {\r\n fontSize: '11px',\r\n fontWeight: '500',\r\n padding: '2px 8px',\r\n borderRadius: '4px',\r\n marginLeft: '8px',\r\n backgroundColor: '#dbeafe',\r\n color: '#1d4ed8',\r\n },\r\n userMessage: {\r\n fontSize: '15px',\r\n fontWeight: '500',\r\n color: '#111827',\r\n marginTop: '8px',\r\n marginBottom: '4px',\r\n },\r\n resourceId: {\r\n fontSize: '12px',\r\n color: '#6b7280',\r\n fontFamily: 'monospace',\r\n marginTop: '4px',\r\n },\r\n resourceLink: {\r\n color: '#6721b0',\r\n textDecoration: 'underline',\r\n cursor: 'pointer',\r\n },\r\n timestamps: {\r\n display: 'flex',\r\n gap: '16px',\r\n marginTop: '8px',\r\n fontSize: '12px',\r\n color: '#9ca3af',\r\n },\r\n dismissButton: {\r\n padding: '6px 12px',\r\n fontSize: '12px',\r\n fontWeight: '500',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n border: '1px solid #e5e7eb',\r\n backgroundColor: '#ffffff',\r\n color: '#6b7280',\r\n marginTop: '8px',\r\n },\r\n dismissButtonHover: {\r\n backgroundColor: '#f3f4f6',\r\n },\r\n emptyState: {\r\n textAlign: 'center' as const,\r\n padding: '40px',\r\n color: '#9ca3af',\r\n fontSize: '14px',\r\n },\r\n loading: {\r\n textAlign: 'center' as const,\r\n padding: '40px',\r\n color: '#6b7280',\r\n fontSize: '14px',\r\n },\r\n pagination: {\r\n display: 'flex',\r\n justifyContent: 'center',\r\n gap: '8px',\r\n marginTop: '20px',\r\n },\r\n pageButton: {\r\n padding: '8px 12px',\r\n fontSize: '14px',\r\n borderRadius: '4px',\r\n cursor: 'pointer',\r\n border: '1px solid #e5e7eb',\r\n backgroundColor: '#ffffff',\r\n color: '#374151',\r\n },\r\n pageButtonDisabled: {\r\n opacity: 0.5,\r\n cursor: 'not-allowed',\r\n },\r\n};\r\n\r\nfunction formatRelativeTime(dateStr: string): string {\r\n const date = new Date(dateStr);\r\n const now = new Date();\r\n const diffMs = now.getTime() - date.getTime();\r\n const diffMins = Math.floor(diffMs / 60000);\r\n const diffHours = Math.floor(diffMs / 3600000);\r\n const diffDays = Math.floor(diffMs / 86400000);\r\n\r\n if (diffMins < 1) return 'Just now';\r\n if (diffMins < 60) return `${diffMins}m ago`;\r\n if (diffHours < 24) return `${diffHours}h ago`;\r\n if (diffDays < 7) return `${diffDays}d ago`;\r\n return date.toLocaleDateString();\r\n}\r\n\r\nfunction isRecent(dateStr: string): boolean {\r\n const date = new Date(dateStr);\r\n const now = new Date();\r\n const diffMs = now.getTime() - date.getTime();\r\n const diffHours = diffMs / 3600000;\r\n return diffHours < 24;\r\n}\r\n\r\nexport function ErrorLogsPanel({ apiBaseUrl, authToken, onResourceClick }: ErrorLogsPanelProps) {\r\n const [logs, setLogs] = useState<ErrorLog[]>([]);\r\n const [loading, setLoading] = useState(true);\r\n const [showDismissed, setShowDismissed] = useState(false);\r\n const [page, setPage] = useState(1);\r\n const [totalPages, setTotalPages] = useState(1);\r\n const [total, setTotal] = useState(0);\r\n\r\n useEffect(() => {\r\n fetchLogs();\r\n }, [showDismissed, page]);\r\n\r\n async function fetchLogs() {\r\n setLoading(true);\r\n try {\r\n const params = new URLSearchParams();\r\n params.set('dismissed', showDismissed ? 'true' : 'false');\r\n params.set('page', page.toString());\r\n params.set('limit', '20');\r\n\r\n const response = await fetch(`${apiBaseUrl}/api/admin/error-logs?${params}`, {\r\n headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},\r\n });\r\n if (response.ok) {\r\n const data = await response.json();\r\n setLogs(data.items || []);\r\n setTotalPages(data.totalPages || 1);\r\n setTotal(data.total || 0);\r\n }\r\n } catch (err) {\r\n console.error('Failed to fetch error logs:', err);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }\r\n\r\n async function handleDismiss(id: string) {\r\n try {\r\n const response = await fetch(`${apiBaseUrl}/api/admin/error-logs/${id}/dismiss`, {\r\n method: 'PATCH',\r\n headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},\r\n });\r\n if (response.ok) {\r\n fetchLogs();\r\n }\r\n } catch (err) {\r\n console.error('Failed to dismiss error:', err);\r\n }\r\n }\r\n\r\n async function handleUndismiss(id: string) {\r\n try {\r\n const response = await fetch(`${apiBaseUrl}/api/admin/error-logs/${id}/undismiss`, {\r\n method: 'PATCH',\r\n headers: authToken ? { Authorization: `Bearer ${authToken}` } : {},\r\n });\r\n if (response.ok) {\r\n fetchLogs();\r\n }\r\n } catch (err) {\r\n console.error('Failed to undismiss error:', err);\r\n }\r\n }\r\n\r\n function getErrorDefinition(code: string) {\r\n return ERROR_DEFINITIONS[code as ErrorCode];\r\n }\r\n\r\n const totalErrors = logs.reduce((sum, log) => sum + log.count, 0);\r\n const recentCount = logs.filter(log => isRecent(log.lastSeenAt)).length;\r\n\r\n return (\r\n <div style={panelStyles.container} data-testid=\"error-logs-panel\">\r\n <div style={panelStyles.header}>\r\n <h2 style={panelStyles.title}>Error Tracking</h2>\r\n <p style={panelStyles.subtitle}>\r\n Aggregated errors from QuizPlayer and AttemptViewer components, sorted by occurrence count\r\n </p>\r\n </div>\r\n\r\n <div style={panelStyles.tabs}>\r\n <button\r\n style={{\r\n ...panelStyles.tab,\r\n ...(showDismissed ? {} : panelStyles.tabActive),\r\n }}\r\n onClick={() => { setShowDismissed(false); setPage(1); }}\r\n data-testid=\"tab-active-errors\"\r\n >\r\n Active Errors\r\n </button>\r\n <button\r\n style={{\r\n ...panelStyles.tab,\r\n ...(showDismissed ? panelStyles.tabActive : {}),\r\n }}\r\n onClick={() => { setShowDismissed(true); setPage(1); }}\r\n data-testid=\"tab-dismissed-errors\"\r\n >\r\n Dismissed\r\n </button>\r\n </div>\r\n\r\n {!showDismissed && (\r\n <div style={panelStyles.stats}>\r\n <div style={panelStyles.statCard}>\r\n <div style={panelStyles.statValue}>{total}</div>\r\n <div style={panelStyles.statLabel}>Unique Errors</div>\r\n </div>\r\n <div style={panelStyles.statCard}>\r\n <div style={panelStyles.statValue}>{totalErrors}</div>\r\n <div style={panelStyles.statLabel}>Total Occurrences</div>\r\n </div>\r\n <div style={panelStyles.statCard}>\r\n <div style={{ ...panelStyles.statValue, color: recentCount > 0 ? '#ef4444' : '#22c55e' }}>\r\n {recentCount}\r\n </div>\r\n <div style={panelStyles.statLabel}>Last 24h</div>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {loading ? (\r\n <div style={panelStyles.loading}>Loading...</div>\r\n ) : logs.length === 0 ? (\r\n <div style={panelStyles.emptyState}>\r\n {showDismissed ? 'No dismissed errors' : 'No active errors'}\r\n </div>\r\n ) : (\r\n <div style={panelStyles.errorList}>\r\n {logs.map(log => {\r\n const def = getErrorDefinition(log.errorCode);\r\n const recent = isRecent(log.lastSeenAt);\r\n\r\n return (\r\n <div\r\n key={log.id}\r\n style={{\r\n ...panelStyles.errorCard,\r\n ...(recent ? panelStyles.errorCardRecent : panelStyles.errorCardOld),\r\n }}\r\n data-testid={`error-log-${log.id}`}\r\n >\r\n <div style={panelStyles.errorHeader}>\r\n <div style={panelStyles.errorLeft}>\r\n <span style={panelStyles.errorCode}>{log.errorCode}</span>\r\n <span style={panelStyles.contextBadge}>{log.context}</span>\r\n <span style={{ ...panelStyles.contextBadge, backgroundColor: '#f3e8ff', color: '#7c3aed' }}>\r\n {log.component}\r\n </span>\r\n </div>\r\n <span\r\n style={{\r\n ...panelStyles.countBadge,\r\n ...(log.count < 10 ? panelStyles.countBadgeLow : {}),\r\n }}\r\n >\r\n {log.count}x\r\n </span>\r\n </div>\r\n\r\n <div style={panelStyles.userMessage}>\r\n {def?.userMessage || log.lastMessage || 'Unknown error'}\r\n </div>\r\n\r\n {log.resourceId && (\r\n <div style={panelStyles.resourceId}>\r\n Resource:{' '}\r\n {onResourceClick ? (\r\n <span\r\n style={panelStyles.resourceLink}\r\n onClick={() => onResourceClick(log.resourceId!, log.context)}\r\n data-testid={`link-resource-${log.id}`}\r\n >\r\n {log.resourceId}\r\n </span>\r\n ) : (\r\n log.resourceId\r\n )}\r\n </div>\r\n )}\r\n\r\n <div style={panelStyles.timestamps}>\r\n <span>First: {formatRelativeTime(log.firstSeenAt)}</span>\r\n <span>Last: {formatRelativeTime(log.lastSeenAt)}</span>\r\n </div>\r\n\r\n <button\r\n style={panelStyles.dismissButton}\r\n onClick={() => showDismissed ? handleUndismiss(log.id) : handleDismiss(log.id)}\r\n data-testid={`button-dismiss-${log.id}`}\r\n >\r\n {showDismissed ? 'Restore' : 'Dismiss'}\r\n </button>\r\n </div>\r\n );\r\n })}\r\n </div>\r\n )}\r\n\r\n {totalPages > 1 && (\r\n <div style={panelStyles.pagination}>\r\n <button\r\n style={{\r\n ...panelStyles.pageButton,\r\n ...(page <= 1 ? panelStyles.pageButtonDisabled : {}),\r\n }}\r\n onClick={() => setPage(p => Math.max(1, p - 1))}\r\n disabled={page <= 1}\r\n data-testid=\"button-prev-page\"\r\n >\r\n Previous\r\n </button>\r\n <span style={{ padding: '8px 12px', color: '#6b7280' }}>\r\n Page {page} of {totalPages}\r\n </span>\r\n <button\r\n style={{\r\n ...panelStyles.pageButton,\r\n ...(page >= totalPages ? panelStyles.pageButtonDisabled : {}),\r\n }}\r\n onClick={() => setPage(p => Math.min(totalPages, p + 1))}\r\n disabled={page >= totalPages}\r\n data-testid=\"button-next-page\"\r\n >\r\n Next\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n"],"mappings":"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","names":["useState","useEffect","useCallback","useRef","useState","useEffect","useRef","jsx","jsxs","VolumeIcon","jsx","jsxs","Fragment","jsx","jsxs","useState","useRef","useEffect","useCallback","selectedAnswer","result","useState","useEffect","useRef","jsx","jsxs","defaultStyles","useState","useRef","useEffect","jsx","jsxs","panelStyles","useState","useEffect","jsx","jsxs","panelStyles","useState","useEffect"]}
|