1
1
import React , { useCallback , useEffect , useMemo , useState } from 'react' ;
2
2
import { AlertCircle , Brain , Github , Shield , Terminal , Volume2 , VolumeX , Zap } from 'lucide-react' ;
3
- import GameOver from './GameOver.tsx' ;
4
- import Completion from './Completion.tsx' ;
5
- import Context from './Context.tsx' ;
6
- import Answers from './Answers.tsx' ;
7
- import Result from './Result.tsx' ;
3
+ import GameOver from '@/components/Quiz/GameOver' ;
4
+ import Completion from '@/components/Quiz/Completion' ;
5
+ import Context from '@/components/Quiz/Context' ;
6
+ import Answers from '@/components/Quiz/Answers' ;
7
+ import Result from '@/components/Quiz/Result' ;
8
+ import LoadingScreen from '@/components/LoadingScreen' ;
8
9
import { Alert , AlertDescription , AlertTitle } from '@/components/ui/alert' ;
9
10
import { Button } from '@/components/ui/button' ;
10
11
import {
@@ -21,10 +22,11 @@ import {
21
22
TooltipProvider ,
22
23
TooltipTrigger ,
23
24
} from '@/components/ui/tooltip' ;
24
- import HealthBar from '@/components/HealthBar' ;
25
+ import HealthBar from '@/components/Quiz/ HealthBar' ;
25
26
import useSoundEffects from '@/hooks/useSoundEffects' ;
26
27
import type { ParsedQuestion } from '@/lib/markdownParser.ts' ;
27
28
import { loadAllQuestions } from '@/lib/markdownParser.ts' ;
29
+ import { isCorrectAnswer } from '@/lib/quiz-utils' ;
28
30
import { renderContent } from '@/components/RenderContent' ;
29
31
import { config } from '@/config' ;
30
32
import './styles.css' ;
@@ -58,13 +60,15 @@ const Quiz: React.FC = () => {
58
60
const [ isLoading , setIsLoading ] = useState ( true ) ;
59
61
const [ isAdditionalInformationOpen , setIsAdditionalInformationOpen ] = useState ( false ) ;
60
62
const [ timeRemaining , setTimeRemaining ] = useState < number | null > ( null ) ;
63
+ const [ isQuizComplete , setIsQuizComplete ] = useState ( false ) ;
61
64
62
65
const currentQuestion = useMemo ( ( ) => questions [ gameState . currentLevel ] , [ questions , gameState . currentLevel ] ) ;
66
+ const isLastQuestion = gameState . currentLevel === questions . length - 1 ;
63
67
64
68
const handleAnswer = useCallback ( ( selectedIndex : number ) => {
65
69
setSelectedAnswer ( selectedIndex ) ;
66
70
const currentQuestion = questions [ gameState . currentLevel ] ;
67
- const isCorrect = selectedIndex === currentQuestion . correctAnswer - 1 ;
71
+ const isCorrect = isCorrectAnswer ( currentQuestion , selectedIndex ) ;
68
72
const isTimedOut = selectedIndex === - 1 ;
69
73
70
74
setGameState ( ( prevState ) => {
@@ -89,7 +93,19 @@ const Quiz: React.FC = () => {
89
93
}
90
94
91
95
if ( isTimedOut ) {
92
- setSelectedAnswer ( currentQuestion . correctAnswer - 1 ) ;
96
+ // Handle timed out scenario for both single and multiple correct answers
97
+ if ( currentQuestion . correctAnswer !== undefined ) {
98
+ setSelectedAnswer ( currentQuestion . correctAnswer - 1 ) ;
99
+ }
100
+ else if ( currentQuestion . correctAnswers !== undefined && currentQuestion . correctAnswers . length > 0 ) {
101
+ // If multiple correct answers, select the first one
102
+ setSelectedAnswer ( currentQuestion . correctAnswers [ 0 ] - 1 ) ;
103
+ }
104
+ else {
105
+ // Fallback if no correct answer is defined (shouldn't happen, but just in case)
106
+ console . error ( 'No correct answer defined for the current question' ) ;
107
+ setSelectedAnswer ( null ) ;
108
+ }
93
109
}
94
110
} , [ gameState . currentLevel , questions , soundEnabled , playCorrectSound , playWrongSound ] ) ;
95
111
@@ -147,17 +163,22 @@ const Quiz: React.FC = () => {
147
163
if ( prevState . isCorrect && prevState . answeredWithoutHint ) {
148
164
newBadges . push ( `Level ${ prevState . currentLevel + 1 } Master` ) ;
149
165
}
166
+ const newLevel = prevState . currentLevel + 1 ;
167
+ if ( isLastQuestion ) {
168
+ setIsQuizComplete ( true ) ;
169
+ return prevState ; // Don't update the state if it's the last question
170
+ }
150
171
return {
151
172
...prevState ,
152
- currentLevel : prevState . currentLevel + 1 ,
173
+ currentLevel : newLevel ,
153
174
hintUsed : false ,
154
175
answerSelected : false ,
155
176
isCorrect : false ,
156
177
answeredWithoutHint : false ,
157
178
badges : newBadges ,
158
179
} ;
159
180
} ) ;
160
- } , [ ] ) ;
181
+ } , [ questions . length , isLastQuestion ] ) ;
161
182
162
183
const useHint = useCallback ( ( ) => {
163
184
setGameState ( prevState => ( { ...prevState , hintUsed : true } ) ) ;
@@ -174,6 +195,7 @@ const Quiz: React.FC = () => {
174
195
isCorrect : false ,
175
196
answeredWithoutHint : false ,
176
197
} ) ;
198
+ setIsQuizComplete ( false ) ;
177
199
} , [ ] ) ;
178
200
179
201
const toggleSound = useCallback ( ( ) => {
@@ -207,14 +229,14 @@ const Quiz: React.FC = () => {
207
229
} ;
208
230
209
231
if ( isLoading ) {
210
- return < div > Loading questions...</ div > ;
232
+ return < LoadingScreen message = " Loading questions..." / >;
211
233
}
212
234
213
235
if ( gameState . playerHealth <= 0 ) {
214
236
return < GameOver score = { gameState . score } badges = { gameState . badges } onReset = { resetGame } /> ;
215
237
}
216
238
217
- if ( gameState . currentLevel >= questions . length && questions . length > 0 ) {
239
+ if ( isQuizComplete ) {
218
240
return < Completion score = { gameState . score } badges = { gameState . badges } onReset = { resetGame } /> ;
219
241
}
220
242
@@ -308,17 +330,17 @@ const Quiz: React.FC = () => {
308
330
< Card className = "w-full max-w-4xl mt-4" >
309
331
< CardContent >
310
332
< Answers
311
- answers = { currentQuestion . answers }
333
+ question = { currentQuestion }
312
334
onAnswer = { handleAnswer }
313
335
disabled = { gameState . answerSelected }
314
336
selectedAnswer = { selectedAnswer }
315
- correctAnswer = { currentQuestion . correctAnswer }
316
337
answered = { gameState . answerSelected }
317
338
/>
318
339
{ gameState . answerSelected && (
319
340
< Result
320
- isCorrect = { gameState . isCorrect }
321
- explanation = { currentQuestion . explanation }
341
+ question = { currentQuestion }
342
+ selectedAnswer = { selectedAnswer }
343
+ isLastQuestion = { isLastQuestion }
322
344
onNext = { nextLevel }
323
345
/>
324
346
) }
0 commit comments