@schoolio/player 1.2.1 → 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 +799 -184
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +733 -143
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
2
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
-
|
|
4
1
|
// src/QuizPlayer.tsx
|
|
2
|
+
import { useState, useEffect, useCallback, useRef } from "react";
|
|
5
3
|
|
|
6
4
|
// src/api.ts
|
|
7
5
|
var QuizApiClient = class {
|
|
@@ -141,14 +139,17 @@ function formatTime(seconds) {
|
|
|
141
139
|
const secs = seconds % 60;
|
|
142
140
|
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
143
141
|
}
|
|
142
|
+
|
|
143
|
+
// src/QuizPlayer.tsx
|
|
144
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
144
145
|
var defaultStyles = {
|
|
145
146
|
container: {
|
|
146
147
|
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
147
|
-
|
|
148
|
-
margin: "0 auto",
|
|
148
|
+
width: "100%",
|
|
149
149
|
padding: "20px",
|
|
150
150
|
backgroundColor: "#ffffff",
|
|
151
|
-
borderRadius: "12px"
|
|
151
|
+
borderRadius: "12px",
|
|
152
|
+
boxSizing: "border-box"
|
|
152
153
|
},
|
|
153
154
|
header: {
|
|
154
155
|
marginBottom: "20px",
|
|
@@ -178,7 +179,8 @@ var defaultStyles = {
|
|
|
178
179
|
transition: "width 0.3s ease"
|
|
179
180
|
},
|
|
180
181
|
question: {
|
|
181
|
-
marginBottom: "24px"
|
|
182
|
+
marginBottom: "24px",
|
|
183
|
+
minHeight: "280px"
|
|
182
184
|
},
|
|
183
185
|
questionText: {
|
|
184
186
|
fontSize: "18px",
|
|
@@ -195,18 +197,31 @@ var defaultStyles = {
|
|
|
195
197
|
border: "2px solid #e5e7eb",
|
|
196
198
|
borderRadius: "8px",
|
|
197
199
|
cursor: "pointer",
|
|
198
|
-
transition: "all 0.2s ease"
|
|
200
|
+
transition: "all 0.2s ease",
|
|
201
|
+
outline: "none",
|
|
202
|
+
backgroundColor: "#ffffff"
|
|
199
203
|
},
|
|
200
204
|
optionSelected: {
|
|
201
205
|
borderColor: "#6721b0",
|
|
202
206
|
backgroundColor: "#f3e8ff"
|
|
203
207
|
},
|
|
208
|
+
optionCorrect: {
|
|
209
|
+
borderColor: "#22c55e",
|
|
210
|
+
backgroundColor: "#f0fdf4"
|
|
211
|
+
},
|
|
212
|
+
optionIncorrect: {
|
|
213
|
+
borderColor: "#ef4444",
|
|
214
|
+
backgroundColor: "#fef2f2"
|
|
215
|
+
},
|
|
204
216
|
input: {
|
|
205
217
|
width: "100%",
|
|
206
218
|
padding: "12px 16px",
|
|
207
219
|
border: "2px solid #e5e7eb",
|
|
208
220
|
borderRadius: "8px",
|
|
209
|
-
fontSize: "16px"
|
|
221
|
+
fontSize: "16px",
|
|
222
|
+
outline: "none",
|
|
223
|
+
boxSizing: "border-box",
|
|
224
|
+
backgroundColor: "#ffffff"
|
|
210
225
|
},
|
|
211
226
|
buttons: {
|
|
212
227
|
display: "flex",
|
|
@@ -235,24 +250,90 @@ var defaultStyles = {
|
|
|
235
250
|
color: "#9ca3af",
|
|
236
251
|
cursor: "not-allowed"
|
|
237
252
|
},
|
|
253
|
+
buttonAddMore: {
|
|
254
|
+
padding: "12px 24px",
|
|
255
|
+
borderRadius: "8px",
|
|
256
|
+
fontSize: "16px",
|
|
257
|
+
fontWeight: "500",
|
|
258
|
+
cursor: "pointer",
|
|
259
|
+
border: "2px solid #6721b0",
|
|
260
|
+
backgroundColor: "transparent",
|
|
261
|
+
color: "#6721b0",
|
|
262
|
+
transition: "all 0.2s ease",
|
|
263
|
+
display: "flex",
|
|
264
|
+
alignItems: "center",
|
|
265
|
+
justifyContent: "center",
|
|
266
|
+
gap: "8px"
|
|
267
|
+
},
|
|
268
|
+
buttonAddMoreDisabled: {
|
|
269
|
+
border: "2px solid #e5e7eb",
|
|
270
|
+
color: "#9ca3af",
|
|
271
|
+
cursor: "not-allowed"
|
|
272
|
+
},
|
|
273
|
+
buttonsColumn: {
|
|
274
|
+
display: "flex",
|
|
275
|
+
flexDirection: "column",
|
|
276
|
+
gap: "12px",
|
|
277
|
+
marginTop: "24px"
|
|
278
|
+
},
|
|
238
279
|
timer: {
|
|
239
280
|
fontSize: "14px",
|
|
240
281
|
color: "#6b7280",
|
|
241
282
|
marginLeft: "16px"
|
|
242
283
|
},
|
|
243
284
|
results: {
|
|
285
|
+
display: "flex",
|
|
286
|
+
flexDirection: "column",
|
|
287
|
+
alignItems: "center",
|
|
288
|
+
justifyContent: "center",
|
|
289
|
+
padding: "48px 24px",
|
|
244
290
|
textAlign: "center",
|
|
245
|
-
|
|
291
|
+
minHeight: "400px",
|
|
292
|
+
position: "relative",
|
|
293
|
+
overflow: "hidden"
|
|
246
294
|
},
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
295
|
+
resultsBackground: {
|
|
296
|
+
position: "absolute",
|
|
297
|
+
inset: "0",
|
|
298
|
+
borderRadius: "16px",
|
|
299
|
+
zIndex: 0
|
|
252
300
|
},
|
|
253
|
-
|
|
301
|
+
resultsContent: {
|
|
302
|
+
position: "relative",
|
|
303
|
+
zIndex: 1,
|
|
304
|
+
display: "flex",
|
|
305
|
+
flexDirection: "column",
|
|
306
|
+
alignItems: "center"
|
|
307
|
+
},
|
|
308
|
+
resultDetails: {
|
|
254
309
|
fontSize: "18px",
|
|
255
|
-
color: "#6b7280"
|
|
310
|
+
color: "#6b7280",
|
|
311
|
+
marginBottom: "4px"
|
|
312
|
+
},
|
|
313
|
+
resultStars: {
|
|
314
|
+
display: "flex",
|
|
315
|
+
justifyContent: "center",
|
|
316
|
+
gap: "8px",
|
|
317
|
+
marginBottom: "20px"
|
|
318
|
+
},
|
|
319
|
+
resultStar: {
|
|
320
|
+
fontSize: "32px",
|
|
321
|
+
animation: "starPop 0.5s ease-out forwards",
|
|
322
|
+
opacity: 0
|
|
323
|
+
},
|
|
324
|
+
confettiContainer: {
|
|
325
|
+
position: "absolute",
|
|
326
|
+
inset: "0",
|
|
327
|
+
pointerEvents: "none",
|
|
328
|
+
overflow: "hidden",
|
|
329
|
+
zIndex: 0
|
|
330
|
+
},
|
|
331
|
+
confettiPiece: {
|
|
332
|
+
position: "absolute",
|
|
333
|
+
width: "10px",
|
|
334
|
+
height: "10px",
|
|
335
|
+
top: "-10px",
|
|
336
|
+
animation: "confettiFall 3s ease-out forwards"
|
|
256
337
|
},
|
|
257
338
|
loading: {
|
|
258
339
|
textAlign: "center",
|
|
@@ -263,6 +344,80 @@ var defaultStyles = {
|
|
|
263
344
|
textAlign: "center",
|
|
264
345
|
padding: "40px",
|
|
265
346
|
color: "#ef4444"
|
|
347
|
+
},
|
|
348
|
+
intro: {
|
|
349
|
+
display: "flex",
|
|
350
|
+
flexDirection: "column",
|
|
351
|
+
alignItems: "center",
|
|
352
|
+
justifyContent: "center",
|
|
353
|
+
padding: "48px 24px",
|
|
354
|
+
textAlign: "center",
|
|
355
|
+
background: "linear-gradient(135deg, #f3e8ff 0%, #e0e7ff 50%, #fce7f3 100%)",
|
|
356
|
+
borderRadius: "16px",
|
|
357
|
+
minHeight: "320px"
|
|
358
|
+
},
|
|
359
|
+
introTitle: {
|
|
360
|
+
fontSize: "28px",
|
|
361
|
+
fontWeight: "700",
|
|
362
|
+
color: "#4c1d95",
|
|
363
|
+
marginBottom: "12px"
|
|
364
|
+
},
|
|
365
|
+
introSubtitle: {
|
|
366
|
+
fontSize: "16px",
|
|
367
|
+
color: "#6b7280",
|
|
368
|
+
marginBottom: "8px"
|
|
369
|
+
},
|
|
370
|
+
introQuestionCount: {
|
|
371
|
+
fontSize: "14px",
|
|
372
|
+
color: "#8b5cf6",
|
|
373
|
+
marginBottom: "32px",
|
|
374
|
+
fontWeight: "500"
|
|
375
|
+
},
|
|
376
|
+
startButton: {
|
|
377
|
+
padding: "16px 48px",
|
|
378
|
+
fontSize: "18px",
|
|
379
|
+
fontWeight: "600",
|
|
380
|
+
backgroundColor: "#7c3aed",
|
|
381
|
+
color: "#ffffff",
|
|
382
|
+
border: "none",
|
|
383
|
+
borderRadius: "12px",
|
|
384
|
+
cursor: "pointer",
|
|
385
|
+
transition: "all 0.2s ease",
|
|
386
|
+
boxShadow: "0 4px 14px rgba(124, 58, 237, 0.4)"
|
|
387
|
+
},
|
|
388
|
+
feedback: {
|
|
389
|
+
marginTop: "16px",
|
|
390
|
+
padding: "16px",
|
|
391
|
+
borderRadius: "8px",
|
|
392
|
+
backgroundColor: "#f9fafb",
|
|
393
|
+
border: "1px solid #e5e7eb"
|
|
394
|
+
},
|
|
395
|
+
feedbackCorrect: {
|
|
396
|
+
backgroundColor: "#f0fdf4",
|
|
397
|
+
borderColor: "#22c55e"
|
|
398
|
+
},
|
|
399
|
+
feedbackIncorrect: {
|
|
400
|
+
backgroundColor: "#fef2f2",
|
|
401
|
+
borderColor: "#ef4444"
|
|
402
|
+
},
|
|
403
|
+
feedbackTitle: {
|
|
404
|
+
fontSize: "16px",
|
|
405
|
+
fontWeight: "600",
|
|
406
|
+
marginBottom: "8px",
|
|
407
|
+
display: "flex",
|
|
408
|
+
alignItems: "center",
|
|
409
|
+
gap: "8px"
|
|
410
|
+
},
|
|
411
|
+
feedbackTitleCorrect: {
|
|
412
|
+
color: "#16a34a"
|
|
413
|
+
},
|
|
414
|
+
feedbackTitleIncorrect: {
|
|
415
|
+
color: "#dc2626"
|
|
416
|
+
},
|
|
417
|
+
feedbackExplanation: {
|
|
418
|
+
fontSize: "14px",
|
|
419
|
+
color: "#4b5563",
|
|
420
|
+
lineHeight: "1.5"
|
|
266
421
|
}
|
|
267
422
|
};
|
|
268
423
|
function Spinner({ size = 16, color = "#ffffff" }) {
|
|
@@ -294,6 +449,7 @@ function QuizPlayer({
|
|
|
294
449
|
onComplete,
|
|
295
450
|
onError,
|
|
296
451
|
onProgress,
|
|
452
|
+
onGenerateMoreQuestions,
|
|
297
453
|
className
|
|
298
454
|
}) {
|
|
299
455
|
const [quiz, setQuiz] = useState(null);
|
|
@@ -308,9 +464,15 @@ function QuizPlayer({
|
|
|
308
464
|
const [error, setError] = useState(null);
|
|
309
465
|
const [isLoading, setIsLoading] = useState(true);
|
|
310
466
|
const [elapsedSeconds, setElapsedSeconds] = useState(0);
|
|
467
|
+
const [showIntro, setShowIntro] = useState(true);
|
|
468
|
+
const [timerStarted, setTimerStarted] = useState(false);
|
|
469
|
+
const [showFeedback, setShowFeedback] = useState(false);
|
|
470
|
+
const [currentAnswerDetail, setCurrentAnswerDetail] = useState(null);
|
|
471
|
+
const [extraQuestions, setExtraQuestions] = useState([]);
|
|
472
|
+
const [isGeneratingExtra, setIsGeneratingExtra] = useState(false);
|
|
311
473
|
const apiClient = useRef(null);
|
|
312
474
|
const timerRef = useRef(null);
|
|
313
|
-
const startTimeRef = useRef(
|
|
475
|
+
const startTimeRef = useRef(0);
|
|
314
476
|
useEffect(() => {
|
|
315
477
|
apiClient.current = new QuizApiClient({ baseUrl: apiBaseUrl, authToken });
|
|
316
478
|
}, [apiBaseUrl, authToken]);
|
|
@@ -362,7 +524,7 @@ function QuizPlayer({
|
|
|
362
524
|
initialize();
|
|
363
525
|
}, [quizId, lessonId, assignLessonId, courseId, childId, parentId, onError]);
|
|
364
526
|
useEffect(() => {
|
|
365
|
-
if (
|
|
527
|
+
if (timerStarted && !isCompleted && !error) {
|
|
366
528
|
startTimeRef.current = Date.now();
|
|
367
529
|
timerRef.current = setInterval(() => {
|
|
368
530
|
setElapsedSeconds(Math.floor((Date.now() - startTimeRef.current) / 1e3));
|
|
@@ -373,27 +535,39 @@ function QuizPlayer({
|
|
|
373
535
|
clearInterval(timerRef.current);
|
|
374
536
|
}
|
|
375
537
|
};
|
|
376
|
-
}, [
|
|
538
|
+
}, [timerStarted, isCompleted, error]);
|
|
539
|
+
const handleStart = useCallback(() => {
|
|
540
|
+
setShowIntro(false);
|
|
541
|
+
setTimerStarted(true);
|
|
542
|
+
}, []);
|
|
543
|
+
useEffect(() => {
|
|
544
|
+
setShowFeedback(false);
|
|
545
|
+
setCurrentAnswerDetail(null);
|
|
546
|
+
}, [currentQuestionIndex]);
|
|
547
|
+
const allQuestions = quiz ? [...quiz.questions, ...extraQuestions] : [];
|
|
548
|
+
const totalQuestions = allQuestions.length;
|
|
549
|
+
const maxQuestions = 50;
|
|
377
550
|
useEffect(() => {
|
|
378
551
|
if (quiz && onProgress) {
|
|
379
552
|
onProgress({
|
|
380
553
|
currentQuestion: currentQuestionIndex + 1,
|
|
381
|
-
totalQuestions
|
|
554
|
+
totalQuestions,
|
|
382
555
|
answeredQuestions: answers.size
|
|
383
556
|
});
|
|
384
557
|
}
|
|
385
|
-
}, [currentQuestionIndex, answers.size, quiz, onProgress]);
|
|
386
|
-
const currentQuestion =
|
|
558
|
+
}, [currentQuestionIndex, answers.size, quiz, onProgress, totalQuestions]);
|
|
559
|
+
const currentQuestion = allQuestions[currentQuestionIndex];
|
|
387
560
|
const handleAnswerChange = useCallback((value) => {
|
|
388
561
|
if (!currentQuestion) return;
|
|
389
562
|
setAnswers((prev) => new Map(prev).set(currentQuestion.id, value));
|
|
390
563
|
}, [currentQuestion]);
|
|
391
|
-
const
|
|
564
|
+
const handleCheckAnswer = useCallback(async () => {
|
|
392
565
|
if (!quiz || !attempt || !currentQuestion || !apiClient.current) return;
|
|
393
566
|
const selectedAnswer2 = answers.get(currentQuestion.id);
|
|
394
567
|
if (selectedAnswer2 === void 0) return;
|
|
395
568
|
setIsNavigating(true);
|
|
396
569
|
const answerDetail = createAnswerDetail(currentQuestion, selectedAnswer2);
|
|
570
|
+
setCurrentAnswerDetail(answerDetail);
|
|
397
571
|
const newAnswersDetail = [...answersDetail];
|
|
398
572
|
const existingIdx = newAnswersDetail.findIndex((a) => a.questionId === currentQuestion.id);
|
|
399
573
|
if (existingIdx >= 0) {
|
|
@@ -411,15 +585,39 @@ function QuizPlayer({
|
|
|
411
585
|
} finally {
|
|
412
586
|
setIsNavigating(false);
|
|
413
587
|
}
|
|
414
|
-
|
|
588
|
+
setShowFeedback(true);
|
|
589
|
+
}, [quiz, attempt, currentQuestion, answers, answersDetail]);
|
|
590
|
+
const handleContinue = useCallback(() => {
|
|
591
|
+
if (!quiz) return;
|
|
592
|
+
setShowFeedback(false);
|
|
593
|
+
setCurrentAnswerDetail(null);
|
|
594
|
+
if (currentQuestionIndex < totalQuestions - 1) {
|
|
415
595
|
setCurrentQuestionIndex((prev) => prev + 1);
|
|
416
596
|
}
|
|
417
|
-
}, [quiz,
|
|
418
|
-
const
|
|
419
|
-
if (
|
|
420
|
-
|
|
597
|
+
}, [quiz, currentQuestionIndex, totalQuestions]);
|
|
598
|
+
const handleAddMoreQuestions = useCallback(async () => {
|
|
599
|
+
if (!attempt || !onGenerateMoreQuestions || isGeneratingExtra) return;
|
|
600
|
+
if (totalQuestions >= maxQuestions) return;
|
|
601
|
+
setIsGeneratingExtra(true);
|
|
602
|
+
try {
|
|
603
|
+
const result2 = await onGenerateMoreQuestions(attempt.id, totalQuestions);
|
|
604
|
+
if (result2.extraQuestions && result2.extraQuestions.length > 0) {
|
|
605
|
+
const slotsAvailable = maxQuestions - totalQuestions;
|
|
606
|
+
const questionsToAppend = result2.extraQuestions.slice(0, slotsAvailable);
|
|
607
|
+
if (questionsToAppend.length > 0) {
|
|
608
|
+
setExtraQuestions((prev) => [...prev, ...questionsToAppend]);
|
|
609
|
+
setCurrentQuestionIndex(totalQuestions);
|
|
610
|
+
setShowFeedback(false);
|
|
611
|
+
setCurrentAnswerDetail(null);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
} catch (err) {
|
|
615
|
+
console.error("Failed to generate extra questions:", err);
|
|
616
|
+
onError?.(err instanceof Error ? err : new Error("Failed to generate extra questions"));
|
|
617
|
+
} finally {
|
|
618
|
+
setIsGeneratingExtra(false);
|
|
421
619
|
}
|
|
422
|
-
}, [
|
|
620
|
+
}, [attempt, onGenerateMoreQuestions, isGeneratingExtra, totalQuestions, maxQuestions, onError]);
|
|
423
621
|
const handleSubmit = useCallback(async () => {
|
|
424
622
|
if (!quiz || !attempt || !apiClient.current) return;
|
|
425
623
|
setIsSubmitting(true);
|
|
@@ -436,7 +634,7 @@ function QuizPlayer({
|
|
|
436
634
|
}
|
|
437
635
|
}
|
|
438
636
|
const scoreData = calculateScore(finalAnswersDetail);
|
|
439
|
-
const timeSpent = Math.floor((Date.now() - startTimeRef.current) / 1e3);
|
|
637
|
+
const timeSpent = timerStarted && startTimeRef.current > 0 ? Math.floor((Date.now() - startTimeRef.current) / 1e3) : elapsedSeconds;
|
|
440
638
|
const updatedAttempt = await apiClient.current.updateAttempt(attempt.id, {
|
|
441
639
|
answers: finalAnswersDetail,
|
|
442
640
|
status: "completed",
|
|
@@ -449,7 +647,7 @@ function QuizPlayer({
|
|
|
449
647
|
attemptId: updatedAttempt.id,
|
|
450
648
|
score: scoreData.score,
|
|
451
649
|
correctAnswers: scoreData.correctAnswers,
|
|
452
|
-
totalQuestions
|
|
650
|
+
totalQuestions,
|
|
453
651
|
answers: finalAnswersDetail,
|
|
454
652
|
timeSpentSeconds: timeSpent
|
|
455
653
|
};
|
|
@@ -465,7 +663,7 @@ function QuizPlayer({
|
|
|
465
663
|
} finally {
|
|
466
664
|
setIsSubmitting(false);
|
|
467
665
|
}
|
|
468
|
-
}, [quiz, attempt, currentQuestion, answers, answersDetail, onComplete, onError]);
|
|
666
|
+
}, [quiz, attempt, currentQuestion, answers, answersDetail, onComplete, onError, totalQuestions, timerStarted, elapsedSeconds]);
|
|
469
667
|
if (isLoading) {
|
|
470
668
|
return /* @__PURE__ */ jsx("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ jsx("div", { style: defaultStyles.loading, children: "Loading quiz..." }) });
|
|
471
669
|
}
|
|
@@ -476,67 +674,403 @@ function QuizPlayer({
|
|
|
476
674
|
] }) }) });
|
|
477
675
|
}
|
|
478
676
|
if (isCompleted && result) {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
677
|
+
const percentage = Math.round(result.correctAnswers / result.totalQuestions * 100);
|
|
678
|
+
const getScoreTheme = (pct) => {
|
|
679
|
+
if (pct >= 80) {
|
|
680
|
+
return {
|
|
681
|
+
color: "#22c55e",
|
|
682
|
+
bgGradient: "linear-gradient(135deg, #dcfce7 0%, #bbf7d0 50%, #86efac 100%)",
|
|
683
|
+
badge: "Quiz Champion!",
|
|
684
|
+
badgeColor: "#fbbf24",
|
|
685
|
+
badgeBg: "linear-gradient(135deg, #fef3c7 0%, #fde68a 100%)",
|
|
686
|
+
mascotMood: "celebrating",
|
|
687
|
+
stars: 3
|
|
688
|
+
};
|
|
689
|
+
} else if (pct >= 60) {
|
|
690
|
+
return {
|
|
691
|
+
color: "#f59e0b",
|
|
692
|
+
bgGradient: "linear-gradient(135deg, #fef3c7 0%, #fde68a 50%, #fcd34d 100%)",
|
|
693
|
+
badge: "Rising Star!",
|
|
694
|
+
badgeColor: "#f59e0b",
|
|
695
|
+
badgeBg: "linear-gradient(135deg, #fed7aa 0%, #fdba74 100%)",
|
|
696
|
+
mascotMood: "happy",
|
|
697
|
+
stars: 2
|
|
698
|
+
};
|
|
699
|
+
} else if (pct >= 40) {
|
|
700
|
+
return {
|
|
701
|
+
color: "#3b82f6",
|
|
702
|
+
bgGradient: "linear-gradient(135deg, #dbeafe 0%, #bfdbfe 50%, #93c5fd 100%)",
|
|
703
|
+
badge: "Great Learner!",
|
|
704
|
+
badgeColor: "#3b82f6",
|
|
705
|
+
badgeBg: "linear-gradient(135deg, #bfdbfe 0%, #93c5fd 100%)",
|
|
706
|
+
mascotMood: "encouraging",
|
|
707
|
+
stars: 1
|
|
708
|
+
};
|
|
709
|
+
} else {
|
|
710
|
+
return {
|
|
711
|
+
color: "#8b5cf6",
|
|
712
|
+
bgGradient: "linear-gradient(135deg, #f3e8ff 0%, #e9d5ff 50%, #d8b4fe 100%)",
|
|
713
|
+
badge: "Keep Growing!",
|
|
714
|
+
badgeColor: "#8b5cf6",
|
|
715
|
+
badgeBg: "linear-gradient(135deg, #e9d5ff 0%, #d8b4fe 100%)",
|
|
716
|
+
mascotMood: "supportive",
|
|
717
|
+
stars: 0
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
const theme = getScoreTheme(percentage);
|
|
722
|
+
const confettiColors = ["#f43f5e", "#ec4899", "#8b5cf6", "#3b82f6", "#22c55e", "#f59e0b", "#ef4444"];
|
|
723
|
+
const confettiPieces = Array.from({ length: 50 }, (_, i) => ({
|
|
724
|
+
id: i,
|
|
725
|
+
left: `${Math.random() * 100}%`,
|
|
726
|
+
delay: `${Math.random() * 2}s`,
|
|
727
|
+
duration: `${2 + Math.random() * 2}s`,
|
|
728
|
+
color: confettiColors[Math.floor(Math.random() * confettiColors.length)],
|
|
729
|
+
rotation: Math.random() * 360,
|
|
730
|
+
size: 6 + Math.random() * 8
|
|
731
|
+
}));
|
|
732
|
+
const StarIcon = ({ filled, delay }) => /* @__PURE__ */ jsx(
|
|
733
|
+
"svg",
|
|
734
|
+
{
|
|
735
|
+
width: "36",
|
|
736
|
+
height: "36",
|
|
737
|
+
viewBox: "0 0 24 24",
|
|
738
|
+
style: {
|
|
739
|
+
animation: "starPop 0.5s ease-out forwards",
|
|
740
|
+
animationDelay: `${delay}s`,
|
|
741
|
+
opacity: 0
|
|
742
|
+
},
|
|
743
|
+
children: /* @__PURE__ */ jsx(
|
|
744
|
+
"path",
|
|
745
|
+
{
|
|
746
|
+
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",
|
|
747
|
+
fill: filled ? "#fbbf24" : "#e5e7eb",
|
|
748
|
+
stroke: filled ? "#f59e0b" : "#d1d5db",
|
|
749
|
+
strokeWidth: "1"
|
|
750
|
+
}
|
|
751
|
+
)
|
|
752
|
+
}
|
|
753
|
+
);
|
|
754
|
+
const MascotOwl = ({ mood }) => {
|
|
755
|
+
const getEyeExpression = () => {
|
|
756
|
+
switch (mood) {
|
|
757
|
+
case "celebrating":
|
|
758
|
+
return { leftEye: ">", rightEye: "<", pupilY: 42 };
|
|
759
|
+
// Squinting happy
|
|
760
|
+
case "happy":
|
|
761
|
+
return { leftEye: null, rightEye: null, pupilY: 42 };
|
|
762
|
+
// Normal happy
|
|
763
|
+
case "encouraging":
|
|
764
|
+
return { leftEye: null, rightEye: null, pupilY: 44 };
|
|
765
|
+
// Looking down warmly
|
|
766
|
+
default:
|
|
767
|
+
return { leftEye: null, rightEye: null, pupilY: 42 };
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
const eyeExpr = getEyeExpression();
|
|
771
|
+
return /* @__PURE__ */ jsxs(
|
|
772
|
+
"svg",
|
|
773
|
+
{
|
|
774
|
+
width: "120",
|
|
775
|
+
height: "120",
|
|
776
|
+
viewBox: "0 0 100 100",
|
|
777
|
+
style: {
|
|
778
|
+
animation: mood === "celebrating" ? "bounce 0.6s ease-in-out infinite" : "gentleBob 2s ease-in-out infinite"
|
|
779
|
+
},
|
|
780
|
+
children: [
|
|
781
|
+
/* @__PURE__ */ jsx("ellipse", { cx: "50", cy: "60", rx: "35", ry: "30", fill: "#8b5cf6" }),
|
|
782
|
+
/* @__PURE__ */ jsx("ellipse", { cx: "50", cy: "65", rx: "25", ry: "20", fill: "#c4b5fd" }),
|
|
783
|
+
/* @__PURE__ */ jsx("circle", { cx: "50", cy: "35", r: "28", fill: "#a78bfa" }),
|
|
784
|
+
/* @__PURE__ */ jsx("polygon", { points: "28,15 35,30 22,28", fill: "#7c3aed" }),
|
|
785
|
+
/* @__PURE__ */ jsx("polygon", { points: "72,15 65,30 78,28", fill: "#7c3aed" }),
|
|
786
|
+
/* @__PURE__ */ jsx("ellipse", { cx: "38", cy: "38", rx: "10", ry: "12", fill: "white" }),
|
|
787
|
+
/* @__PURE__ */ jsx("ellipse", { cx: "62", cy: "38", rx: "10", ry: "12", fill: "white" }),
|
|
788
|
+
eyeExpr.leftEye ? /* @__PURE__ */ jsx("text", { x: "38", y: "44", textAnchor: "middle", fontSize: "16", fill: "#1f2937", children: eyeExpr.leftEye }) : /* @__PURE__ */ jsx("circle", { cx: "38", cy: eyeExpr.pupilY, r: "5", fill: "#1f2937" }),
|
|
789
|
+
eyeExpr.rightEye ? /* @__PURE__ */ jsx("text", { x: "62", y: "44", textAnchor: "middle", fontSize: "16", fill: "#1f2937", children: eyeExpr.rightEye }) : /* @__PURE__ */ jsx("circle", { cx: "62", cy: eyeExpr.pupilY, r: "5", fill: "#1f2937" }),
|
|
790
|
+
/* @__PURE__ */ jsx("polygon", { points: "50,45 45,52 55,52", fill: "#fbbf24" }),
|
|
791
|
+
(mood === "celebrating" || mood === "happy") && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
792
|
+
/* @__PURE__ */ jsx("ellipse", { cx: "28", cy: "45", rx: "5", ry: "3", fill: "#fda4af", opacity: "0.6" }),
|
|
793
|
+
/* @__PURE__ */ jsx("ellipse", { cx: "72", cy: "45", rx: "5", ry: "3", fill: "#fda4af", opacity: "0.6" })
|
|
794
|
+
] }),
|
|
795
|
+
mood === "celebrating" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
796
|
+
/* @__PURE__ */ jsx("ellipse", { cx: "18", cy: "55", rx: "8", ry: "15", fill: "#7c3aed", transform: "rotate(-30 18 55)" }),
|
|
797
|
+
/* @__PURE__ */ jsx("ellipse", { cx: "82", cy: "55", rx: "8", ry: "15", fill: "#7c3aed", transform: "rotate(30 82 55)" })
|
|
798
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
799
|
+
/* @__PURE__ */ jsx("ellipse", { cx: "20", cy: "60", rx: "8", ry: "15", fill: "#7c3aed" }),
|
|
800
|
+
/* @__PURE__ */ jsx("ellipse", { cx: "80", cy: "60", rx: "8", ry: "15", fill: "#7c3aed" })
|
|
801
|
+
] }),
|
|
802
|
+
/* @__PURE__ */ jsx("ellipse", { cx: "40", cy: "88", rx: "8", ry: "4", fill: "#fbbf24" }),
|
|
803
|
+
/* @__PURE__ */ jsx("ellipse", { cx: "60", cy: "88", rx: "8", ry: "4", fill: "#fbbf24" })
|
|
804
|
+
]
|
|
805
|
+
}
|
|
806
|
+
);
|
|
807
|
+
};
|
|
808
|
+
return /* @__PURE__ */ jsxs("div", { className, style: defaultStyles.container, children: [
|
|
809
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
810
|
+
@keyframes confettiFall {
|
|
811
|
+
0% {
|
|
812
|
+
transform: translateY(-10px) rotate(0deg);
|
|
813
|
+
opacity: 1;
|
|
814
|
+
}
|
|
815
|
+
100% {
|
|
816
|
+
transform: translateY(500px) rotate(720deg);
|
|
817
|
+
opacity: 0;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
@keyframes starPop {
|
|
821
|
+
0% {
|
|
822
|
+
transform: scale(0);
|
|
823
|
+
opacity: 0;
|
|
824
|
+
}
|
|
825
|
+
50% {
|
|
826
|
+
transform: scale(1.3);
|
|
827
|
+
}
|
|
828
|
+
100% {
|
|
829
|
+
transform: scale(1);
|
|
830
|
+
opacity: 1;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
@keyframes bounce {
|
|
834
|
+
0%, 100% {
|
|
835
|
+
transform: translateY(0);
|
|
836
|
+
}
|
|
837
|
+
50% {
|
|
838
|
+
transform: translateY(-10px);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
@keyframes gentleBob {
|
|
842
|
+
0%, 100% {
|
|
843
|
+
transform: translateY(0);
|
|
844
|
+
}
|
|
845
|
+
50% {
|
|
846
|
+
transform: translateY(-5px);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
@keyframes badgePop {
|
|
850
|
+
0% {
|
|
851
|
+
transform: scale(0) rotate(-10deg);
|
|
852
|
+
opacity: 0;
|
|
853
|
+
}
|
|
854
|
+
60% {
|
|
855
|
+
transform: scale(1.1) rotate(5deg);
|
|
856
|
+
}
|
|
857
|
+
100% {
|
|
858
|
+
transform: scale(1) rotate(0deg);
|
|
859
|
+
opacity: 1;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
@keyframes scoreSlideIn {
|
|
863
|
+
0% {
|
|
864
|
+
transform: translateY(20px);
|
|
865
|
+
opacity: 0;
|
|
866
|
+
}
|
|
867
|
+
100% {
|
|
868
|
+
transform: translateY(0);
|
|
869
|
+
opacity: 1;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
` }),
|
|
873
|
+
/* @__PURE__ */ jsxs("div", { style: defaultStyles.results, children: [
|
|
874
|
+
percentage >= 60 && /* @__PURE__ */ jsx("div", { style: defaultStyles.confettiContainer, children: confettiPieces.map((piece) => /* @__PURE__ */ jsx(
|
|
875
|
+
"div",
|
|
876
|
+
{
|
|
877
|
+
style: {
|
|
878
|
+
...defaultStyles.confettiPiece,
|
|
879
|
+
left: piece.left,
|
|
880
|
+
width: `${piece.size}px`,
|
|
881
|
+
height: `${piece.size}px`,
|
|
882
|
+
backgroundColor: piece.color,
|
|
883
|
+
borderRadius: Math.random() > 0.5 ? "50%" : "2px",
|
|
884
|
+
animationDelay: piece.delay,
|
|
885
|
+
animationDuration: piece.duration,
|
|
886
|
+
transform: `rotate(${piece.rotation}deg)`
|
|
887
|
+
}
|
|
888
|
+
},
|
|
889
|
+
piece.id
|
|
890
|
+
)) }),
|
|
891
|
+
/* @__PURE__ */ jsx("div", { style: { ...defaultStyles.resultsBackground, background: theme.bgGradient } }),
|
|
892
|
+
/* @__PURE__ */ jsxs("div", { style: defaultStyles.resultsContent, children: [
|
|
893
|
+
/* @__PURE__ */ jsxs("div", { style: defaultStyles.resultStars, children: [
|
|
894
|
+
/* @__PURE__ */ jsx(StarIcon, { filled: theme.stars >= 1, delay: 0.3 }),
|
|
895
|
+
/* @__PURE__ */ jsx(StarIcon, { filled: theme.stars >= 2, delay: 0.5 }),
|
|
896
|
+
/* @__PURE__ */ jsx(StarIcon, { filled: theme.stars >= 3, delay: 0.7 })
|
|
897
|
+
] }),
|
|
898
|
+
/* @__PURE__ */ jsx("div", { style: { marginBottom: "16px" }, children: /* @__PURE__ */ jsx(MascotOwl, { mood: theme.mascotMood }) }),
|
|
899
|
+
/* @__PURE__ */ jsx(
|
|
900
|
+
"div",
|
|
901
|
+
{
|
|
902
|
+
style: {
|
|
903
|
+
background: theme.badgeBg,
|
|
904
|
+
padding: "12px 28px",
|
|
905
|
+
borderRadius: "50px",
|
|
906
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
|
|
907
|
+
marginBottom: "20px",
|
|
908
|
+
animation: "badgePop 0.6s ease-out 0.2s forwards",
|
|
909
|
+
opacity: 0,
|
|
910
|
+
border: `3px solid ${theme.badgeColor}`
|
|
911
|
+
},
|
|
912
|
+
children: /* @__PURE__ */ jsx(
|
|
913
|
+
"span",
|
|
914
|
+
{
|
|
915
|
+
style: {
|
|
916
|
+
fontSize: "22px",
|
|
917
|
+
fontWeight: "700",
|
|
918
|
+
color: "#1f2937",
|
|
919
|
+
textShadow: "0 1px 2px rgba(255,255,255,0.5)"
|
|
920
|
+
},
|
|
921
|
+
children: theme.badge
|
|
922
|
+
}
|
|
923
|
+
)
|
|
924
|
+
}
|
|
925
|
+
),
|
|
926
|
+
/* @__PURE__ */ jsxs(
|
|
927
|
+
"div",
|
|
928
|
+
{
|
|
929
|
+
style: {
|
|
930
|
+
animation: "scoreSlideIn 0.5s ease-out 0.4s forwards",
|
|
931
|
+
opacity: 0
|
|
932
|
+
},
|
|
933
|
+
children: [
|
|
934
|
+
/* @__PURE__ */ jsxs(
|
|
935
|
+
"div",
|
|
936
|
+
{
|
|
937
|
+
style: {
|
|
938
|
+
fontSize: "48px",
|
|
939
|
+
fontWeight: "800",
|
|
940
|
+
color: theme.color,
|
|
941
|
+
lineHeight: "1",
|
|
942
|
+
marginBottom: "4px"
|
|
943
|
+
},
|
|
944
|
+
children: [
|
|
945
|
+
result.correctAnswers,
|
|
946
|
+
" of ",
|
|
947
|
+
result.totalQuestions
|
|
948
|
+
]
|
|
949
|
+
}
|
|
950
|
+
),
|
|
951
|
+
/* @__PURE__ */ jsx(
|
|
952
|
+
"div",
|
|
953
|
+
{
|
|
954
|
+
style: {
|
|
955
|
+
fontSize: "20px",
|
|
956
|
+
fontWeight: "600",
|
|
957
|
+
color: "#6b7280",
|
|
958
|
+
marginBottom: "12px"
|
|
959
|
+
},
|
|
960
|
+
children: "correct answers"
|
|
961
|
+
}
|
|
962
|
+
)
|
|
963
|
+
]
|
|
964
|
+
}
|
|
965
|
+
),
|
|
966
|
+
/* @__PURE__ */ jsxs("div", { style: { ...defaultStyles.resultDetails, marginTop: "8px" }, children: [
|
|
967
|
+
"Time: ",
|
|
968
|
+
formatTime(result.timeSpentSeconds)
|
|
969
|
+
] })
|
|
970
|
+
] })
|
|
493
971
|
] })
|
|
972
|
+
] });
|
|
973
|
+
}
|
|
974
|
+
if (quiz && showIntro) {
|
|
975
|
+
return /* @__PURE__ */ jsx("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ jsxs("div", { style: defaultStyles.intro, children: [
|
|
976
|
+
/* @__PURE__ */ jsx("div", { style: defaultStyles.introTitle, children: quiz.title }),
|
|
977
|
+
/* @__PURE__ */ jsx("div", { style: defaultStyles.introSubtitle, children: "Ready to test your knowledge?" }),
|
|
978
|
+
/* @__PURE__ */ jsxs("div", { style: defaultStyles.introQuestionCount, children: [
|
|
979
|
+
quiz.questions.length,
|
|
980
|
+
" question",
|
|
981
|
+
quiz.questions.length !== 1 ? "s" : "",
|
|
982
|
+
" to answer"
|
|
983
|
+
] }),
|
|
984
|
+
/* @__PURE__ */ jsx(
|
|
985
|
+
"button",
|
|
986
|
+
{
|
|
987
|
+
style: defaultStyles.startButton,
|
|
988
|
+
onClick: handleStart,
|
|
989
|
+
onMouseOver: (e) => {
|
|
990
|
+
e.currentTarget.style.transform = "translateY(-2px)";
|
|
991
|
+
e.currentTarget.style.boxShadow = "0 6px 20px rgba(124, 58, 237, 0.5)";
|
|
992
|
+
},
|
|
993
|
+
onMouseOut: (e) => {
|
|
994
|
+
e.currentTarget.style.transform = "translateY(0)";
|
|
995
|
+
e.currentTarget.style.boxShadow = "0 4px 14px rgba(124, 58, 237, 0.4)";
|
|
996
|
+
},
|
|
997
|
+
"data-testid": "button-start-quiz",
|
|
998
|
+
children: "Let's Start!"
|
|
999
|
+
}
|
|
1000
|
+
)
|
|
494
1001
|
] }) });
|
|
495
1002
|
}
|
|
496
1003
|
if (!quiz || !currentQuestion) {
|
|
497
1004
|
return /* @__PURE__ */ jsx("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ jsx("div", { style: defaultStyles.error, children: "No quiz data available" }) });
|
|
498
1005
|
}
|
|
499
1006
|
const selectedAnswer = answers.get(currentQuestion.id);
|
|
500
|
-
const isLastQuestion = currentQuestionIndex ===
|
|
501
|
-
const progressPercent = (currentQuestionIndex + 1) /
|
|
1007
|
+
const isLastQuestion = currentQuestionIndex === totalQuestions - 1;
|
|
1008
|
+
const progressPercent = (currentQuestionIndex + 1) / totalQuestions * 100;
|
|
1009
|
+
const remainingSlots = maxQuestions - totalQuestions;
|
|
1010
|
+
const questionsToAdd = Math.min(5, remainingSlots);
|
|
1011
|
+
const canAddMore = onGenerateMoreQuestions && remainingSlots > 0;
|
|
502
1012
|
return /* @__PURE__ */ jsxs("div", { className, style: defaultStyles.container, children: [
|
|
503
1013
|
/* @__PURE__ */ jsxs("div", { style: defaultStyles.header, children: [
|
|
504
|
-
/* @__PURE__ */
|
|
505
|
-
/* @__PURE__ */ jsx("div", { style: defaultStyles.title, children: quiz.title }),
|
|
506
|
-
/* @__PURE__ */ jsx("div", { style: defaultStyles.timer, children: formatTime(elapsedSeconds) })
|
|
507
|
-
] }),
|
|
1014
|
+
/* @__PURE__ */ jsx("div", { style: defaultStyles.title, children: quiz.title }),
|
|
508
1015
|
/* @__PURE__ */ jsxs("div", { style: defaultStyles.progress, children: [
|
|
509
1016
|
"Question ",
|
|
510
1017
|
currentQuestionIndex + 1,
|
|
511
1018
|
" of ",
|
|
512
|
-
|
|
1019
|
+
totalQuestions
|
|
513
1020
|
] }),
|
|
514
1021
|
/* @__PURE__ */ jsx("div", { style: defaultStyles.progressBar, children: /* @__PURE__ */ jsx("div", { style: { ...defaultStyles.progressFill, width: `${progressPercent}%` } }) })
|
|
515
1022
|
] }),
|
|
516
1023
|
/* @__PURE__ */ jsxs("div", { style: defaultStyles.question, children: [
|
|
517
1024
|
/* @__PURE__ */ jsx("div", { style: defaultStyles.questionText, children: currentQuestion.question }),
|
|
518
|
-
(currentQuestion.type === "single" || currentQuestion.type === "true-false") && /* @__PURE__ */ jsx("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) =>
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
1025
|
+
(currentQuestion.type === "single" || currentQuestion.type === "true-false") && /* @__PURE__ */ jsx("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) => {
|
|
1026
|
+
const isSelected = selectedAnswer === option;
|
|
1027
|
+
const isCorrectOption = currentQuestion.correctAnswer === option;
|
|
1028
|
+
let optionStyle = { ...defaultStyles.option };
|
|
1029
|
+
if (showFeedback) {
|
|
1030
|
+
if (isCorrectOption) {
|
|
1031
|
+
optionStyle = { ...optionStyle, ...defaultStyles.optionCorrect };
|
|
1032
|
+
} else if (isSelected && !isCorrectOption) {
|
|
1033
|
+
optionStyle = { ...optionStyle, ...defaultStyles.optionIncorrect };
|
|
1034
|
+
}
|
|
1035
|
+
} else if (isSelected) {
|
|
1036
|
+
optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
|
|
1037
|
+
}
|
|
1038
|
+
return /* @__PURE__ */ jsx(
|
|
1039
|
+
"div",
|
|
1040
|
+
{
|
|
1041
|
+
style: {
|
|
1042
|
+
...optionStyle,
|
|
1043
|
+
cursor: showFeedback ? "default" : "pointer"
|
|
1044
|
+
},
|
|
1045
|
+
onClick: () => !showFeedback && handleAnswerChange(option),
|
|
1046
|
+
children: option
|
|
524
1047
|
},
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
idx
|
|
529
|
-
)) }),
|
|
1048
|
+
idx
|
|
1049
|
+
);
|
|
1050
|
+
}) }),
|
|
530
1051
|
currentQuestion.type === "multiple" && /* @__PURE__ */ jsx("div", { style: defaultStyles.options, children: currentQuestion.options?.map((option, idx) => {
|
|
531
1052
|
const selected = Array.isArray(selectedAnswer) && selectedAnswer.includes(option);
|
|
1053
|
+
const correctAnswers = Array.isArray(currentQuestion.correctAnswer) ? currentQuestion.correctAnswer : currentQuestion.correctAnswer ? [currentQuestion.correctAnswer] : [];
|
|
1054
|
+
const isCorrectOption = correctAnswers.includes(option);
|
|
1055
|
+
let optionStyle = { ...defaultStyles.option };
|
|
1056
|
+
if (showFeedback) {
|
|
1057
|
+
if (isCorrectOption) {
|
|
1058
|
+
optionStyle = { ...optionStyle, ...defaultStyles.optionCorrect };
|
|
1059
|
+
} else if (selected && !isCorrectOption) {
|
|
1060
|
+
optionStyle = { ...optionStyle, ...defaultStyles.optionIncorrect };
|
|
1061
|
+
}
|
|
1062
|
+
} else if (selected) {
|
|
1063
|
+
optionStyle = { ...optionStyle, ...defaultStyles.optionSelected };
|
|
1064
|
+
}
|
|
532
1065
|
return /* @__PURE__ */ jsx(
|
|
533
1066
|
"div",
|
|
534
1067
|
{
|
|
535
1068
|
style: {
|
|
536
|
-
...
|
|
537
|
-
|
|
1069
|
+
...optionStyle,
|
|
1070
|
+
cursor: showFeedback ? "default" : "pointer"
|
|
538
1071
|
},
|
|
539
1072
|
onClick: () => {
|
|
1073
|
+
if (showFeedback) return;
|
|
540
1074
|
const current = Array.isArray(selectedAnswer) ? selectedAnswer : [];
|
|
541
1075
|
if (selected) {
|
|
542
1076
|
handleAnswerChange(current.filter((o) => o !== option));
|
|
@@ -555,7 +1089,8 @@ function QuizPlayer({
|
|
|
555
1089
|
style: { ...defaultStyles.input, minHeight: currentQuestion.type === "essay" ? "150px" : "60px" },
|
|
556
1090
|
value: selectedAnswer || "",
|
|
557
1091
|
onChange: (e) => handleAnswerChange(e.target.value),
|
|
558
|
-
placeholder: "Type your answer here..."
|
|
1092
|
+
placeholder: "Type your answer here...",
|
|
1093
|
+
disabled: showFeedback
|
|
559
1094
|
}
|
|
560
1095
|
),
|
|
561
1096
|
currentQuestion.type === "fill" && /* @__PURE__ */ jsx("div", { style: defaultStyles.options, children: currentQuestion.blanks?.map((_, idx) => /* @__PURE__ */ jsx(
|
|
@@ -568,50 +1103,93 @@ function QuizPlayer({
|
|
|
568
1103
|
current[idx] = e.target.value;
|
|
569
1104
|
handleAnswerChange(current);
|
|
570
1105
|
},
|
|
571
|
-
placeholder: `Blank ${idx + 1}
|
|
1106
|
+
placeholder: `Blank ${idx + 1}`,
|
|
1107
|
+
disabled: showFeedback
|
|
572
1108
|
},
|
|
573
1109
|
idx
|
|
574
|
-
)) })
|
|
1110
|
+
)) }),
|
|
1111
|
+
showFeedback && currentAnswerDetail && /* @__PURE__ */ jsxs("div", { style: {
|
|
1112
|
+
...defaultStyles.feedback,
|
|
1113
|
+
...currentAnswerDetail.isCorrect ? defaultStyles.feedbackCorrect : defaultStyles.feedbackIncorrect
|
|
1114
|
+
}, children: [
|
|
1115
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
1116
|
+
...defaultStyles.feedbackTitle,
|
|
1117
|
+
...currentAnswerDetail.isCorrect ? defaultStyles.feedbackTitleCorrect : defaultStyles.feedbackTitleIncorrect
|
|
1118
|
+
}, children: currentAnswerDetail.isCorrect ? "\u2713 Correct!" : "\u2717 Incorrect" }),
|
|
1119
|
+
currentQuestion.explanation && /* @__PURE__ */ jsx("div", { style: defaultStyles.feedbackExplanation, children: currentQuestion.explanation })
|
|
1120
|
+
] })
|
|
575
1121
|
] }),
|
|
576
|
-
/* @__PURE__ */ jsxs("div", { style: defaultStyles.
|
|
577
|
-
/* @__PURE__ */ jsx(
|
|
1122
|
+
/* @__PURE__ */ jsxs("div", { style: defaultStyles.buttonsColumn, children: [
|
|
1123
|
+
showFeedback && isLastQuestion && canAddMore && /* @__PURE__ */ jsx(
|
|
578
1124
|
"button",
|
|
579
1125
|
{
|
|
580
1126
|
style: {
|
|
581
|
-
...defaultStyles.
|
|
582
|
-
...
|
|
1127
|
+
...defaultStyles.buttonAddMore,
|
|
1128
|
+
...isGeneratingExtra ? defaultStyles.buttonAddMoreDisabled : {}
|
|
583
1129
|
},
|
|
584
|
-
onClick:
|
|
585
|
-
disabled:
|
|
586
|
-
|
|
1130
|
+
onClick: handleAddMoreQuestions,
|
|
1131
|
+
disabled: isGeneratingExtra,
|
|
1132
|
+
"data-testid": "button-add-more-questions",
|
|
1133
|
+
children: isGeneratingExtra ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1134
|
+
/* @__PURE__ */ jsx(Spinner, { size: 16, color: "#9ca3af" }),
|
|
1135
|
+
"Generating Questions..."
|
|
1136
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1137
|
+
"+ Add ",
|
|
1138
|
+
questionsToAdd,
|
|
1139
|
+
" More Question",
|
|
1140
|
+
questionsToAdd !== 1 ? "s" : ""
|
|
1141
|
+
] })
|
|
587
1142
|
}
|
|
588
1143
|
),
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
1144
|
+
/* @__PURE__ */ jsx("div", { style: { ...defaultStyles.buttons, justifyContent: "flex-end" }, children: showFeedback ? (
|
|
1145
|
+
// After viewing feedback
|
|
1146
|
+
isLastQuestion ? /* @__PURE__ */ jsx(
|
|
1147
|
+
"button",
|
|
1148
|
+
{
|
|
1149
|
+
style: {
|
|
1150
|
+
...defaultStyles.button,
|
|
1151
|
+
...isSubmitting || isGeneratingExtra ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary
|
|
1152
|
+
},
|
|
1153
|
+
onClick: handleSubmit,
|
|
1154
|
+
disabled: isSubmitting || isGeneratingExtra,
|
|
1155
|
+
"data-testid": "button-submit-quiz",
|
|
1156
|
+
children: isSubmitting ? /* @__PURE__ */ jsx(Spinner, { size: 16, color: "#9ca3af" }) : "Submit Quiz"
|
|
1157
|
+
}
|
|
1158
|
+
) : /* @__PURE__ */ jsx(
|
|
1159
|
+
"button",
|
|
1160
|
+
{
|
|
1161
|
+
style: {
|
|
1162
|
+
...defaultStyles.button,
|
|
1163
|
+
...defaultStyles.buttonPrimary
|
|
1164
|
+
},
|
|
1165
|
+
onClick: handleContinue,
|
|
1166
|
+
"data-testid": "button-continue",
|
|
1167
|
+
children: "Continue"
|
|
1168
|
+
}
|
|
1169
|
+
)
|
|
1170
|
+
) : (
|
|
1171
|
+
// Before checking answer
|
|
1172
|
+
/* @__PURE__ */ jsx(
|
|
1173
|
+
"button",
|
|
1174
|
+
{
|
|
1175
|
+
style: {
|
|
1176
|
+
...defaultStyles.button,
|
|
1177
|
+
...isNavigating || selectedAnswer === void 0 ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary
|
|
1178
|
+
},
|
|
1179
|
+
onClick: handleCheckAnswer,
|
|
1180
|
+
disabled: isNavigating || selectedAnswer === void 0,
|
|
1181
|
+
"data-testid": "button-check-answer",
|
|
1182
|
+
children: isNavigating ? /* @__PURE__ */ jsx(Spinner, { size: 16, color: "#9ca3af" }) : "Check Answer"
|
|
1183
|
+
}
|
|
1184
|
+
)
|
|
1185
|
+
) })
|
|
612
1186
|
] })
|
|
613
1187
|
] });
|
|
614
1188
|
}
|
|
1189
|
+
|
|
1190
|
+
// src/AttemptViewer.tsx
|
|
1191
|
+
import { useState as useState2, useEffect as useEffect2 } from "react";
|
|
1192
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
615
1193
|
var defaultStyles2 = {
|
|
616
1194
|
container: {
|
|
617
1195
|
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
@@ -626,6 +1204,12 @@ var defaultStyles2 = {
|
|
|
626
1204
|
borderBottom: "1px solid #e5e7eb",
|
|
627
1205
|
paddingBottom: "20px"
|
|
628
1206
|
},
|
|
1207
|
+
title: {
|
|
1208
|
+
fontSize: "24px",
|
|
1209
|
+
fontWeight: "600",
|
|
1210
|
+
marginBottom: "16px",
|
|
1211
|
+
color: "#111827"
|
|
1212
|
+
},
|
|
629
1213
|
summaryGrid: {
|
|
630
1214
|
display: "grid",
|
|
631
1215
|
gridTemplateColumns: "repeat(auto-fit, minmax(120px, 1fr))",
|
|
@@ -785,11 +1369,11 @@ function AttemptViewer({
|
|
|
785
1369
|
showExplanations = true,
|
|
786
1370
|
title
|
|
787
1371
|
}) {
|
|
788
|
-
const [attempt, setAttempt] =
|
|
789
|
-
const [loading, setLoading] =
|
|
790
|
-
const [error, setError] =
|
|
791
|
-
|
|
792
|
-
new QuizApiClient({
|
|
1372
|
+
const [attempt, setAttempt] = useState2(null);
|
|
1373
|
+
const [loading, setLoading] = useState2(true);
|
|
1374
|
+
const [error, setError] = useState2(null);
|
|
1375
|
+
useEffect2(() => {
|
|
1376
|
+
const apiClient = new QuizApiClient({
|
|
793
1377
|
baseUrl: apiBaseUrl,
|
|
794
1378
|
authToken
|
|
795
1379
|
});
|
|
@@ -821,49 +1405,49 @@ function AttemptViewer({
|
|
|
821
1405
|
window.location.reload();
|
|
822
1406
|
};
|
|
823
1407
|
if (loading) {
|
|
824
|
-
return /* @__PURE__ */
|
|
825
|
-
/* @__PURE__ */
|
|
826
|
-
/* @__PURE__ */
|
|
827
|
-
/* @__PURE__ */
|
|
828
|
-
/* @__PURE__ */
|
|
1408
|
+
return /* @__PURE__ */ jsxs2("div", { style: defaultStyles2.container, className, children: [
|
|
1409
|
+
/* @__PURE__ */ jsx2("style", { children: spinnerKeyframes }),
|
|
1410
|
+
/* @__PURE__ */ jsxs2("div", { style: defaultStyles2.loading, children: [
|
|
1411
|
+
/* @__PURE__ */ jsx2("div", { style: defaultStyles2.spinner }),
|
|
1412
|
+
/* @__PURE__ */ jsx2("p", { style: { marginTop: "16px", color: "#6b7280" }, children: "Loading attempt..." })
|
|
829
1413
|
] })
|
|
830
1414
|
] });
|
|
831
1415
|
}
|
|
832
1416
|
if (error || !attempt) {
|
|
833
|
-
return /* @__PURE__ */
|
|
834
|
-
/* @__PURE__ */
|
|
835
|
-
/* @__PURE__ */
|
|
836
|
-
/* @__PURE__ */
|
|
1417
|
+
return /* @__PURE__ */ jsx2("div", { style: defaultStyles2.container, className, children: /* @__PURE__ */ jsxs2("div", { style: defaultStyles2.error, children: [
|
|
1418
|
+
/* @__PURE__ */ jsx2("p", { style: { fontSize: "18px", fontWeight: "500" }, children: "Failed to load attempt" }),
|
|
1419
|
+
/* @__PURE__ */ jsx2("p", { style: { marginTop: "8px", color: "#6b7280" }, children: error }),
|
|
1420
|
+
/* @__PURE__ */ jsx2("button", { style: defaultStyles2.retryButton, onClick: handleRetry, children: "Try Again" })
|
|
837
1421
|
] }) });
|
|
838
1422
|
}
|
|
839
1423
|
const scorePercentage = attempt.score ?? 0;
|
|
840
1424
|
const correctCount = attempt.correctAnswers ?? 0;
|
|
841
1425
|
const totalQuestions = attempt.totalQuestions;
|
|
842
1426
|
const timeSpent = attempt.timeSpentSeconds ?? 0;
|
|
843
|
-
return /* @__PURE__ */
|
|
844
|
-
/* @__PURE__ */
|
|
845
|
-
/* @__PURE__ */
|
|
846
|
-
/* @__PURE__ */
|
|
847
|
-
/* @__PURE__ */
|
|
1427
|
+
return /* @__PURE__ */ jsxs2("div", { style: defaultStyles2.container, className, children: [
|
|
1428
|
+
/* @__PURE__ */ jsx2("style", { children: spinnerKeyframes }),
|
|
1429
|
+
/* @__PURE__ */ jsx2("div", { style: defaultStyles2.header, children: /* @__PURE__ */ jsxs2("div", { style: defaultStyles2.summaryGrid, children: [
|
|
1430
|
+
/* @__PURE__ */ jsxs2("div", { style: defaultStyles2.summaryCard, children: [
|
|
1431
|
+
/* @__PURE__ */ jsxs2("div", { style: defaultStyles2.summaryValue, children: [
|
|
848
1432
|
scorePercentage,
|
|
849
1433
|
"%"
|
|
850
1434
|
] }),
|
|
851
|
-
/* @__PURE__ */
|
|
1435
|
+
/* @__PURE__ */ jsx2("div", { style: defaultStyles2.summaryLabel, children: "Score" })
|
|
852
1436
|
] }),
|
|
853
|
-
/* @__PURE__ */
|
|
854
|
-
/* @__PURE__ */
|
|
1437
|
+
/* @__PURE__ */ jsxs2("div", { style: defaultStyles2.summaryCard, children: [
|
|
1438
|
+
/* @__PURE__ */ jsxs2("div", { style: defaultStyles2.summaryValue, children: [
|
|
855
1439
|
correctCount,
|
|
856
1440
|
"/",
|
|
857
1441
|
totalQuestions
|
|
858
1442
|
] }),
|
|
859
|
-
/* @__PURE__ */
|
|
1443
|
+
/* @__PURE__ */ jsx2("div", { style: defaultStyles2.summaryLabel, children: "Correct" })
|
|
860
1444
|
] }),
|
|
861
|
-
/* @__PURE__ */
|
|
862
|
-
/* @__PURE__ */
|
|
863
|
-
/* @__PURE__ */
|
|
1445
|
+
/* @__PURE__ */ jsxs2("div", { style: defaultStyles2.summaryCard, children: [
|
|
1446
|
+
/* @__PURE__ */ jsx2("div", { style: defaultStyles2.summaryValue, children: formatTime(timeSpent) }),
|
|
1447
|
+
/* @__PURE__ */ jsx2("div", { style: defaultStyles2.summaryLabel, children: "Time" })
|
|
864
1448
|
] })
|
|
865
1449
|
] }) }),
|
|
866
|
-
/* @__PURE__ */
|
|
1450
|
+
/* @__PURE__ */ jsx2("div", { style: defaultStyles2.questionsList, children: attempt.answers.map((answer, index) => /* @__PURE__ */ jsxs2(
|
|
867
1451
|
"div",
|
|
868
1452
|
{
|
|
869
1453
|
style: {
|
|
@@ -871,12 +1455,12 @@ function AttemptViewer({
|
|
|
871
1455
|
...answer.isCorrect ? defaultStyles2.questionCardCorrect : defaultStyles2.questionCardIncorrect
|
|
872
1456
|
},
|
|
873
1457
|
children: [
|
|
874
|
-
/* @__PURE__ */
|
|
875
|
-
/* @__PURE__ */
|
|
1458
|
+
/* @__PURE__ */ jsxs2("div", { style: defaultStyles2.questionHeader, children: [
|
|
1459
|
+
/* @__PURE__ */ jsxs2("span", { style: defaultStyles2.questionNumber, children: [
|
|
876
1460
|
"Question ",
|
|
877
1461
|
index + 1
|
|
878
1462
|
] }),
|
|
879
|
-
/* @__PURE__ */
|
|
1463
|
+
/* @__PURE__ */ jsx2(
|
|
880
1464
|
"span",
|
|
881
1465
|
{
|
|
882
1466
|
style: {
|
|
@@ -887,23 +1471,23 @@ function AttemptViewer({
|
|
|
887
1471
|
}
|
|
888
1472
|
)
|
|
889
1473
|
] }),
|
|
890
|
-
/* @__PURE__ */
|
|
891
|
-
/* @__PURE__ */
|
|
892
|
-
/* @__PURE__ */
|
|
893
|
-
/* @__PURE__ */
|
|
1474
|
+
/* @__PURE__ */ jsx2("div", { style: defaultStyles2.questionText, children: answer.questionText }),
|
|
1475
|
+
/* @__PURE__ */ jsxs2("div", { style: defaultStyles2.answerSection, children: [
|
|
1476
|
+
/* @__PURE__ */ jsx2("span", { style: defaultStyles2.answerLabel, children: "Your answer:" }),
|
|
1477
|
+
/* @__PURE__ */ jsx2("span", { style: defaultStyles2.studentAnswer, children: formatAnswer(answer.selectedAnswer) })
|
|
894
1478
|
] }),
|
|
895
|
-
!answer.isCorrect && answer.correctAnswer && /* @__PURE__ */
|
|
896
|
-
/* @__PURE__ */
|
|
897
|
-
/* @__PURE__ */
|
|
1479
|
+
!answer.isCorrect && answer.correctAnswer && /* @__PURE__ */ jsxs2("div", { style: defaultStyles2.answerSection, children: [
|
|
1480
|
+
/* @__PURE__ */ jsx2("span", { style: defaultStyles2.answerLabel, children: "Correct answer:" }),
|
|
1481
|
+
/* @__PURE__ */ jsx2("span", { style: defaultStyles2.correctAnswer, children: formatAnswer(answer.correctAnswer) })
|
|
898
1482
|
] }),
|
|
899
|
-
/* @__PURE__ */
|
|
1483
|
+
/* @__PURE__ */ jsxs2("div", { style: defaultStyles2.points, children: [
|
|
900
1484
|
answer.pointsEarned,
|
|
901
1485
|
" / ",
|
|
902
1486
|
answer.points,
|
|
903
1487
|
" points"
|
|
904
1488
|
] }),
|
|
905
|
-
showExplanations && answer.explanation && /* @__PURE__ */
|
|
906
|
-
/* @__PURE__ */
|
|
1489
|
+
showExplanations && answer.explanation && /* @__PURE__ */ jsxs2("div", { style: defaultStyles2.explanation, children: [
|
|
1490
|
+
/* @__PURE__ */ jsx2("strong", { children: "Explanation:" }),
|
|
907
1491
|
" ",
|
|
908
1492
|
answer.explanation
|
|
909
1493
|
] })
|
|
@@ -913,7 +1497,13 @@ function AttemptViewer({
|
|
|
913
1497
|
)) })
|
|
914
1498
|
] });
|
|
915
1499
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1500
|
+
export {
|
|
1501
|
+
AttemptViewer,
|
|
1502
|
+
QuizApiClient,
|
|
1503
|
+
QuizPlayer,
|
|
1504
|
+
calculateScore,
|
|
1505
|
+
checkAnswer,
|
|
1506
|
+
createAnswerDetail,
|
|
1507
|
+
formatTime
|
|
1508
|
+
};
|
|
919
1509
|
//# sourceMappingURL=index.mjs.map
|