@schoolio/player 1.2.2 → 1.3.0
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.d.mts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +662 -97
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +663 -98
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -177,11 +177,11 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
177
177
|
var defaultStyles = {
|
|
178
178
|
container: {
|
|
179
179
|
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
180
|
-
|
|
181
|
-
margin: "0 auto",
|
|
180
|
+
width: "100%",
|
|
182
181
|
padding: "20px",
|
|
183
182
|
backgroundColor: "#ffffff",
|
|
184
|
-
borderRadius: "12px"
|
|
183
|
+
borderRadius: "12px",
|
|
184
|
+
boxSizing: "border-box"
|
|
185
185
|
},
|
|
186
186
|
header: {
|
|
187
187
|
marginBottom: "20px",
|
|
@@ -211,7 +211,8 @@ var defaultStyles = {
|
|
|
211
211
|
transition: "width 0.3s ease"
|
|
212
212
|
},
|
|
213
213
|
question: {
|
|
214
|
-
marginBottom: "24px"
|
|
214
|
+
marginBottom: "24px",
|
|
215
|
+
minHeight: "280px"
|
|
215
216
|
},
|
|
216
217
|
questionText: {
|
|
217
218
|
fontSize: "18px",
|
|
@@ -228,7 +229,9 @@ var defaultStyles = {
|
|
|
228
229
|
border: "2px solid #e5e7eb",
|
|
229
230
|
borderRadius: "8px",
|
|
230
231
|
cursor: "pointer",
|
|
231
|
-
transition: "all 0.2s ease"
|
|
232
|
+
transition: "all 0.2s ease",
|
|
233
|
+
outline: "none",
|
|
234
|
+
backgroundColor: "#ffffff"
|
|
232
235
|
},
|
|
233
236
|
optionSelected: {
|
|
234
237
|
borderColor: "#6721b0",
|
|
@@ -247,7 +250,10 @@ var defaultStyles = {
|
|
|
247
250
|
padding: "12px 16px",
|
|
248
251
|
border: "2px solid #e5e7eb",
|
|
249
252
|
borderRadius: "8px",
|
|
250
|
-
fontSize: "16px"
|
|
253
|
+
fontSize: "16px",
|
|
254
|
+
outline: "none",
|
|
255
|
+
boxSizing: "border-box",
|
|
256
|
+
backgroundColor: "#ffffff"
|
|
251
257
|
},
|
|
252
258
|
buttons: {
|
|
253
259
|
display: "flex",
|
|
@@ -276,24 +282,90 @@ var defaultStyles = {
|
|
|
276
282
|
color: "#9ca3af",
|
|
277
283
|
cursor: "not-allowed"
|
|
278
284
|
},
|
|
285
|
+
buttonAddMore: {
|
|
286
|
+
padding: "12px 24px",
|
|
287
|
+
borderRadius: "8px",
|
|
288
|
+
fontSize: "16px",
|
|
289
|
+
fontWeight: "500",
|
|
290
|
+
cursor: "pointer",
|
|
291
|
+
border: "2px solid #6721b0",
|
|
292
|
+
backgroundColor: "transparent",
|
|
293
|
+
color: "#6721b0",
|
|
294
|
+
transition: "all 0.2s ease",
|
|
295
|
+
display: "flex",
|
|
296
|
+
alignItems: "center",
|
|
297
|
+
justifyContent: "center",
|
|
298
|
+
gap: "8px"
|
|
299
|
+
},
|
|
300
|
+
buttonAddMoreDisabled: {
|
|
301
|
+
border: "2px solid #e5e7eb",
|
|
302
|
+
color: "#9ca3af",
|
|
303
|
+
cursor: "not-allowed"
|
|
304
|
+
},
|
|
305
|
+
buttonsColumn: {
|
|
306
|
+
display: "flex",
|
|
307
|
+
flexDirection: "column",
|
|
308
|
+
gap: "12px",
|
|
309
|
+
marginTop: "24px"
|
|
310
|
+
},
|
|
279
311
|
timer: {
|
|
280
312
|
fontSize: "14px",
|
|
281
313
|
color: "#6b7280",
|
|
282
314
|
marginLeft: "16px"
|
|
283
315
|
},
|
|
284
316
|
results: {
|
|
317
|
+
display: "flex",
|
|
318
|
+
flexDirection: "column",
|
|
319
|
+
alignItems: "center",
|
|
320
|
+
justifyContent: "center",
|
|
321
|
+
padding: "48px 24px",
|
|
285
322
|
textAlign: "center",
|
|
286
|
-
|
|
323
|
+
minHeight: "400px",
|
|
324
|
+
position: "relative",
|
|
325
|
+
overflow: "hidden"
|
|
287
326
|
},
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
327
|
+
resultsBackground: {
|
|
328
|
+
position: "absolute",
|
|
329
|
+
inset: "0",
|
|
330
|
+
borderRadius: "16px",
|
|
331
|
+
zIndex: 0
|
|
293
332
|
},
|
|
294
|
-
|
|
333
|
+
resultsContent: {
|
|
334
|
+
position: "relative",
|
|
335
|
+
zIndex: 1,
|
|
336
|
+
display: "flex",
|
|
337
|
+
flexDirection: "column",
|
|
338
|
+
alignItems: "center"
|
|
339
|
+
},
|
|
340
|
+
resultDetails: {
|
|
295
341
|
fontSize: "18px",
|
|
296
|
-
color: "#6b7280"
|
|
342
|
+
color: "#6b7280",
|
|
343
|
+
marginBottom: "4px"
|
|
344
|
+
},
|
|
345
|
+
resultStars: {
|
|
346
|
+
display: "flex",
|
|
347
|
+
justifyContent: "center",
|
|
348
|
+
gap: "8px",
|
|
349
|
+
marginBottom: "20px"
|
|
350
|
+
},
|
|
351
|
+
resultStar: {
|
|
352
|
+
fontSize: "32px",
|
|
353
|
+
animation: "starPop 0.5s ease-out forwards",
|
|
354
|
+
opacity: 0
|
|
355
|
+
},
|
|
356
|
+
confettiContainer: {
|
|
357
|
+
position: "absolute",
|
|
358
|
+
inset: "0",
|
|
359
|
+
pointerEvents: "none",
|
|
360
|
+
overflow: "hidden",
|
|
361
|
+
zIndex: 0
|
|
362
|
+
},
|
|
363
|
+
confettiPiece: {
|
|
364
|
+
position: "absolute",
|
|
365
|
+
width: "10px",
|
|
366
|
+
height: "10px",
|
|
367
|
+
top: "-10px",
|
|
368
|
+
animation: "confettiFall 3s ease-out forwards"
|
|
297
369
|
},
|
|
298
370
|
loading: {
|
|
299
371
|
textAlign: "center",
|
|
@@ -304,6 +376,80 @@ var defaultStyles = {
|
|
|
304
376
|
textAlign: "center",
|
|
305
377
|
padding: "40px",
|
|
306
378
|
color: "#ef4444"
|
|
379
|
+
},
|
|
380
|
+
intro: {
|
|
381
|
+
display: "flex",
|
|
382
|
+
flexDirection: "column",
|
|
383
|
+
alignItems: "center",
|
|
384
|
+
justifyContent: "center",
|
|
385
|
+
padding: "48px 24px",
|
|
386
|
+
textAlign: "center",
|
|
387
|
+
background: "linear-gradient(135deg, #f3e8ff 0%, #e0e7ff 50%, #fce7f3 100%)",
|
|
388
|
+
borderRadius: "16px",
|
|
389
|
+
minHeight: "320px"
|
|
390
|
+
},
|
|
391
|
+
introTitle: {
|
|
392
|
+
fontSize: "28px",
|
|
393
|
+
fontWeight: "700",
|
|
394
|
+
color: "#4c1d95",
|
|
395
|
+
marginBottom: "12px"
|
|
396
|
+
},
|
|
397
|
+
introSubtitle: {
|
|
398
|
+
fontSize: "16px",
|
|
399
|
+
color: "#6b7280",
|
|
400
|
+
marginBottom: "8px"
|
|
401
|
+
},
|
|
402
|
+
introQuestionCount: {
|
|
403
|
+
fontSize: "14px",
|
|
404
|
+
color: "#8b5cf6",
|
|
405
|
+
marginBottom: "32px",
|
|
406
|
+
fontWeight: "500"
|
|
407
|
+
},
|
|
408
|
+
startButton: {
|
|
409
|
+
padding: "16px 48px",
|
|
410
|
+
fontSize: "18px",
|
|
411
|
+
fontWeight: "600",
|
|
412
|
+
backgroundColor: "#7c3aed",
|
|
413
|
+
color: "#ffffff",
|
|
414
|
+
border: "none",
|
|
415
|
+
borderRadius: "12px",
|
|
416
|
+
cursor: "pointer",
|
|
417
|
+
transition: "all 0.2s ease",
|
|
418
|
+
boxShadow: "0 4px 14px rgba(124, 58, 237, 0.4)"
|
|
419
|
+
},
|
|
420
|
+
feedback: {
|
|
421
|
+
marginTop: "16px",
|
|
422
|
+
padding: "16px",
|
|
423
|
+
borderRadius: "8px",
|
|
424
|
+
backgroundColor: "#f9fafb",
|
|
425
|
+
border: "1px solid #e5e7eb"
|
|
426
|
+
},
|
|
427
|
+
feedbackCorrect: {
|
|
428
|
+
backgroundColor: "#f0fdf4",
|
|
429
|
+
borderColor: "#22c55e"
|
|
430
|
+
},
|
|
431
|
+
feedbackIncorrect: {
|
|
432
|
+
backgroundColor: "#fef2f2",
|
|
433
|
+
borderColor: "#ef4444"
|
|
434
|
+
},
|
|
435
|
+
feedbackTitle: {
|
|
436
|
+
fontSize: "16px",
|
|
437
|
+
fontWeight: "600",
|
|
438
|
+
marginBottom: "8px",
|
|
439
|
+
display: "flex",
|
|
440
|
+
alignItems: "center",
|
|
441
|
+
gap: "8px"
|
|
442
|
+
},
|
|
443
|
+
feedbackTitleCorrect: {
|
|
444
|
+
color: "#16a34a"
|
|
445
|
+
},
|
|
446
|
+
feedbackTitleIncorrect: {
|
|
447
|
+
color: "#dc2626"
|
|
448
|
+
},
|
|
449
|
+
feedbackExplanation: {
|
|
450
|
+
fontSize: "14px",
|
|
451
|
+
color: "#4b5563",
|
|
452
|
+
lineHeight: "1.5"
|
|
307
453
|
}
|
|
308
454
|
};
|
|
309
455
|
function Spinner({ size = 16, color = "#ffffff" }) {
|
|
@@ -335,6 +481,7 @@ function QuizPlayer({
|
|
|
335
481
|
onComplete,
|
|
336
482
|
onError,
|
|
337
483
|
onProgress,
|
|
484
|
+
onGenerateMoreQuestions,
|
|
338
485
|
className
|
|
339
486
|
}) {
|
|
340
487
|
const [quiz, setQuiz] = (0, import_react.useState)(null);
|
|
@@ -349,9 +496,15 @@ function QuizPlayer({
|
|
|
349
496
|
const [error, setError] = (0, import_react.useState)(null);
|
|
350
497
|
const [isLoading, setIsLoading] = (0, import_react.useState)(true);
|
|
351
498
|
const [elapsedSeconds, setElapsedSeconds] = (0, import_react.useState)(0);
|
|
499
|
+
const [showIntro, setShowIntro] = (0, import_react.useState)(true);
|
|
500
|
+
const [timerStarted, setTimerStarted] = (0, import_react.useState)(false);
|
|
501
|
+
const [showFeedback, setShowFeedback] = (0, import_react.useState)(false);
|
|
502
|
+
const [currentAnswerDetail, setCurrentAnswerDetail] = (0, import_react.useState)(null);
|
|
503
|
+
const [extraQuestions, setExtraQuestions] = (0, import_react.useState)([]);
|
|
504
|
+
const [isGeneratingExtra, setIsGeneratingExtra] = (0, import_react.useState)(false);
|
|
352
505
|
const apiClient = (0, import_react.useRef)(null);
|
|
353
506
|
const timerRef = (0, import_react.useRef)(null);
|
|
354
|
-
const startTimeRef = (0, import_react.useRef)(
|
|
507
|
+
const startTimeRef = (0, import_react.useRef)(0);
|
|
355
508
|
(0, import_react.useEffect)(() => {
|
|
356
509
|
apiClient.current = new QuizApiClient({ baseUrl: apiBaseUrl, authToken });
|
|
357
510
|
}, [apiBaseUrl, authToken]);
|
|
@@ -403,7 +556,7 @@ function QuizPlayer({
|
|
|
403
556
|
initialize();
|
|
404
557
|
}, [quizId, lessonId, assignLessonId, courseId, childId, parentId, onError]);
|
|
405
558
|
(0, import_react.useEffect)(() => {
|
|
406
|
-
if (
|
|
559
|
+
if (timerStarted && !isCompleted && !error) {
|
|
407
560
|
startTimeRef.current = Date.now();
|
|
408
561
|
timerRef.current = setInterval(() => {
|
|
409
562
|
setElapsedSeconds(Math.floor((Date.now() - startTimeRef.current) / 1e3));
|
|
@@ -414,27 +567,39 @@ function QuizPlayer({
|
|
|
414
567
|
clearInterval(timerRef.current);
|
|
415
568
|
}
|
|
416
569
|
};
|
|
417
|
-
}, [
|
|
570
|
+
}, [timerStarted, isCompleted, error]);
|
|
571
|
+
const handleStart = (0, import_react.useCallback)(() => {
|
|
572
|
+
setShowIntro(false);
|
|
573
|
+
setTimerStarted(true);
|
|
574
|
+
}, []);
|
|
575
|
+
(0, import_react.useEffect)(() => {
|
|
576
|
+
setShowFeedback(false);
|
|
577
|
+
setCurrentAnswerDetail(null);
|
|
578
|
+
}, [currentQuestionIndex]);
|
|
579
|
+
const allQuestions = quiz ? [...quiz.questions, ...extraQuestions] : [];
|
|
580
|
+
const totalQuestions = allQuestions.length;
|
|
581
|
+
const maxQuestions = 50;
|
|
418
582
|
(0, import_react.useEffect)(() => {
|
|
419
583
|
if (quiz && onProgress) {
|
|
420
584
|
onProgress({
|
|
421
585
|
currentQuestion: currentQuestionIndex + 1,
|
|
422
|
-
totalQuestions
|
|
586
|
+
totalQuestions,
|
|
423
587
|
answeredQuestions: answers.size
|
|
424
588
|
});
|
|
425
589
|
}
|
|
426
|
-
}, [currentQuestionIndex, answers.size, quiz, onProgress]);
|
|
427
|
-
const currentQuestion =
|
|
590
|
+
}, [currentQuestionIndex, answers.size, quiz, onProgress, totalQuestions]);
|
|
591
|
+
const currentQuestion = allQuestions[currentQuestionIndex];
|
|
428
592
|
const handleAnswerChange = (0, import_react.useCallback)((value) => {
|
|
429
593
|
if (!currentQuestion) return;
|
|
430
594
|
setAnswers((prev) => new Map(prev).set(currentQuestion.id, value));
|
|
431
595
|
}, [currentQuestion]);
|
|
432
|
-
const
|
|
596
|
+
const handleCheckAnswer = (0, import_react.useCallback)(async () => {
|
|
433
597
|
if (!quiz || !attempt || !currentQuestion || !apiClient.current) return;
|
|
434
598
|
const selectedAnswer2 = answers.get(currentQuestion.id);
|
|
435
599
|
if (selectedAnswer2 === void 0) return;
|
|
436
600
|
setIsNavigating(true);
|
|
437
601
|
const answerDetail = createAnswerDetail(currentQuestion, selectedAnswer2);
|
|
602
|
+
setCurrentAnswerDetail(answerDetail);
|
|
438
603
|
const newAnswersDetail = [...answersDetail];
|
|
439
604
|
const existingIdx = newAnswersDetail.findIndex((a) => a.questionId === currentQuestion.id);
|
|
440
605
|
if (existingIdx >= 0) {
|
|
@@ -452,15 +617,39 @@ function QuizPlayer({
|
|
|
452
617
|
} finally {
|
|
453
618
|
setIsNavigating(false);
|
|
454
619
|
}
|
|
455
|
-
|
|
620
|
+
setShowFeedback(true);
|
|
621
|
+
}, [quiz, attempt, currentQuestion, answers, answersDetail]);
|
|
622
|
+
const handleContinue = (0, import_react.useCallback)(() => {
|
|
623
|
+
if (!quiz) return;
|
|
624
|
+
setShowFeedback(false);
|
|
625
|
+
setCurrentAnswerDetail(null);
|
|
626
|
+
if (currentQuestionIndex < totalQuestions - 1) {
|
|
456
627
|
setCurrentQuestionIndex((prev) => prev + 1);
|
|
457
628
|
}
|
|
458
|
-
}, [quiz,
|
|
459
|
-
const
|
|
460
|
-
if (
|
|
461
|
-
|
|
629
|
+
}, [quiz, currentQuestionIndex, totalQuestions]);
|
|
630
|
+
const handleAddMoreQuestions = (0, import_react.useCallback)(async () => {
|
|
631
|
+
if (!attempt || !onGenerateMoreQuestions || isGeneratingExtra) return;
|
|
632
|
+
if (totalQuestions >= maxQuestions) return;
|
|
633
|
+
setIsGeneratingExtra(true);
|
|
634
|
+
try {
|
|
635
|
+
const result2 = await onGenerateMoreQuestions(attempt.id, totalQuestions);
|
|
636
|
+
if (result2.extraQuestions && result2.extraQuestions.length > 0) {
|
|
637
|
+
const slotsAvailable = maxQuestions - totalQuestions;
|
|
638
|
+
const questionsToAppend = result2.extraQuestions.slice(0, slotsAvailable);
|
|
639
|
+
if (questionsToAppend.length > 0) {
|
|
640
|
+
setExtraQuestions((prev) => [...prev, ...questionsToAppend]);
|
|
641
|
+
setCurrentQuestionIndex(totalQuestions);
|
|
642
|
+
setShowFeedback(false);
|
|
643
|
+
setCurrentAnswerDetail(null);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
} catch (err) {
|
|
647
|
+
console.error("Failed to generate extra questions:", err);
|
|
648
|
+
onError?.(err instanceof Error ? err : new Error("Failed to generate extra questions"));
|
|
649
|
+
} finally {
|
|
650
|
+
setIsGeneratingExtra(false);
|
|
462
651
|
}
|
|
463
|
-
}, [
|
|
652
|
+
}, [attempt, onGenerateMoreQuestions, isGeneratingExtra, totalQuestions, maxQuestions, onError]);
|
|
464
653
|
const handleSubmit = (0, import_react.useCallback)(async () => {
|
|
465
654
|
if (!quiz || !attempt || !apiClient.current) return;
|
|
466
655
|
setIsSubmitting(true);
|
|
@@ -477,7 +666,7 @@ function QuizPlayer({
|
|
|
477
666
|
}
|
|
478
667
|
}
|
|
479
668
|
const scoreData = calculateScore(finalAnswersDetail);
|
|
480
|
-
const timeSpent = Math.floor((Date.now() - startTimeRef.current) / 1e3);
|
|
669
|
+
const timeSpent = timerStarted && startTimeRef.current > 0 ? Math.floor((Date.now() - startTimeRef.current) / 1e3) : elapsedSeconds;
|
|
481
670
|
const updatedAttempt = await apiClient.current.updateAttempt(attempt.id, {
|
|
482
671
|
answers: finalAnswersDetail,
|
|
483
672
|
status: "completed",
|
|
@@ -490,7 +679,7 @@ function QuizPlayer({
|
|
|
490
679
|
attemptId: updatedAttempt.id,
|
|
491
680
|
score: scoreData.score,
|
|
492
681
|
correctAnswers: scoreData.correctAnswers,
|
|
493
|
-
totalQuestions
|
|
682
|
+
totalQuestions,
|
|
494
683
|
answers: finalAnswersDetail,
|
|
495
684
|
timeSpentSeconds: timeSpent
|
|
496
685
|
};
|
|
@@ -506,7 +695,7 @@ function QuizPlayer({
|
|
|
506
695
|
} finally {
|
|
507
696
|
setIsSubmitting(false);
|
|
508
697
|
}
|
|
509
|
-
}, [quiz, attempt, currentQuestion, answers, answersDetail, onComplete, onError]);
|
|
698
|
+
}, [quiz, attempt, currentQuestion, answers, answersDetail, onComplete, onError, totalQuestions, timerStarted, elapsedSeconds]);
|
|
510
699
|
if (isLoading) {
|
|
511
700
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.loading, children: "Loading quiz..." }) });
|
|
512
701
|
}
|
|
@@ -517,67 +706,403 @@ function QuizPlayer({
|
|
|
517
706
|
] }) }) });
|
|
518
707
|
}
|
|
519
708
|
if (isCompleted && result) {
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
709
|
+
const percentage = Math.round(result.correctAnswers / result.totalQuestions * 100);
|
|
710
|
+
const getScoreTheme = (pct) => {
|
|
711
|
+
if (pct >= 80) {
|
|
712
|
+
return {
|
|
713
|
+
color: "#22c55e",
|
|
714
|
+
bgGradient: "linear-gradient(135deg, #dcfce7 0%, #bbf7d0 50%, #86efac 100%)",
|
|
715
|
+
badge: "Quiz Champion!",
|
|
716
|
+
badgeColor: "#fbbf24",
|
|
717
|
+
badgeBg: "linear-gradient(135deg, #fef3c7 0%, #fde68a 100%)",
|
|
718
|
+
mascotMood: "celebrating",
|
|
719
|
+
stars: 3
|
|
720
|
+
};
|
|
721
|
+
} else if (pct >= 60) {
|
|
722
|
+
return {
|
|
723
|
+
color: "#f59e0b",
|
|
724
|
+
bgGradient: "linear-gradient(135deg, #fef3c7 0%, #fde68a 50%, #fcd34d 100%)",
|
|
725
|
+
badge: "Rising Star!",
|
|
726
|
+
badgeColor: "#f59e0b",
|
|
727
|
+
badgeBg: "linear-gradient(135deg, #fed7aa 0%, #fdba74 100%)",
|
|
728
|
+
mascotMood: "happy",
|
|
729
|
+
stars: 2
|
|
730
|
+
};
|
|
731
|
+
} else if (pct >= 40) {
|
|
732
|
+
return {
|
|
733
|
+
color: "#3b82f6",
|
|
734
|
+
bgGradient: "linear-gradient(135deg, #dbeafe 0%, #bfdbfe 50%, #93c5fd 100%)",
|
|
735
|
+
badge: "Great Learner!",
|
|
736
|
+
badgeColor: "#3b82f6",
|
|
737
|
+
badgeBg: "linear-gradient(135deg, #bfdbfe 0%, #93c5fd 100%)",
|
|
738
|
+
mascotMood: "encouraging",
|
|
739
|
+
stars: 1
|
|
740
|
+
};
|
|
741
|
+
} else {
|
|
742
|
+
return {
|
|
743
|
+
color: "#8b5cf6",
|
|
744
|
+
bgGradient: "linear-gradient(135deg, #f3e8ff 0%, #e9d5ff 50%, #d8b4fe 100%)",
|
|
745
|
+
badge: "Keep Growing!",
|
|
746
|
+
badgeColor: "#8b5cf6",
|
|
747
|
+
badgeBg: "linear-gradient(135deg, #e9d5ff 0%, #d8b4fe 100%)",
|
|
748
|
+
mascotMood: "supportive",
|
|
749
|
+
stars: 0
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
const theme = getScoreTheme(percentage);
|
|
754
|
+
const confettiColors = ["#f43f5e", "#ec4899", "#8b5cf6", "#3b82f6", "#22c55e", "#f59e0b", "#ef4444"];
|
|
755
|
+
const confettiPieces = Array.from({ length: 50 }, (_, i) => ({
|
|
756
|
+
id: i,
|
|
757
|
+
left: `${Math.random() * 100}%`,
|
|
758
|
+
delay: `${Math.random() * 2}s`,
|
|
759
|
+
duration: `${2 + Math.random() * 2}s`,
|
|
760
|
+
color: confettiColors[Math.floor(Math.random() * confettiColors.length)],
|
|
761
|
+
rotation: Math.random() * 360,
|
|
762
|
+
size: 6 + Math.random() * 8
|
|
763
|
+
}));
|
|
764
|
+
const StarIcon = ({ filled, delay }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
765
|
+
"svg",
|
|
766
|
+
{
|
|
767
|
+
width: "36",
|
|
768
|
+
height: "36",
|
|
769
|
+
viewBox: "0 0 24 24",
|
|
770
|
+
style: {
|
|
771
|
+
animation: "starPop 0.5s ease-out forwards",
|
|
772
|
+
animationDelay: `${delay}s`,
|
|
773
|
+
opacity: 0
|
|
774
|
+
},
|
|
775
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
776
|
+
"path",
|
|
777
|
+
{
|
|
778
|
+
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",
|
|
779
|
+
fill: filled ? "#fbbf24" : "#e5e7eb",
|
|
780
|
+
stroke: filled ? "#f59e0b" : "#d1d5db",
|
|
781
|
+
strokeWidth: "1"
|
|
782
|
+
}
|
|
783
|
+
)
|
|
784
|
+
}
|
|
785
|
+
);
|
|
786
|
+
const MascotOwl = ({ mood }) => {
|
|
787
|
+
const getEyeExpression = () => {
|
|
788
|
+
switch (mood) {
|
|
789
|
+
case "celebrating":
|
|
790
|
+
return { leftEye: ">", rightEye: "<", pupilY: 42 };
|
|
791
|
+
// Squinting happy
|
|
792
|
+
case "happy":
|
|
793
|
+
return { leftEye: null, rightEye: null, pupilY: 42 };
|
|
794
|
+
// Normal happy
|
|
795
|
+
case "encouraging":
|
|
796
|
+
return { leftEye: null, rightEye: null, pupilY: 44 };
|
|
797
|
+
// Looking down warmly
|
|
798
|
+
default:
|
|
799
|
+
return { leftEye: null, rightEye: null, pupilY: 42 };
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
const eyeExpr = getEyeExpression();
|
|
803
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
804
|
+
"svg",
|
|
805
|
+
{
|
|
806
|
+
width: "120",
|
|
807
|
+
height: "120",
|
|
808
|
+
viewBox: "0 0 100 100",
|
|
809
|
+
style: {
|
|
810
|
+
animation: mood === "celebrating" ? "bounce 0.6s ease-in-out infinite" : "gentleBob 2s ease-in-out infinite"
|
|
811
|
+
},
|
|
812
|
+
children: [
|
|
813
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "50", cy: "60", rx: "35", ry: "30", fill: "#8b5cf6" }),
|
|
814
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "50", cy: "65", rx: "25", ry: "20", fill: "#c4b5fd" }),
|
|
815
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "50", cy: "35", r: "28", fill: "#a78bfa" }),
|
|
816
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: "28,15 35,30 22,28", fill: "#7c3aed" }),
|
|
817
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: "72,15 65,30 78,28", fill: "#7c3aed" }),
|
|
818
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "38", cy: "38", rx: "10", ry: "12", fill: "white" }),
|
|
819
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "62", cy: "38", rx: "10", ry: "12", fill: "white" }),
|
|
820
|
+
eyeExpr.leftEye ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x: "38", y: "44", textAnchor: "middle", fontSize: "16", fill: "#1f2937", children: eyeExpr.leftEye }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "38", cy: eyeExpr.pupilY, r: "5", fill: "#1f2937" }),
|
|
821
|
+
eyeExpr.rightEye ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", { x: "62", y: "44", textAnchor: "middle", fontSize: "16", fill: "#1f2937", children: eyeExpr.rightEye }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "62", cy: eyeExpr.pupilY, r: "5", fill: "#1f2937" }),
|
|
822
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("polygon", { points: "50,45 45,52 55,52", fill: "#fbbf24" }),
|
|
823
|
+
(mood === "celebrating" || mood === "happy") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
824
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "28", cy: "45", rx: "5", ry: "3", fill: "#fda4af", opacity: "0.6" }),
|
|
825
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "72", cy: "45", rx: "5", ry: "3", fill: "#fda4af", opacity: "0.6" })
|
|
826
|
+
] }),
|
|
827
|
+
mood === "celebrating" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
828
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "18", cy: "55", rx: "8", ry: "15", fill: "#7c3aed", transform: "rotate(-30 18 55)" }),
|
|
829
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "82", cy: "55", rx: "8", ry: "15", fill: "#7c3aed", transform: "rotate(30 82 55)" })
|
|
830
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
831
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "20", cy: "60", rx: "8", ry: "15", fill: "#7c3aed" }),
|
|
832
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "80", cy: "60", rx: "8", ry: "15", fill: "#7c3aed" })
|
|
833
|
+
] }),
|
|
834
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "40", cy: "88", rx: "8", ry: "4", fill: "#fbbf24" }),
|
|
835
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ellipse", { cx: "60", cy: "88", rx: "8", ry: "4", fill: "#fbbf24" })
|
|
836
|
+
]
|
|
837
|
+
}
|
|
838
|
+
);
|
|
839
|
+
};
|
|
840
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className, style: defaultStyles.container, children: [
|
|
841
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
|
|
842
|
+
@keyframes confettiFall {
|
|
843
|
+
0% {
|
|
844
|
+
transform: translateY(-10px) rotate(0deg);
|
|
845
|
+
opacity: 1;
|
|
846
|
+
}
|
|
847
|
+
100% {
|
|
848
|
+
transform: translateY(500px) rotate(720deg);
|
|
849
|
+
opacity: 0;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
@keyframes starPop {
|
|
853
|
+
0% {
|
|
854
|
+
transform: scale(0);
|
|
855
|
+
opacity: 0;
|
|
856
|
+
}
|
|
857
|
+
50% {
|
|
858
|
+
transform: scale(1.3);
|
|
859
|
+
}
|
|
860
|
+
100% {
|
|
861
|
+
transform: scale(1);
|
|
862
|
+
opacity: 1;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
@keyframes bounce {
|
|
866
|
+
0%, 100% {
|
|
867
|
+
transform: translateY(0);
|
|
868
|
+
}
|
|
869
|
+
50% {
|
|
870
|
+
transform: translateY(-10px);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
@keyframes gentleBob {
|
|
874
|
+
0%, 100% {
|
|
875
|
+
transform: translateY(0);
|
|
876
|
+
}
|
|
877
|
+
50% {
|
|
878
|
+
transform: translateY(-5px);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
@keyframes badgePop {
|
|
882
|
+
0% {
|
|
883
|
+
transform: scale(0) rotate(-10deg);
|
|
884
|
+
opacity: 0;
|
|
885
|
+
}
|
|
886
|
+
60% {
|
|
887
|
+
transform: scale(1.1) rotate(5deg);
|
|
888
|
+
}
|
|
889
|
+
100% {
|
|
890
|
+
transform: scale(1) rotate(0deg);
|
|
891
|
+
opacity: 1;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
@keyframes scoreSlideIn {
|
|
895
|
+
0% {
|
|
896
|
+
transform: translateY(20px);
|
|
897
|
+
opacity: 0;
|
|
898
|
+
}
|
|
899
|
+
100% {
|
|
900
|
+
transform: translateY(0);
|
|
901
|
+
opacity: 1;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
` }),
|
|
905
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: defaultStyles.results, children: [
|
|
906
|
+
percentage >= 60 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.confettiContainer, children: confettiPieces.map((piece) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
907
|
+
"div",
|
|
908
|
+
{
|
|
909
|
+
style: {
|
|
910
|
+
...defaultStyles.confettiPiece,
|
|
911
|
+
left: piece.left,
|
|
912
|
+
width: `${piece.size}px`,
|
|
913
|
+
height: `${piece.size}px`,
|
|
914
|
+
backgroundColor: piece.color,
|
|
915
|
+
borderRadius: Math.random() > 0.5 ? "50%" : "2px",
|
|
916
|
+
animationDelay: piece.delay,
|
|
917
|
+
animationDuration: piece.duration,
|
|
918
|
+
transform: `rotate(${piece.rotation}deg)`
|
|
919
|
+
}
|
|
920
|
+
},
|
|
921
|
+
piece.id
|
|
922
|
+
)) }),
|
|
923
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...defaultStyles.resultsBackground, background: theme.bgGradient } }),
|
|
924
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: defaultStyles.resultsContent, children: [
|
|
925
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: defaultStyles.resultStars, children: [
|
|
926
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StarIcon, { filled: theme.stars >= 1, delay: 0.3 }),
|
|
927
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StarIcon, { filled: theme.stars >= 2, delay: 0.5 }),
|
|
928
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StarIcon, { filled: theme.stars >= 3, delay: 0.7 })
|
|
929
|
+
] }),
|
|
930
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginBottom: "16px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MascotOwl, { mood: theme.mascotMood }) }),
|
|
931
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
932
|
+
"div",
|
|
933
|
+
{
|
|
934
|
+
style: {
|
|
935
|
+
background: theme.badgeBg,
|
|
936
|
+
padding: "12px 28px",
|
|
937
|
+
borderRadius: "50px",
|
|
938
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
|
|
939
|
+
marginBottom: "20px",
|
|
940
|
+
animation: "badgePop 0.6s ease-out 0.2s forwards",
|
|
941
|
+
opacity: 0,
|
|
942
|
+
border: `3px solid ${theme.badgeColor}`
|
|
943
|
+
},
|
|
944
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
945
|
+
"span",
|
|
946
|
+
{
|
|
947
|
+
style: {
|
|
948
|
+
fontSize: "22px",
|
|
949
|
+
fontWeight: "700",
|
|
950
|
+
color: "#1f2937",
|
|
951
|
+
textShadow: "0 1px 2px rgba(255,255,255,0.5)"
|
|
952
|
+
},
|
|
953
|
+
children: theme.badge
|
|
954
|
+
}
|
|
955
|
+
)
|
|
956
|
+
}
|
|
957
|
+
),
|
|
958
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
959
|
+
"div",
|
|
960
|
+
{
|
|
961
|
+
style: {
|
|
962
|
+
animation: "scoreSlideIn 0.5s ease-out 0.4s forwards",
|
|
963
|
+
opacity: 0
|
|
964
|
+
},
|
|
965
|
+
children: [
|
|
966
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
967
|
+
"div",
|
|
968
|
+
{
|
|
969
|
+
style: {
|
|
970
|
+
fontSize: "48px",
|
|
971
|
+
fontWeight: "800",
|
|
972
|
+
color: theme.color,
|
|
973
|
+
lineHeight: "1",
|
|
974
|
+
marginBottom: "4px"
|
|
975
|
+
},
|
|
976
|
+
children: [
|
|
977
|
+
result.correctAnswers,
|
|
978
|
+
" of ",
|
|
979
|
+
result.totalQuestions
|
|
980
|
+
]
|
|
981
|
+
}
|
|
982
|
+
),
|
|
983
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
984
|
+
"div",
|
|
985
|
+
{
|
|
986
|
+
style: {
|
|
987
|
+
fontSize: "20px",
|
|
988
|
+
fontWeight: "600",
|
|
989
|
+
color: "#6b7280",
|
|
990
|
+
marginBottom: "12px"
|
|
991
|
+
},
|
|
992
|
+
children: "correct answers"
|
|
993
|
+
}
|
|
994
|
+
)
|
|
995
|
+
]
|
|
996
|
+
}
|
|
997
|
+
),
|
|
998
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...defaultStyles.resultDetails, marginTop: "8px" }, children: [
|
|
999
|
+
"Time: ",
|
|
1000
|
+
formatTime(result.timeSpentSeconds)
|
|
1001
|
+
] })
|
|
1002
|
+
] })
|
|
534
1003
|
] })
|
|
1004
|
+
] });
|
|
1005
|
+
}
|
|
1006
|
+
if (quiz && showIntro) {
|
|
1007
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: defaultStyles.intro, children: [
|
|
1008
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.introTitle, children: quiz.title }),
|
|
1009
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.introSubtitle, children: "Ready to test your knowledge?" }),
|
|
1010
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: defaultStyles.introQuestionCount, children: [
|
|
1011
|
+
quiz.questions.length,
|
|
1012
|
+
" question",
|
|
1013
|
+
quiz.questions.length !== 1 ? "s" : "",
|
|
1014
|
+
" to answer"
|
|
1015
|
+
] }),
|
|
1016
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1017
|
+
"button",
|
|
1018
|
+
{
|
|
1019
|
+
style: defaultStyles.startButton,
|
|
1020
|
+
onClick: handleStart,
|
|
1021
|
+
onMouseOver: (e) => {
|
|
1022
|
+
e.currentTarget.style.transform = "translateY(-2px)";
|
|
1023
|
+
e.currentTarget.style.boxShadow = "0 6px 20px rgba(124, 58, 237, 0.5)";
|
|
1024
|
+
},
|
|
1025
|
+
onMouseOut: (e) => {
|
|
1026
|
+
e.currentTarget.style.transform = "translateY(0)";
|
|
1027
|
+
e.currentTarget.style.boxShadow = "0 4px 14px rgba(124, 58, 237, 0.4)";
|
|
1028
|
+
},
|
|
1029
|
+
"data-testid": "button-start-quiz",
|
|
1030
|
+
children: "Let's Start!"
|
|
1031
|
+
}
|
|
1032
|
+
)
|
|
535
1033
|
] }) });
|
|
536
1034
|
}
|
|
537
1035
|
if (!quiz || !currentQuestion) {
|
|
538
1036
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.error, children: "No quiz data available" }) });
|
|
539
1037
|
}
|
|
540
1038
|
const selectedAnswer = answers.get(currentQuestion.id);
|
|
541
|
-
const isLastQuestion = currentQuestionIndex ===
|
|
542
|
-
const progressPercent = (currentQuestionIndex + 1) /
|
|
1039
|
+
const isLastQuestion = currentQuestionIndex === totalQuestions - 1;
|
|
1040
|
+
const progressPercent = (currentQuestionIndex + 1) / totalQuestions * 100;
|
|
1041
|
+
const remainingSlots = maxQuestions - totalQuestions;
|
|
1042
|
+
const questionsToAdd = Math.min(5, remainingSlots);
|
|
1043
|
+
const canAddMore = onGenerateMoreQuestions && remainingSlots > 0;
|
|
543
1044
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className, style: defaultStyles.container, children: [
|
|
544
1045
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: defaultStyles.header, children: [
|
|
545
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
546
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.title, children: quiz.title }),
|
|
547
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.timer, children: formatTime(elapsedSeconds) })
|
|
548
|
-
] }),
|
|
1046
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.title, children: quiz.title }),
|
|
549
1047
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: defaultStyles.progress, children: [
|
|
550
1048
|
"Question ",
|
|
551
1049
|
currentQuestionIndex + 1,
|
|
552
1050
|
" of ",
|
|
553
|
-
|
|
1051
|
+
totalQuestions
|
|
554
1052
|
] }),
|
|
555
1053
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.progressBar, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...defaultStyles.progressFill, width: `${progressPercent}%` } }) })
|
|
556
1054
|
] }),
|
|
557
1055
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: defaultStyles.question, children: [
|
|
558
1056
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.questionText, children: currentQuestion.question }),
|
|
559
|
-
(currentQuestion.type === "single" || currentQuestion.type === "true-false") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) =>
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
1057
|
+
(currentQuestion.type === "single" || currentQuestion.type === "true-false") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) => {
|
|
1058
|
+
const isSelected = selectedAnswer === option;
|
|
1059
|
+
const isCorrectOption = currentQuestion.correctAnswer === option;
|
|
1060
|
+
let optionStyle = { ...defaultStyles.option };
|
|
1061
|
+
if (showFeedback) {
|
|
1062
|
+
if (isCorrectOption) {
|
|
1063
|
+
optionStyle = { ...optionStyle, ...defaultStyles.optionCorrect };
|
|
1064
|
+
} else if (isSelected && !isCorrectOption) {
|
|
1065
|
+
optionStyle = { ...optionStyle, ...defaultStyles.optionIncorrect };
|
|
1066
|
+
}
|
|
1067
|
+
} else if (isSelected) {
|
|
1068
|
+
optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
|
|
1069
|
+
}
|
|
1070
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1071
|
+
"div",
|
|
1072
|
+
{
|
|
1073
|
+
style: {
|
|
1074
|
+
...optionStyle,
|
|
1075
|
+
cursor: showFeedback ? "default" : "pointer"
|
|
1076
|
+
},
|
|
1077
|
+
onClick: () => !showFeedback && handleAnswerChange(option),
|
|
1078
|
+
children: option
|
|
565
1079
|
},
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
idx
|
|
570
|
-
)) }),
|
|
1080
|
+
idx
|
|
1081
|
+
);
|
|
1082
|
+
}) }),
|
|
571
1083
|
currentQuestion.type === "multiple" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) => {
|
|
572
1084
|
const selected = Array.isArray(selectedAnswer) && selectedAnswer.includes(option);
|
|
1085
|
+
const correctAnswers = Array.isArray(currentQuestion.correctAnswer) ? currentQuestion.correctAnswer : currentQuestion.correctAnswer ? [currentQuestion.correctAnswer] : [];
|
|
1086
|
+
const isCorrectOption = correctAnswers.includes(option);
|
|
1087
|
+
let optionStyle = { ...defaultStyles.option };
|
|
1088
|
+
if (showFeedback) {
|
|
1089
|
+
if (isCorrectOption) {
|
|
1090
|
+
optionStyle = { ...optionStyle, ...defaultStyles.optionCorrect };
|
|
1091
|
+
} else if (selected && !isCorrectOption) {
|
|
1092
|
+
optionStyle = { ...optionStyle, ...defaultStyles.optionIncorrect };
|
|
1093
|
+
}
|
|
1094
|
+
} else if (selected) {
|
|
1095
|
+
optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
|
|
1096
|
+
}
|
|
573
1097
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
574
1098
|
"div",
|
|
575
1099
|
{
|
|
576
1100
|
style: {
|
|
577
|
-
...
|
|
578
|
-
|
|
1101
|
+
...optionStyle,
|
|
1102
|
+
cursor: showFeedback ? "default" : "pointer"
|
|
579
1103
|
},
|
|
580
1104
|
onClick: () => {
|
|
1105
|
+
if (showFeedback) return;
|
|
581
1106
|
const current = Array.isArray(selectedAnswer) ? selectedAnswer : [];
|
|
582
1107
|
if (selected) {
|
|
583
1108
|
handleAnswerChange(current.filter((o) => o !== option));
|
|
@@ -596,7 +1121,8 @@ function QuizPlayer({
|
|
|
596
1121
|
style: { ...defaultStyles.input, minHeight: currentQuestion.type === "essay" ? "150px" : "60px" },
|
|
597
1122
|
value: selectedAnswer || "",
|
|
598
1123
|
onChange: (e) => handleAnswerChange(e.target.value),
|
|
599
|
-
placeholder: "Type your answer here..."
|
|
1124
|
+
placeholder: "Type your answer here...",
|
|
1125
|
+
disabled: showFeedback
|
|
600
1126
|
}
|
|
601
1127
|
),
|
|
602
1128
|
currentQuestion.type === "fill" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.options, children: currentQuestion.blanks?.map((_, idx) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -609,47 +1135,86 @@ function QuizPlayer({
|
|
|
609
1135
|
current[idx] = e.target.value;
|
|
610
1136
|
handleAnswerChange(current);
|
|
611
1137
|
},
|
|
612
|
-
placeholder: `Blank ${idx + 1}
|
|
1138
|
+
placeholder: `Blank ${idx + 1}`,
|
|
1139
|
+
disabled: showFeedback
|
|
613
1140
|
},
|
|
614
1141
|
idx
|
|
615
|
-
)) })
|
|
1142
|
+
)) }),
|
|
1143
|
+
showFeedback && currentAnswerDetail && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
|
|
1144
|
+
...defaultStyles.feedback,
|
|
1145
|
+
...currentAnswerDetail.isCorrect ? defaultStyles.feedbackCorrect : defaultStyles.feedbackIncorrect
|
|
1146
|
+
}, children: [
|
|
1147
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
|
|
1148
|
+
...defaultStyles.feedbackTitle,
|
|
1149
|
+
...currentAnswerDetail.isCorrect ? defaultStyles.feedbackTitleCorrect : defaultStyles.feedbackTitleIncorrect
|
|
1150
|
+
}, children: currentAnswerDetail.isCorrect ? "\u2713 Correct!" : "\u2717 Incorrect" }),
|
|
1151
|
+
currentQuestion.explanation && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultStyles.feedbackExplanation, children: currentQuestion.explanation })
|
|
1152
|
+
] })
|
|
616
1153
|
] }),
|
|
617
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: defaultStyles.
|
|
618
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1154
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: defaultStyles.buttonsColumn, children: [
|
|
1155
|
+
showFeedback && isLastQuestion && canAddMore && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
619
1156
|
"button",
|
|
620
1157
|
{
|
|
621
1158
|
style: {
|
|
622
|
-
...defaultStyles.
|
|
623
|
-
...
|
|
1159
|
+
...defaultStyles.buttonAddMore,
|
|
1160
|
+
...isGeneratingExtra ? defaultStyles.buttonAddMoreDisabled : {}
|
|
624
1161
|
},
|
|
625
|
-
onClick:
|
|
626
|
-
disabled:
|
|
627
|
-
|
|
1162
|
+
onClick: handleAddMoreQuestions,
|
|
1163
|
+
disabled: isGeneratingExtra,
|
|
1164
|
+
"data-testid": "button-add-more-questions",
|
|
1165
|
+
children: isGeneratingExtra ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1166
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, { size: 16, color: "#9ca3af" }),
|
|
1167
|
+
"Generating Questions..."
|
|
1168
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1169
|
+
"+ Add ",
|
|
1170
|
+
questionsToAdd,
|
|
1171
|
+
" More Question",
|
|
1172
|
+
questionsToAdd !== 1 ? "s" : ""
|
|
1173
|
+
] })
|
|
628
1174
|
}
|
|
629
1175
|
),
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
1176
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...defaultStyles.buttons, justifyContent: "flex-end" }, children: showFeedback ? (
|
|
1177
|
+
// After viewing feedback
|
|
1178
|
+
isLastQuestion ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1179
|
+
"button",
|
|
1180
|
+
{
|
|
1181
|
+
style: {
|
|
1182
|
+
...defaultStyles.button,
|
|
1183
|
+
...isSubmitting || isGeneratingExtra ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary
|
|
1184
|
+
},
|
|
1185
|
+
onClick: handleSubmit,
|
|
1186
|
+
disabled: isSubmitting || isGeneratingExtra,
|
|
1187
|
+
"data-testid": "button-submit-quiz",
|
|
1188
|
+
children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, { size: 16, color: "#9ca3af" }) : "Submit Quiz"
|
|
1189
|
+
}
|
|
1190
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1191
|
+
"button",
|
|
1192
|
+
{
|
|
1193
|
+
style: {
|
|
1194
|
+
...defaultStyles.button,
|
|
1195
|
+
...defaultStyles.buttonPrimary
|
|
1196
|
+
},
|
|
1197
|
+
onClick: handleContinue,
|
|
1198
|
+
"data-testid": "button-continue",
|
|
1199
|
+
children: "Continue"
|
|
1200
|
+
}
|
|
1201
|
+
)
|
|
1202
|
+
) : (
|
|
1203
|
+
// Before checking answer
|
|
1204
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1205
|
+
"button",
|
|
1206
|
+
{
|
|
1207
|
+
style: {
|
|
1208
|
+
...defaultStyles.button,
|
|
1209
|
+
...isNavigating || selectedAnswer === void 0 ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary
|
|
1210
|
+
},
|
|
1211
|
+
onClick: handleCheckAnswer,
|
|
1212
|
+
disabled: isNavigating || selectedAnswer === void 0,
|
|
1213
|
+
"data-testid": "button-check-answer",
|
|
1214
|
+
children: isNavigating ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, { size: 16, color: "#9ca3af" }) : "Check Answer"
|
|
1215
|
+
}
|
|
1216
|
+
)
|
|
1217
|
+
) })
|
|
653
1218
|
] })
|
|
654
1219
|
] });
|
|
655
1220
|
}
|