@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.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
- maxWidth: "800px",
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
- padding: "40px 20px"
291
+ minHeight: "400px",
292
+ position: "relative",
293
+ overflow: "hidden"
246
294
  },
247
- resultScore: {
248
- fontSize: "48px",
249
- fontWeight: "700",
250
- color: "#6721b0",
251
- marginBottom: "8px"
295
+ resultsBackground: {
296
+ position: "absolute",
297
+ inset: "0",
298
+ borderRadius: "16px",
299
+ zIndex: 0
252
300
  },
253
- resultLabel: {
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(Date.now());
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 (!isLoading && !isCompleted && !error) {
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
- }, [isLoading, isCompleted, error]);
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: quiz.questions.length,
554
+ totalQuestions,
382
555
  answeredQuestions: answers.size
383
556
  });
384
557
  }
385
- }, [currentQuestionIndex, answers.size, quiz, onProgress]);
386
- const currentQuestion = quiz?.questions[currentQuestionIndex];
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 handleNext = useCallback(async () => {
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
- if (currentQuestionIndex < quiz.questions.length - 1) {
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, attempt, currentQuestion, answers, answersDetail, currentQuestionIndex]);
418
- const handlePrevious = useCallback(() => {
419
- if (currentQuestionIndex > 0) {
420
- setCurrentQuestionIndex((prev) => prev - 1);
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
- }, [currentQuestionIndex]);
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: quiz.questions.length,
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
- return /* @__PURE__ */ jsx("div", { className, style: defaultStyles.container, children: /* @__PURE__ */ jsxs("div", { style: defaultStyles.results, children: [
480
- /* @__PURE__ */ jsxs("div", { style: defaultStyles.resultScore, children: [
481
- result.score,
482
- "%"
483
- ] }),
484
- /* @__PURE__ */ jsxs("div", { style: defaultStyles.resultLabel, children: [
485
- result.correctAnswers,
486
- " of ",
487
- result.totalQuestions,
488
- " correct"
489
- ] }),
490
- /* @__PURE__ */ jsxs("div", { style: { ...defaultStyles.resultLabel, marginTop: "8px" }, children: [
491
- "Time: ",
492
- formatTime(result.timeSpentSeconds)
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 === quiz.questions.length - 1;
501
- const progressPercent = (currentQuestionIndex + 1) / quiz.questions.length * 100;
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__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
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
- quiz.questions.length
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) => /* @__PURE__ */ jsx(
519
- "div",
520
- {
521
- style: {
522
- ...defaultStyles.option,
523
- ...selectedAnswer === option ? defaultStyles.optionSelected : {}
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
- onClick: () => handleAnswerChange(option),
526
- children: option
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
- ...defaultStyles.option,
537
- ...selected ? defaultStyles.optionSelected : {}
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.buttons, children: [
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.button,
582
- ...currentQuestionIndex > 0 ? defaultStyles.buttonSecondary : defaultStyles.buttonDisabled
1127
+ ...defaultStyles.buttonAddMore,
1128
+ ...isGeneratingExtra ? defaultStyles.buttonAddMoreDisabled : {}
583
1129
  },
584
- onClick: handlePrevious,
585
- disabled: currentQuestionIndex === 0,
586
- children: "Previous"
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
- isLastQuestion ? /* @__PURE__ */ jsx(
590
- "button",
591
- {
592
- style: {
593
- ...defaultStyles.button,
594
- ...isSubmitting ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary
595
- },
596
- onClick: handleSubmit,
597
- disabled: isSubmitting || selectedAnswer === void 0,
598
- children: isSubmitting ? /* @__PURE__ */ jsx(Spinner, { size: 16, color: "#9ca3af" }) : "Submit Quiz"
599
- }
600
- ) : /* @__PURE__ */ jsx(
601
- "button",
602
- {
603
- style: {
604
- ...defaultStyles.button,
605
- ...isNavigating || selectedAnswer === void 0 ? defaultStyles.buttonDisabled : defaultStyles.buttonPrimary
606
- },
607
- onClick: handleNext,
608
- disabled: isNavigating || selectedAnswer === void 0,
609
- children: isNavigating ? /* @__PURE__ */ jsx(Spinner, { size: 16, color: "#9ca3af" }) : "Next"
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] = useState(null);
789
- const [loading, setLoading] = useState(true);
790
- const [error, setError] = useState(null);
791
- useEffect(() => {
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__ */ jsxs("div", { style: defaultStyles2.container, className, children: [
825
- /* @__PURE__ */ jsx("style", { children: spinnerKeyframes }),
826
- /* @__PURE__ */ jsxs("div", { style: defaultStyles2.loading, children: [
827
- /* @__PURE__ */ jsx("div", { style: defaultStyles2.spinner }),
828
- /* @__PURE__ */ jsx("p", { style: { marginTop: "16px", color: "#6b7280" }, children: "Loading attempt..." })
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__ */ jsx("div", { style: defaultStyles2.container, className, children: /* @__PURE__ */ jsxs("div", { style: defaultStyles2.error, children: [
834
- /* @__PURE__ */ jsx("p", { style: { fontSize: "18px", fontWeight: "500" }, children: "Failed to load attempt" }),
835
- /* @__PURE__ */ jsx("p", { style: { marginTop: "8px", color: "#6b7280" }, children: error }),
836
- /* @__PURE__ */ jsx("button", { style: defaultStyles2.retryButton, onClick: handleRetry, children: "Try Again" })
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__ */ jsxs("div", { style: defaultStyles2.container, className, children: [
844
- /* @__PURE__ */ jsx("style", { children: spinnerKeyframes }),
845
- /* @__PURE__ */ jsx("div", { style: defaultStyles2.header, children: /* @__PURE__ */ jsxs("div", { style: defaultStyles2.summaryGrid, children: [
846
- /* @__PURE__ */ jsxs("div", { style: defaultStyles2.summaryCard, children: [
847
- /* @__PURE__ */ jsxs("div", { style: defaultStyles2.summaryValue, children: [
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__ */ jsx("div", { style: defaultStyles2.summaryLabel, children: "Score" })
1435
+ /* @__PURE__ */ jsx2("div", { style: defaultStyles2.summaryLabel, children: "Score" })
852
1436
  ] }),
853
- /* @__PURE__ */ jsxs("div", { style: defaultStyles2.summaryCard, children: [
854
- /* @__PURE__ */ jsxs("div", { style: defaultStyles2.summaryValue, children: [
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__ */ jsx("div", { style: defaultStyles2.summaryLabel, children: "Correct" })
1443
+ /* @__PURE__ */ jsx2("div", { style: defaultStyles2.summaryLabel, children: "Correct" })
860
1444
  ] }),
861
- /* @__PURE__ */ jsxs("div", { style: defaultStyles2.summaryCard, children: [
862
- /* @__PURE__ */ jsx("div", { style: defaultStyles2.summaryValue, children: formatTime(timeSpent) }),
863
- /* @__PURE__ */ jsx("div", { style: defaultStyles2.summaryLabel, children: "Time" })
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__ */ jsx("div", { style: defaultStyles2.questionsList, children: attempt.answers.map((answer, index) => /* @__PURE__ */ jsxs(
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__ */ jsxs("div", { style: defaultStyles2.questionHeader, children: [
875
- /* @__PURE__ */ jsxs("span", { style: defaultStyles2.questionNumber, children: [
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__ */ jsx(
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__ */ jsx("div", { style: defaultStyles2.questionText, children: answer.questionText }),
891
- /* @__PURE__ */ jsxs("div", { style: defaultStyles2.answerSection, children: [
892
- /* @__PURE__ */ jsx("span", { style: defaultStyles2.answerLabel, children: "Your answer:" }),
893
- /* @__PURE__ */ jsx("span", { style: defaultStyles2.studentAnswer, children: formatAnswer(answer.selectedAnswer) })
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__ */ jsxs("div", { style: defaultStyles2.answerSection, children: [
896
- /* @__PURE__ */ jsx("span", { style: defaultStyles2.answerLabel, children: "Correct answer:" }),
897
- /* @__PURE__ */ jsx("span", { style: defaultStyles2.correctAnswer, children: formatAnswer(answer.correctAnswer) })
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__ */ jsxs("div", { style: defaultStyles2.points, children: [
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__ */ jsxs("div", { style: defaultStyles2.explanation, children: [
906
- /* @__PURE__ */ jsx("strong", { children: "Explanation:" }),
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
- export { AttemptViewer, QuizApiClient, QuizPlayer, calculateScore, checkAnswer, createAnswerDetail, formatTime };
918
- //# sourceMappingURL=index.mjs.map
1500
+ export {
1501
+ AttemptViewer,
1502
+ QuizApiClient,
1503
+ QuizPlayer,
1504
+ calculateScore,
1505
+ checkAnswer,
1506
+ createAnswerDetail,
1507
+ formatTime
1508
+ };
919
1509
  //# sourceMappingURL=index.mjs.map