Spaces:
Runtime error
Runtime error
| import React, { useState, useEffect } from 'react' | |
| import QuestionPanel from './QuestionPanel' | |
| import SidebarPanel from './SidebarPanel' | |
| import { Clock, X } from 'lucide-react' | |
| export default function ExamInterface({ examType, questions, onEndExam }) { | |
| const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0) | |
| const [timeRemaining, setTimeRemaining] = useState(getBlockTime(examType)) | |
| const [answers, setAnswers] = useState({}) | |
| const [markedForReview, setMarkedForReview] = useState(new Set()) | |
| const [contrast, setContrast] = useState(100) | |
| const [showSettings, setShowSettings] = useState(false) | |
| function getBlockTime(type) { | |
| return type === 'step1' ? 30 * 60 : 40 * 60 | |
| } | |
| useEffect(() => { | |
| const timer = setInterval(() => { | |
| setTimeRemaining(prev => { | |
| if (prev <= 0) { | |
| clearInterval(timer) | |
| return 0 | |
| } | |
| return prev - 1 | |
| }) | |
| }, 1000) | |
| return () => clearInterval(timer) | |
| }, []) | |
| const handleAnswerSelect = (option) => { | |
| setAnswers({ | |
| ...answers, | |
| [currentQuestionIndex]: option | |
| }) | |
| } | |
| const handleMarkForReview = () => { | |
| const newSet = new Set(markedForReview) | |
| if (newSet.has(currentQuestionIndex)) { | |
| newSet.delete(currentQuestionIndex) | |
| } else { | |
| newSet.add(currentQuestionIndex) | |
| } | |
| setMarkedForReview(newSet) | |
| } | |
| const goToQuestion = (index) => { | |
| setCurrentQuestionIndex(index) | |
| } | |
| const goToPrevious = () => { | |
| if (currentQuestionIndex > 0) { | |
| setCurrentQuestionIndex(currentQuestionIndex - 1) | |
| } | |
| } | |
| const goToNext = () => { | |
| if (currentQuestionIndex < questions.length - 1) { | |
| setCurrentQuestionIndex(currentQuestionIndex + 1) | |
| } | |
| } | |
| const formatTime = (seconds) => { | |
| const mins = Math.floor(seconds / 60) | |
| const secs = seconds % 60 | |
| return `${mins}:${secs.toString().padStart(2, '0')}` | |
| } | |
| const currentQuestion = questions[currentQuestionIndex] | |
| const isAnswered = answers.hasOwnProperty(currentQuestionIndex) | |
| const isMarked = markedForReview.has(currentQuestionIndex) | |
| const answeredCount = Object.keys(answers).length | |
| const markedCount = markedForReview.size | |
| return ( | |
| <div className="exam-container"> | |
| {/* Header */} | |
| <div className="exam-header"> | |
| <div className="flex justify-between items-center max-w-7xl mx-auto w-full"> | |
| <div> | |
| <h1 className="text-2xl font-bold">USMLE {examType.toUpperCase()} Exam</h1> | |
| <p className="text-blue-200">Block {Math.floor(currentQuestionIndex / 20) + 1} of {Math.ceil(questions.length / 20)}</p> | |
| </div> | |
| <div className="flex items-center gap-6"> | |
| <div className="flex items-center gap-2 bg-white bg-opacity-20 px-4 py-2 rounded-lg"> | |
| <Clock className="w-5 h-5" /> | |
| <div> | |
| <div className="text-sm text-blue-200">Time Remaining</div> | |
| <div className="text-2xl font-bold">{formatTime(timeRemaining)}</div> | |
| </div> | |
| </div> | |
| <button | |
| onClick={onEndExam} | |
| className="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-lg flex items-center gap-2 transition-colors" | |
| > | |
| <X className="w-4 h-4" /> | |
| Exit Exam | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| {/* Main Content */} | |
| <div className="exam-content"> | |
| <QuestionPanel | |
| question={currentQuestion} | |
| questionNumber={currentQuestionIndex + 1} | |
| totalQuestions={questions.length} | |
| selectedAnswer={answers[currentQuestionIndex]} | |
| onAnswerSelect={handleAnswerSelect} | |
| onMarkForReview={handleMarkForReview} | |
| isMarked={isMarked} | |
| onPrevious={goToPrevious} | |
| onNext={goToNext} | |
| canGoPrevious={currentQuestionIndex > 0} | |
| canGoNext={currentQuestionIndex < questions.length - 1} | |
| contrast={contrast} | |
| /> | |
| <SidebarPanel | |
| totalQuestions={questions.length} | |
| currentQuestionIndex={currentQuestionIndex} | |
| answers={answers} | |
| markedForReview={markedForReview} | |
| onGoToQuestion={goToQuestion} | |
| answeredCount={answeredCount} | |
| markedCount={markedCount} | |
| contrast={contrast} | |
| onContrastChange={setContrast} | |
| /> | |
| </div> | |
| </div> | |
| ) | |
| } | |