@thanh01.pmt/interactive-quiz-kit 1.0.24 → 1.0.25

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/player.js CHANGED
@@ -1,5 +1,5 @@
1
- import * as React28 from 'react';
2
- import React28__default, { useRef, useState, useImperativeHandle, useCallback, useEffect, forwardRef, useMemo } from 'react';
1
+ import * as React9 from 'react';
2
+ import React9__default, { useRef, useState, useImperativeHandle, useCallback, useEffect, forwardRef, useMemo } from 'react';
3
3
  import ReactDOM from 'react-dom/client';
4
4
  import { useTranslation } from 'react-i18next';
5
5
  import { z } from 'zod';
@@ -9,6 +9,7 @@ import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
9
9
  import { Circle, Check, ChevronDown, ChevronUp, Loader2, Play, CheckCircle, XCircle, RotateCcw, BarChart2, Clock, Percent, AlertTriangle, LogOut, Wand2, AlertCircle, ChevronLeft, ChevronRight } from 'lucide-react';
10
10
  import { clsx } from 'clsx';
11
11
  import { twMerge } from 'tailwind-merge';
12
+ import { jsx, jsxs } from 'react/jsx-runtime';
12
13
  import * as LabelPrimitive from '@radix-ui/react-label';
13
14
  import { cva } from 'class-variance-authority';
14
15
  import ReactMarkdown from 'react-markdown';
@@ -28,37 +29,7 @@ import * as ProgressPrimitive from '@radix-ui/react-progress';
28
29
  import * as AccordionPrimitive from '@radix-ui/react-accordion';
29
30
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
30
31
 
31
- var __defProp = Object.defineProperty;
32
- var __defProps = Object.defineProperties;
33
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
34
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
35
- var __hasOwnProp = Object.prototype.hasOwnProperty;
36
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
37
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
38
- var __spreadValues = (a, b) => {
39
- for (var prop in b || (b = {}))
40
- if (__hasOwnProp.call(b, prop))
41
- __defNormalProp(a, prop, b[prop]);
42
- if (__getOwnPropSymbols)
43
- for (var prop of __getOwnPropSymbols(b)) {
44
- if (__propIsEnum.call(b, prop))
45
- __defNormalProp(a, prop, b[prop]);
46
- }
47
- return a;
48
- };
49
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
50
- var __objRest = (source, exclude) => {
51
- var target = {};
52
- for (var prop in source)
53
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
54
- target[prop] = source[prop];
55
- if (source != null && __getOwnPropSymbols)
56
- for (var prop of __getOwnPropSymbols(source)) {
57
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
58
- target[prop] = source[prop];
59
- }
60
- return target;
61
- };
32
+ // src/player.ts
62
33
 
63
34
  // src/services/SCORMService.ts
64
35
  var SCORM_TRUE = "true";
@@ -79,11 +50,12 @@ var SCORMService = class {
79
50
  this.isInitialized = false;
80
51
  this.isTerminated = false;
81
52
  this.studentName = null;
82
- this.settings = __spreadValues({
53
+ this.settings = {
83
54
  setCompletionOnFinish: true,
84
55
  setSuccessOnPass: true,
85
- autoCommit: true
86
- }, settings);
56
+ autoCommit: true,
57
+ ...settings
58
+ };
87
59
  if (typeof window !== "undefined") {
88
60
  this._findAPI();
89
61
  }
@@ -189,14 +161,13 @@ var SCORMService = class {
189
161
  }
190
162
  }
191
163
  getValue(element) {
192
- var _a;
193
164
  if (!this.hasAPI() || !this.isInitialized) return null;
194
165
  const value = this.scormVersionFound === "2004" ? this.scormAPI.GetValue(element) : this.scormAPI.LMSGetValue(element);
195
166
  const error = this.getLastError();
196
167
  if (error.code !== SCORM_NO_ERROR && error.code !== "403" && error.code !== "0") {
197
168
  console.warn(`SCORMService: GetValue for ${element} produced an error ${error.code}: ${error.message}. Returning raw value:`, value);
198
169
  }
199
- return (_a = value == null ? void 0 : value.toString()) != null ? _a : null;
170
+ return value?.toString() ?? null;
200
171
  }
201
172
  commit() {
202
173
  if (!this.hasAPI() || !this.isInitialized) {
@@ -268,7 +239,6 @@ var SCORMService = class {
268
239
  }
269
240
  }
270
241
  getLastError() {
271
- var _a, _b;
272
242
  if (!this.hasAPI()) return { code: "-1", message: "SCORM API not found." };
273
243
  const errorCode = this.scormVersionFound === "2004" ? this.scormAPI.GetLastError() : this.scormAPI.LMSGetLastError();
274
244
  if (errorCode === SCORM_NO_ERROR || errorCode === 0 || errorCode === "0") {
@@ -278,8 +248,8 @@ var SCORMService = class {
278
248
  const diagnostic = this.scormVersionFound === "2004" ? this.scormAPI.GetDiagnostic(errorCode.toString()) : this.scormAPI.LMSGetDiagnostic(errorCode.toString());
279
249
  return {
280
250
  code: errorCode.toString(),
281
- message: (_a = errorMessage == null ? void 0 : errorMessage.toString()) != null ? _a : "Unknown error.",
282
- diagnostic: (_b = diagnostic == null ? void 0 : diagnostic.toString()) != null ? _b : void 0
251
+ message: errorMessage?.toString() ?? "Unknown error.",
252
+ diagnostic: diagnostic?.toString() ?? void 0
283
253
  };
284
254
  }
285
255
  formatCMITime(totalSeconds) {
@@ -310,14 +280,13 @@ var SCORMService = class {
310
280
  // src/services/evaluators/multiple-choice-evaluator.ts
311
281
  var MultipleChoiceEvaluator = class {
312
282
  async evaluate(question, answer) {
313
- var _a;
314
- const points = (_a = question.points) != null ? _a : 0;
283
+ const points = question.points ?? 0;
315
284
  const correctAnswerId = question.correctAnswerId;
316
285
  const isCorrect = answer === correctAnswerId;
317
286
  const correctOption = question.options.find((opt) => opt.id === correctAnswerId);
318
287
  const correctAnswerDetail = {
319
288
  id: correctAnswerId,
320
- value: (correctOption == null ? void 0 : correctOption.text) || ""
289
+ value: correctOption?.text || ""
321
290
  };
322
291
  return Promise.resolve({
323
292
  isCorrect,
@@ -330,8 +299,7 @@ var MultipleChoiceEvaluator = class {
330
299
  // src/services/evaluators/multiple-response-evaluator.ts
331
300
  var MultipleResponseEvaluator = class {
332
301
  async evaluate(question, answer) {
333
- var _a;
334
- const points = (_a = question.points) != null ? _a : 0;
302
+ const points = question.points ?? 0;
335
303
  const correctAnswerIds = question.correctAnswerIds;
336
304
  let isCorrect = false;
337
305
  if (Array.isArray(answer)) {
@@ -340,10 +308,7 @@ var MultipleResponseEvaluator = class {
340
308
  isCorrect = userAnswerSet.size === correctAnswerSet.size && [...userAnswerSet].every((id) => correctAnswerSet.has(id));
341
309
  }
342
310
  const correctValues = correctAnswerIds.map(
343
- (id) => {
344
- var _a2;
345
- return ((_a2 = question.options.find((opt) => opt.id === id)) == null ? void 0 : _a2.text) || "";
346
- }
311
+ (id) => question.options.find((opt) => opt.id === id)?.text || ""
347
312
  );
348
313
  const correctAnswerDetail = {
349
314
  id: correctAnswerIds,
@@ -360,8 +325,7 @@ var MultipleResponseEvaluator = class {
360
325
  // src/services/evaluators/true-false-evaluator.ts
361
326
  var TrueFalseEvaluator = class {
362
327
  async evaluate(question, answer) {
363
- var _a;
364
- const points = (_a = question.points) != null ? _a : 0;
328
+ const points = question.points ?? 0;
365
329
  const correctAnswer = question.correctAnswer;
366
330
  let userAnswer = answer;
367
331
  if (typeof answer === "string") {
@@ -383,12 +347,11 @@ var TrueFalseEvaluator = class {
383
347
  // src/services/evaluators/short-answer-evaluator.ts
384
348
  var ShortAnswerEvaluator = class {
385
349
  async evaluate(question, answer) {
386
- var _a, _b;
387
- const points = (_a = question.points) != null ? _a : 0;
350
+ const points = question.points ?? 0;
388
351
  let isCorrect = false;
389
352
  if (typeof answer === "string") {
390
353
  const userAnswerTrimmed = answer.trim();
391
- const caseSensitive = (_b = question.isCaseSensitive) != null ? _b : false;
354
+ const caseSensitive = question.isCaseSensitive ?? false;
392
355
  isCorrect = question.acceptedAnswers.some(
393
356
  (accAns) => caseSensitive ? accAns.trim() === userAnswerTrimmed : accAns.trim().toLowerCase() === userAnswerTrimmed.toLowerCase()
394
357
  );
@@ -408,8 +371,7 @@ var ShortAnswerEvaluator = class {
408
371
  // src/services/evaluators/numeric-evaluator.ts
409
372
  var NumericEvaluator = class {
410
373
  async evaluate(question, answer) {
411
- var _a;
412
- const points = (_a = question.points) != null ? _a : 0;
374
+ const points = question.points ?? 0;
413
375
  let isCorrect = false;
414
376
  if (typeof answer === "string" || typeof answer === "number") {
415
377
  const userAnswerNum = parseFloat(String(answer));
@@ -432,17 +394,13 @@ var NumericEvaluator = class {
432
394
  // src/services/evaluators/sequence-evaluator.ts
433
395
  var SequenceEvaluator = class {
434
396
  async evaluate(question, answer) {
435
- var _a;
436
- const points = (_a = question.points) != null ? _a : 0;
397
+ const points = question.points ?? 0;
437
398
  let isCorrect = false;
438
399
  if (Array.isArray(answer) && answer.length === question.correctOrder.length) {
439
400
  isCorrect = answer.every((itemId, index) => itemId === question.correctOrder[index]);
440
401
  }
441
402
  const correctValues = question.correctOrder.map(
442
- (id) => {
443
- var _a2;
444
- return ((_a2 = question.items.find((item) => item.id === id)) == null ? void 0 : _a2.content) || "";
445
- }
403
+ (id) => question.items.find((item) => item.id === id)?.content || ""
446
404
  );
447
405
  const correctAnswerDetail = {
448
406
  id: question.correctOrder,
@@ -459,17 +417,15 @@ var SequenceEvaluator = class {
459
417
  // src/services/evaluators/matching-evaluator.ts
460
418
  var MatchingEvaluator = class {
461
419
  async evaluate(question, answer) {
462
- var _a;
463
- const points = (_a = question.points) != null ? _a : 0;
420
+ const points = question.points ?? 0;
464
421
  let isCorrect = false;
465
422
  if (typeof answer === "object" && answer !== null && !Array.isArray(answer)) {
466
423
  const userAnswerMap = answer;
467
424
  isCorrect = question.correctAnswerMap.length === Object.keys(userAnswerMap).length && question.correctAnswerMap.every((map) => userAnswerMap[map.promptId] === map.optionId);
468
425
  }
469
426
  const correctMap = question.correctAnswerMap.reduce((acc, curr) => {
470
- var _a2, _b;
471
- const promptText = ((_a2 = question.prompts.find((p) => p.id === curr.promptId)) == null ? void 0 : _a2.content) || "";
472
- const optionText = ((_b = question.options.find((o) => o.id === curr.optionId)) == null ? void 0 : _b.content) || "";
427
+ const promptText = question.prompts.find((p) => p.id === curr.promptId)?.content || "";
428
+ const optionText = question.options.find((o) => o.id === curr.optionId)?.content || "";
473
429
  acc[promptText] = optionText;
474
430
  return acc;
475
431
  }, {});
@@ -488,16 +444,14 @@ var MatchingEvaluator = class {
488
444
  // src/services/evaluators/fill-in-the-blanks-evaluator.ts
489
445
  var FillInTheBlanksEvaluator = class {
490
446
  async evaluate(question, answer) {
491
- var _a;
492
- const points = (_a = question.points) != null ? _a : 0;
447
+ const points = question.points ?? 0;
493
448
  let isCorrect = false;
494
449
  if (typeof answer === "object" && answer !== null && !Array.isArray(answer)) {
495
450
  const userAnswerMap = answer;
496
451
  isCorrect = question.answers.length > 0 && question.answers.every((correctAnsDef) => {
497
- var _a2, _b;
498
- const userValForBlank = (_a2 = userAnswerMap[correctAnsDef.blankId]) == null ? void 0 : _a2.trim();
452
+ const userValForBlank = userAnswerMap[correctAnsDef.blankId]?.trim();
499
453
  if (userValForBlank === void 0) return false;
500
- const caseSensitive = (_b = question.isCaseSensitive) != null ? _b : false;
454
+ const caseSensitive = question.isCaseSensitive ?? false;
501
455
  return correctAnsDef.acceptedValues.some(
502
456
  (accVal) => caseSensitive ? accVal.trim() === userValForBlank : accVal.trim().toLowerCase() === userValForBlank.toLowerCase()
503
457
  );
@@ -522,17 +476,15 @@ var FillInTheBlanksEvaluator = class {
522
476
  // src/services/evaluators/drag-and-drop-evaluator.ts
523
477
  var DragAndDropEvaluator = class {
524
478
  async evaluate(question, answer) {
525
- var _a;
526
- const points = (_a = question.points) != null ? _a : 0;
479
+ const points = question.points ?? 0;
527
480
  let isCorrect = false;
528
481
  if (typeof answer === "object" && answer !== null && !Array.isArray(answer)) {
529
482
  const userAnswerMap = answer;
530
483
  isCorrect = question.answerMap.length === Object.keys(userAnswerMap).length && question.answerMap.every((map) => userAnswerMap[map.draggableId] === map.dropZoneId);
531
484
  }
532
485
  const correctMap = question.answerMap.reduce((acc, curr) => {
533
- var _a2, _b;
534
- const draggableText = ((_a2 = question.draggableItems.find((d) => d.id === curr.draggableId)) == null ? void 0 : _a2.content) || "";
535
- const dropZoneText = ((_b = question.dropZones.find((z3) => z3.id === curr.dropZoneId)) == null ? void 0 : _b.label) || "";
486
+ const draggableText = question.draggableItems.find((d) => d.id === curr.draggableId)?.content || "";
487
+ const dropZoneText = question.dropZones.find((z3) => z3.id === curr.dropZoneId)?.label || "";
536
488
  acc[draggableText] = dropZoneText;
537
489
  return acc;
538
490
  }, {});
@@ -551,8 +503,7 @@ var DragAndDropEvaluator = class {
551
503
  // src/services/evaluators/hotspot-evaluator.ts
552
504
  var HotspotEvaluator = class {
553
505
  async evaluate(question, answer) {
554
- var _a;
555
- const points = (_a = question.points) != null ? _a : 0;
506
+ const points = question.points ?? 0;
556
507
  let isCorrect = false;
557
508
  if (Array.isArray(answer)) {
558
509
  const userAnswerSet = new Set(answer);
@@ -560,10 +511,7 @@ var HotspotEvaluator = class {
560
511
  isCorrect = userAnswerSet.size === correctAnswerSet.size && [...userAnswerSet].every((id) => correctAnswerSet.has(id));
561
512
  }
562
513
  const correctValues = question.correctHotspotIds.map(
563
- (id) => {
564
- var _a2;
565
- return ((_a2 = question.hotspots.find((h) => h.id === id)) == null ? void 0 : _a2.description) || id;
566
- }
514
+ (id) => question.hotspots.find((h) => h.id === id)?.description || id
567
515
  );
568
516
  const correctAnswerDetail = {
569
517
  id: question.correctHotspotIds,
@@ -580,11 +528,10 @@ var HotspotEvaluator = class {
580
528
  // src/services/evaluators/programming-evaluator.ts
581
529
  var ProgrammingEvaluator = class {
582
530
  async evaluate(question, answer) {
583
- var _a, _b;
584
- const points = (_a = question.points) != null ? _a : 0;
531
+ const points = question.points ?? 0;
585
532
  let isCorrect = false;
586
533
  if (typeof answer === "string" && typeof question.solutionGeneratedCode === "string") {
587
- if (typeof window !== "undefined" && ((_b = window.Blockly) == null ? void 0 : _b.JavaScript)) {
534
+ if (typeof window !== "undefined" && window.Blockly?.JavaScript) {
588
535
  const LocalBlockly = window.Blockly;
589
536
  let generatedUserCode = "";
590
537
  try {
@@ -658,10 +605,10 @@ var JsonRepairEngine = class {
658
605
  if (breakIndex !== -1) {
659
606
  const stringContent = afterUnterminated.substring(0, breakIndex);
660
607
  const remainder = afterUnterminated.substring(breakIndex);
661
- const escapedContent = stringContent.replace(new RegExp('(?<!\\\\)"', "g"), '\\"');
608
+ const escapedContent = stringContent.replace(/(?<!\\)"/g, '\\"');
662
609
  repaired = beforeUnterminated + escapedContent + '"' + remainder;
663
610
  } else {
664
- const escapedContent = afterUnterminated.replace(new RegExp('(?<!\\\\)"', "g"), '\\"');
611
+ const escapedContent = afterUnterminated.replace(/(?<!\\)"/g, '\\"');
665
612
  repaired = beforeUnterminated + escapedContent + '"';
666
613
  }
667
614
  }
@@ -737,7 +684,6 @@ var JsonRepairEngine = class {
737
684
  * Main repair function that attempts multiple strategies.
738
685
  */
739
686
  static repairJson(jsonStr) {
740
- var _a;
741
687
  let current = jsonStr.trim();
742
688
  const maxAttempts = 5;
743
689
  let lastError = "";
@@ -767,7 +713,7 @@ var JsonRepairEngine = class {
767
713
  }
768
714
  lastError = validation.error || "";
769
715
  lastPosition = validation.position;
770
- if ((_a = validation.error) == null ? void 0 : _a.includes("Unterminated string")) {
716
+ if (validation.error?.includes("Unterminated string")) {
771
717
  current = this.repairUnterminatedStrings(current);
772
718
  } else {
773
719
  current = this.applyCommonFixes(current);
@@ -1062,9 +1008,10 @@ var CodeEvaluationService = class {
1062
1008
  userCode,
1063
1009
  testCase
1064
1010
  }, this.apiKey);
1065
- return __spreadValues({
1066
- testCaseId: testCase.id
1067
- }, aiResult);
1011
+ return {
1012
+ testCaseId: testCase.id,
1013
+ ...aiResult
1014
+ };
1068
1015
  }
1069
1016
  /**
1070
1017
  * Evaluates user's code against all test cases for a given question.
@@ -1101,8 +1048,7 @@ var CodeEvaluationService = class {
1101
1048
  // src/services/evaluators/coding-evaluator.ts
1102
1049
  var CodingEvaluator = class {
1103
1050
  async evaluate(question, answer) {
1104
- var _a;
1105
- const points = (_a = question.points) != null ? _a : 0;
1051
+ const points = question.points ?? 0;
1106
1052
  if (typeof answer !== "string" || !answer.trim()) {
1107
1053
  return {
1108
1054
  isCorrect: false,
@@ -1159,17 +1105,16 @@ var QuizEngine = class {
1159
1105
  this.quizResultState = { scormStatus: "idle" };
1160
1106
  this.questionStartTime = null;
1161
1107
  this.questionTimings = /* @__PURE__ */ new Map();
1162
- var _a, _b, _c, _d, _e;
1163
1108
  this.config = options.config;
1164
1109
  this.callbacks = options.callbacks || {};
1165
- this.questions = ((_a = this.config.settings) == null ? void 0 : _a.shuffleQuestions) ? [...this.config.questions].sort(() => Math.random() - 0.5) : this.config.questions;
1110
+ this.questions = this.config.settings?.shuffleQuestions ? [...this.config.questions].sort(() => Math.random() - 0.5) : this.config.questions;
1166
1111
  this.overallStartTime = Date.now();
1167
1112
  this.evaluators = /* @__PURE__ */ new Map();
1168
1113
  this.registerEvaluators();
1169
- if (((_b = this.config.settings) == null ? void 0 : _b.timeLimitMinutes) && this.config.settings.timeLimitMinutes > 0) {
1114
+ if (this.config.settings?.timeLimitMinutes && this.config.settings.timeLimitMinutes > 0) {
1170
1115
  this.timeLeftInSeconds = this.config.settings.timeLimitMinutes * 60;
1171
1116
  }
1172
- if ((_c = this.config.settings) == null ? void 0 : _c.scorm) {
1117
+ if (this.config.settings?.scorm) {
1173
1118
  this.quizResultState.scormStatus = "initializing";
1174
1119
  this.scormService = new SCORMService(this.config.settings.scorm);
1175
1120
  if (this.scormService.hasAPI()) {
@@ -1202,7 +1147,7 @@ var QuizEngine = class {
1202
1147
  if (this.timeLeftInSeconds !== null) {
1203
1148
  this.startTimer();
1204
1149
  }
1205
- (_e = (_d = this.callbacks).onQuestionChange) == null ? void 0 : _e.call(_d, initialQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1150
+ this.callbacks.onQuestionChange?.(initialQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1206
1151
  }
1207
1152
  registerEvaluators() {
1208
1153
  this.evaluators.set("multiple_choice", new MultipleChoiceEvaluator());
@@ -1240,15 +1185,14 @@ var QuizEngine = class {
1240
1185
  }
1241
1186
  }
1242
1187
  handleTick() {
1243
- var _a, _b, _c, _d;
1244
1188
  if (this.timeLeftInSeconds === null) return;
1245
1189
  if (this.timeLeftInSeconds > 0) {
1246
1190
  this.timeLeftInSeconds--;
1247
- (_b = (_a = this.callbacks).onTimeTick) == null ? void 0 : _b.call(_a, this.timeLeftInSeconds);
1191
+ this.callbacks.onTimeTick?.(this.timeLeftInSeconds);
1248
1192
  }
1249
1193
  if (this.timeLeftInSeconds <= 0) {
1250
1194
  this.stopTimer();
1251
- (_d = (_c = this.callbacks).onQuizTimeUp) == null ? void 0 : _d.call(_c);
1195
+ this.callbacks.onQuizTimeUp?.();
1252
1196
  this.calculateResults();
1253
1197
  }
1254
1198
  }
@@ -1271,43 +1215,39 @@ var QuizEngine = class {
1271
1215
  return this.quizResultState.score !== void 0;
1272
1216
  }
1273
1217
  submitAnswer(questionId, answer) {
1274
- var _a, _b;
1275
1218
  this.userAnswers.set(questionId, answer);
1276
1219
  const question = this.questions.find((q) => q.id === questionId);
1277
- if (question) (_b = (_a = this.callbacks).onAnswerSubmit) == null ? void 0 : _b.call(_a, question, answer);
1220
+ if (question) this.callbacks.onAnswerSubmit?.(question, answer);
1278
1221
  }
1279
1222
  nextQuestion() {
1280
- var _a, _b;
1281
1223
  this._recordCurrentQuestionTime();
1282
1224
  if (this.currentQuestionIndex < this.questions.length - 1) {
1283
1225
  this.currentQuestionIndex++;
1284
1226
  const currentQ = this.getCurrentQuestion();
1285
1227
  this.questionStartTime = Date.now();
1286
- (_b = (_a = this.callbacks).onQuestionChange) == null ? void 0 : _b.call(_a, currentQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1228
+ this.callbacks.onQuestionChange?.(currentQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1287
1229
  return currentQ;
1288
1230
  }
1289
1231
  return null;
1290
1232
  }
1291
1233
  previousQuestion() {
1292
- var _a, _b;
1293
1234
  this._recordCurrentQuestionTime();
1294
1235
  if (this.currentQuestionIndex > 0) {
1295
1236
  this.currentQuestionIndex--;
1296
1237
  const currentQ = this.getCurrentQuestion();
1297
1238
  this.questionStartTime = Date.now();
1298
- (_b = (_a = this.callbacks).onQuestionChange) == null ? void 0 : _b.call(_a, currentQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1239
+ this.callbacks.onQuestionChange?.(currentQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1299
1240
  return currentQ;
1300
1241
  }
1301
1242
  return null;
1302
1243
  }
1303
1244
  goToQuestion(index) {
1304
- var _a, _b;
1305
1245
  if (index >= 0 && index < this.questions.length && index !== this.currentQuestionIndex) {
1306
1246
  this._recordCurrentQuestionTime();
1307
1247
  this.currentQuestionIndex = index;
1308
1248
  const currentQ = this.getCurrentQuestion();
1309
1249
  this.questionStartTime = Date.now();
1310
- (_b = (_a = this.callbacks).onQuestionChange) == null ? void 0 : _b.call(_a, currentQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1250
+ this.callbacks.onQuestionChange?.(currentQ, this.getCurrentQuestionNumber(), this.getTotalQuestions());
1311
1251
  return currentQ;
1312
1252
  }
1313
1253
  return this.getCurrentQuestion();
@@ -1333,7 +1273,6 @@ var QuizEngine = class {
1333
1273
  }
1334
1274
  // (Tiếp theo từ Phần 1)
1335
1275
  async calculateResults() {
1336
- var _a, _b, _c, _d, _e;
1337
1276
  this.stopTimer();
1338
1277
  this._recordCurrentQuestionTime();
1339
1278
  let totalScore = 0;
@@ -1342,7 +1281,7 @@ var QuizEngine = class {
1342
1281
  let accumulatedTotalTimeSpent = 0;
1343
1282
  for (const question of this.questions) {
1344
1283
  const userAnswerRaw = this.userAnswers.get(question.id) || null;
1345
- maxScore += (_a = question.points) != null ? _a : 0;
1284
+ maxScore += question.points ?? 0;
1346
1285
  const evaluator = this.evaluators.get(question.questionType);
1347
1286
  if (!evaluator) {
1348
1287
  console.warn(`No evaluator found for question type: ${question.questionType}`);
@@ -1382,13 +1321,13 @@ var QuizEngine = class {
1382
1321
  }
1383
1322
  const percentage = maxScore > 0 ? parseFloat((totalScore / maxScore * 100).toFixed(2)) : 0;
1384
1323
  let passed = void 0;
1385
- if (((_b = this.config.settings) == null ? void 0 : _b.passingScorePercent) != null) {
1324
+ if (this.config.settings?.passingScorePercent != null) {
1386
1325
  passed = percentage >= this.config.settings.passingScorePercent;
1387
1326
  }
1388
1327
  const totalQuizTimeSpentSeconds = parseFloat(accumulatedTotalTimeSpent.toFixed(2));
1389
1328
  const averageTimePerQuestionSeconds = this.questions.length > 0 ? parseFloat((totalQuizTimeSpentSeconds / this.questions.length).toFixed(2)) : 0;
1390
1329
  const metadataPerformance = await this._calculateMetadataPerformance();
1391
- const finalResults = __spreadValues({
1330
+ const finalResults = {
1392
1331
  score: totalScore,
1393
1332
  maxScore,
1394
1333
  percentage,
@@ -1400,39 +1339,33 @@ var QuizEngine = class {
1400
1339
  scormError: this.quizResultState.scormError,
1401
1340
  studentName: this.quizResultState.studentName,
1402
1341
  totalTimeSpentSeconds: totalQuizTimeSpentSeconds,
1403
- averageTimePerQuestionSeconds
1404
- }, metadataPerformance);
1405
- this.quizResultState = __spreadValues(__spreadValues({}, this.quizResultState), finalResults);
1406
- if ((_c = this.config.settings) == null ? void 0 : _c.scorm) this._sendResultsToSCORM(finalResults);
1342
+ averageTimePerQuestionSeconds,
1343
+ ...metadataPerformance
1344
+ };
1345
+ this.quizResultState = { ...this.quizResultState, ...finalResults };
1346
+ if (this.config.settings?.scorm) this._sendResultsToSCORM(finalResults);
1407
1347
  await this._sendResultsToWebhook(finalResults);
1408
- (_e = (_d = this.callbacks).onQuizFinish) == null ? void 0 : _e.call(_d, finalResults);
1348
+ this.callbacks.onQuizFinish?.(finalResults);
1409
1349
  return finalResults;
1410
1350
  }
1411
1351
  formatUserAnswerDetail(question, userAnswerRaw) {
1412
- var _a, _b, _c, _d, _e;
1413
1352
  if (userAnswerRaw === null) return null;
1414
1353
  switch (question.questionType) {
1415
1354
  case "multiple_choice": {
1416
1355
  const q = question;
1417
1356
  const id = userAnswerRaw;
1418
- return { id, value: ((_a = q.options.find((opt) => opt.id === id)) == null ? void 0 : _a.text) || "" };
1357
+ return { id, value: q.options.find((opt) => opt.id === id)?.text || "" };
1419
1358
  }
1420
1359
  case "multiple_response": {
1421
1360
  const q = question;
1422
1361
  const ids = userAnswerRaw;
1423
- const values = ids.map((id) => {
1424
- var _a2;
1425
- return ((_a2 = q.options.find((opt) => opt.id === id)) == null ? void 0 : _a2.text) || "";
1426
- });
1362
+ const values = ids.map((id) => q.options.find((opt) => opt.id === id)?.text || "");
1427
1363
  return { id: ids, value: values };
1428
1364
  }
1429
1365
  case "sequence": {
1430
1366
  const q = question;
1431
1367
  const ids = userAnswerRaw;
1432
- const values = ids.map((id) => {
1433
- var _a2;
1434
- return ((_a2 = q.items.find((item) => item.id === id)) == null ? void 0 : _a2.content) || "";
1435
- });
1368
+ const values = ids.map((id) => q.items.find((item) => item.id === id)?.content || "");
1436
1369
  return { id: ids, value: values };
1437
1370
  }
1438
1371
  case "matching": {
@@ -1441,8 +1374,8 @@ var QuizEngine = class {
1441
1374
  const valueMap = {};
1442
1375
  for (const promptId in userAnswerMap) {
1443
1376
  const optionId = userAnswerMap[promptId];
1444
- const promptText = ((_b = q.prompts.find((p) => p.id === promptId)) == null ? void 0 : _b.content) || "";
1445
- const optionText = ((_c = q.options.find((o) => o.id === optionId)) == null ? void 0 : _c.content) || "";
1377
+ const promptText = q.prompts.find((p) => p.id === promptId)?.content || "";
1378
+ const optionText = q.options.find((o) => o.id === optionId)?.content || "";
1446
1379
  valueMap[promptText] = optionText;
1447
1380
  }
1448
1381
  return { id: null, value: valueMap };
@@ -1454,8 +1387,8 @@ var QuizEngine = class {
1454
1387
  const enrichedUserAnswerMap = {};
1455
1388
  for (const draggableId in userAnswerMapByIds) {
1456
1389
  const dropZoneId = userAnswerMapByIds[draggableId];
1457
- const draggableText = ((_d = q.draggableItems.find((d) => d.id === draggableId)) == null ? void 0 : _d.content) || `(ID: ${draggableId})`;
1458
- const dropZoneText = ((_e = q.dropZones.find((z3) => z3.id === dropZoneId)) == null ? void 0 : _e.label) || `(ID: ${dropZoneId})`;
1390
+ const draggableText = q.draggableItems.find((d) => d.id === draggableId)?.content || `(ID: ${draggableId})`;
1391
+ const dropZoneText = q.dropZones.find((z3) => z3.id === dropZoneId)?.label || `(ID: ${dropZoneId})`;
1459
1392
  enrichedUserAnswerMap[draggableText] = dropZoneText;
1460
1393
  }
1461
1394
  return { id: null, value: enrichedUserAnswerMap };
@@ -1467,7 +1400,6 @@ var QuizEngine = class {
1467
1400
  }
1468
1401
  }
1469
1402
  async _calculateMetadataPerformance() {
1470
- var _a;
1471
1403
  const loPerformanceMap = /* @__PURE__ */ new Map();
1472
1404
  const categoryPerformanceMap = /* @__PURE__ */ new Map();
1473
1405
  const topicPerformanceMap = /* @__PURE__ */ new Map();
@@ -1489,7 +1421,7 @@ var QuizEngine = class {
1489
1421
  const evaluator = this.evaluators.get(q.questionType);
1490
1422
  if (evaluator) {
1491
1423
  const { isCorrect } = await evaluator.evaluate(q, userAnswer);
1492
- const pointsForThisQuestion = (_a = q.points) != null ? _a : 0;
1424
+ const pointsForThisQuestion = q.points ?? 0;
1493
1425
  updateMap(loPerformanceMap, q.learningObjective, pointsForThisQuestion, isCorrect);
1494
1426
  updateMap(categoryPerformanceMap, q.category, pointsForThisQuestion, isCorrect);
1495
1427
  updateMap(topicPerformanceMap, q.topic, pointsForThisQuestion, isCorrect);
@@ -1516,8 +1448,7 @@ var QuizEngine = class {
1516
1448
  };
1517
1449
  }
1518
1450
  async _sendResultsToWebhook(results) {
1519
- var _a;
1520
- if (!((_a = this.config.settings) == null ? void 0 : _a.webhookUrl)) {
1451
+ if (!this.config.settings?.webhookUrl) {
1521
1452
  results.webhookStatus = "idle";
1522
1453
  return;
1523
1454
  }
@@ -1545,12 +1476,11 @@ var QuizEngine = class {
1545
1476
  }
1546
1477
  }
1547
1478
  _sendResultsToSCORM(results) {
1548
- var _a, _b, _c, _d, _e, _f, _g;
1549
1479
  if (!this.scormService || !this.scormService.hasAPI() || this.quizResultState.scormStatus === "no_api") {
1550
1480
  results.scormStatus = this.quizResultState.scormStatus || "idle";
1551
1481
  return;
1552
1482
  }
1553
- if (this.quizResultState.scormStatus === "error" && ((_a = this.quizResultState.scormError) == null ? void 0 : _a.includes("initialization failed"))) {
1483
+ if (this.quizResultState.scormStatus === "error" && this.quizResultState.scormError?.includes("initialization failed")) {
1554
1484
  results.scormStatus = "error";
1555
1485
  results.scormError = this.quizResultState.scormError;
1556
1486
  return;
@@ -1559,15 +1489,15 @@ var QuizEngine = class {
1559
1489
  try {
1560
1490
  this.scormService.setScore(results.score, results.maxScore, 0);
1561
1491
  let lessonStatusSetting = "completed";
1562
- if (((_b = this.config.settings) == null ? void 0 : _b.passingScorePercent) !== void 0 && ((_c = this.config.settings) == null ? void 0 : _c.passingScorePercent) !== null) {
1492
+ if (this.config.settings?.passingScorePercent !== void 0 && this.config.settings?.passingScorePercent !== null) {
1563
1493
  lessonStatusSetting = results.passed ? "passed" : "failed";
1564
- } else if ((_e = (_d = this.config.settings) == null ? void 0 : _d.scorm) == null ? void 0 : _e.setCompletionOnFinish) {
1494
+ } else if (this.config.settings?.scorm?.setCompletionOnFinish) {
1565
1495
  lessonStatusSetting = "completed";
1566
1496
  }
1567
1497
  this.scormService.setLessonStatus(lessonStatusSetting, results.passed);
1568
1498
  if (results.totalTimeSpentSeconds !== void 0 && this.scormService.formatCMITime) {
1569
1499
  const cmiTime = this.scormService.formatCMITime(results.totalTimeSpentSeconds);
1570
- const sessionTimeVar = ((_g = (_f = this.config.settings) == null ? void 0 : _f.scorm) == null ? void 0 : _g.sessionTimeVar) || (this.scormService.getSCORMVersion() === "2004" ? "cmi.session_time" : "cmi.core.session_time");
1500
+ const sessionTimeVar = this.config.settings?.scorm?.sessionTimeVar || (this.scormService.getSCORMVersion() === "2004" ? "cmi.session_time" : "cmi.core.session_time");
1571
1501
  if (sessionTimeVar) this.scormService.setValue(sessionTimeVar, cmiTime);
1572
1502
  }
1573
1503
  const commitResult = this.scormService.commit();
@@ -1586,114 +1516,96 @@ var QuizEngine = class {
1586
1516
  function cn(...inputs) {
1587
1517
  return twMerge(clsx(inputs));
1588
1518
  }
1589
-
1590
- // src/react-ui/components/elements/radio-group.tsx
1591
- var RadioGroup = React28.forwardRef((_a, ref) => {
1592
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
1593
- return /* @__PURE__ */ React28.createElement(
1519
+ var RadioGroup = React9.forwardRef(({ className, ...props }, ref) => {
1520
+ return /* @__PURE__ */ jsx(
1594
1521
  RadioGroupPrimitive.Root,
1595
- __spreadProps(__spreadValues({
1596
- className: cn("grid gap-2", className)
1597
- }, props), {
1522
+ {
1523
+ className: cn("grid gap-2", className),
1524
+ ...props,
1598
1525
  ref
1599
- })
1526
+ }
1600
1527
  );
1601
1528
  });
1602
1529
  RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
1603
- var RadioGroupItem = React28.forwardRef((_a, ref) => {
1604
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
1605
- return /* @__PURE__ */ React28.createElement(
1530
+ var RadioGroupItem = React9.forwardRef(({ className, ...props }, ref) => {
1531
+ return /* @__PURE__ */ jsx(
1606
1532
  RadioGroupPrimitive.Item,
1607
- __spreadValues({
1533
+ {
1608
1534
  ref,
1609
1535
  className: cn(
1610
1536
  "aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
1611
1537
  className
1612
- )
1613
- }, props),
1614
- /* @__PURE__ */ React28.createElement(RadioGroupPrimitive.Indicator, { className: "flex items-center justify-center" }, /* @__PURE__ */ React28.createElement(Circle, { className: "h-2.5 w-2.5 fill-current text-current" }))
1538
+ ),
1539
+ ...props,
1540
+ children: /* @__PURE__ */ jsx(RadioGroupPrimitive.Indicator, { className: "flex items-center justify-center", children: /* @__PURE__ */ jsx(Circle, { className: "h-2.5 w-2.5 fill-current text-current" }) })
1541
+ }
1615
1542
  );
1616
1543
  });
1617
1544
  RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
1618
1545
  var labelVariants = cva(
1619
1546
  "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
1620
1547
  );
1621
- var Label = React28.forwardRef((_a, ref) => {
1622
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
1623
- return /* @__PURE__ */ React28.createElement(
1624
- LabelPrimitive.Root,
1625
- __spreadValues({
1626
- ref,
1627
- className: cn(labelVariants(), className)
1628
- }, props)
1629
- );
1630
- });
1548
+ var Label = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1549
+ LabelPrimitive.Root,
1550
+ {
1551
+ ref,
1552
+ className: cn(labelVariants(), className),
1553
+ ...props
1554
+ }
1555
+ ));
1631
1556
  Label.displayName = LabelPrimitive.Root.displayName;
1632
- var Card = React28.forwardRef((_a, ref) => {
1633
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
1634
- return /* @__PURE__ */ React28.createElement(
1635
- "div",
1636
- __spreadValues({
1637
- ref,
1638
- className: cn(
1639
- "rounded-lg border bg-card text-card-foreground shadow-sm",
1640
- className
1641
- )
1642
- }, props)
1643
- );
1644
- });
1557
+ var Card = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1558
+ "div",
1559
+ {
1560
+ ref,
1561
+ className: cn(
1562
+ "rounded-lg border bg-card text-card-foreground shadow-sm",
1563
+ className
1564
+ ),
1565
+ ...props
1566
+ }
1567
+ ));
1645
1568
  Card.displayName = "Card";
1646
- var CardHeader = React28.forwardRef((_a, ref) => {
1647
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
1648
- return /* @__PURE__ */ React28.createElement(
1649
- "div",
1650
- __spreadValues({
1651
- ref,
1652
- className: cn("flex flex-col space-y-1.5 p-6", className)
1653
- }, props)
1654
- );
1655
- });
1569
+ var CardHeader = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1570
+ "div",
1571
+ {
1572
+ ref,
1573
+ className: cn("flex flex-col space-y-1.5 p-6", className),
1574
+ ...props
1575
+ }
1576
+ ));
1656
1577
  CardHeader.displayName = "CardHeader";
1657
- var CardTitle = React28.forwardRef((_a, ref) => {
1658
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
1659
- return /* @__PURE__ */ React28.createElement(
1660
- "div",
1661
- __spreadValues({
1662
- ref,
1663
- className: cn(
1664
- "text-2xl font-semibold leading-none tracking-tight",
1665
- className
1666
- )
1667
- }, props)
1668
- );
1669
- });
1578
+ var CardTitle = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1579
+ "div",
1580
+ {
1581
+ ref,
1582
+ className: cn(
1583
+ "text-2xl font-semibold leading-none tracking-tight",
1584
+ className
1585
+ ),
1586
+ ...props
1587
+ }
1588
+ ));
1670
1589
  CardTitle.displayName = "CardTitle";
1671
- var CardDescription = React28.forwardRef((_a, ref) => {
1672
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
1673
- return /* @__PURE__ */ React28.createElement(
1674
- "div",
1675
- __spreadValues({
1676
- ref,
1677
- className: cn("text-sm text-muted-foreground", className)
1678
- }, props)
1679
- );
1680
- });
1590
+ var CardDescription = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1591
+ "div",
1592
+ {
1593
+ ref,
1594
+ className: cn("text-sm text-muted-foreground", className),
1595
+ ...props
1596
+ }
1597
+ ));
1681
1598
  CardDescription.displayName = "CardDescription";
1682
- var CardContent = React28.forwardRef((_a, ref) => {
1683
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
1684
- return /* @__PURE__ */ React28.createElement("div", __spreadValues({ ref, className: cn("p-6 pt-0", className) }, props));
1685
- });
1599
+ var CardContent = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("p-6 pt-0", className), ...props }));
1686
1600
  CardContent.displayName = "CardContent";
1687
- var CardFooter = React28.forwardRef((_a, ref) => {
1688
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
1689
- return /* @__PURE__ */ React28.createElement(
1690
- "div",
1691
- __spreadValues({
1692
- ref,
1693
- className: cn("flex items-center p-6 pt-0", className)
1694
- }, props)
1695
- );
1696
- });
1601
+ var CardFooter = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1602
+ "div",
1603
+ {
1604
+ ref,
1605
+ className: cn("flex items-center p-6 pt-0", className),
1606
+ ...props
1607
+ }
1608
+ ));
1697
1609
  CardFooter.displayName = "CardFooter";
1698
1610
  var MarkdownRenderer = ({
1699
1611
  content,
@@ -1737,20 +1649,19 @@ var MarkdownRenderer = ({
1737
1649
  const processedContent = processContentForVideos(content);
1738
1650
  return (
1739
1651
  // Using Tailwind Typography for beautiful default styling of markdown content
1740
- /* @__PURE__ */ React28__default.createElement("div", { className: `prose dark:prose-invert max-w-none ${className}` }, /* @__PURE__ */ React28__default.createElement(
1652
+ /* @__PURE__ */ jsx("div", { className: `prose dark:prose-invert max-w-none ${className}`, children: /* @__PURE__ */ jsx(
1741
1653
  ReactMarkdown,
1742
1654
  {
1743
1655
  remarkPlugins: [remarkGfm, remarkMath],
1744
1656
  rehypePlugins: [rehypeHighlight, rehypeKatex],
1745
1657
  components: {
1746
1658
  // Override the default image component to handle videos and responsive images
1747
- img: (_a) => {
1748
- var _b = _a, { node } = _b, props = __objRest(_b, ["node"]);
1659
+ img: ({ node, ...props }) => {
1749
1660
  const src = props.src || "";
1750
1661
  const { platform, id } = getVideoId(src);
1751
1662
  if (platform && id) {
1752
1663
  const videoSrc = platform === "youtube" ? `https://www.youtube.com/embed/${id}` : `https://player.vimeo.com/video/${id}`;
1753
- return /* @__PURE__ */ React28__default.createElement("div", { className: "aspect-w-16 aspect-h-9 my-4" }, /* @__PURE__ */ React28__default.createElement(
1664
+ return /* @__PURE__ */ jsx("div", { className: "aspect-w-16 aspect-h-9 my-4", children: /* @__PURE__ */ jsx(
1754
1665
  "iframe",
1755
1666
  {
1756
1667
  src: videoSrc,
@@ -1759,13 +1670,14 @@ var MarkdownRenderer = ({
1759
1670
  allowFullScreen: true,
1760
1671
  className: "w-full h-full rounded-md"
1761
1672
  }
1762
- ));
1673
+ ) });
1763
1674
  }
1764
1675
  return (
1765
1676
  // eslint-disable-next-line @next/next/no-img-element
1766
- /* @__PURE__ */ React28__default.createElement(
1677
+ /* @__PURE__ */ jsx(
1767
1678
  "img",
1768
- __spreadProps(__spreadValues({}, props), {
1679
+ {
1680
+ ...props,
1769
1681
  style: {
1770
1682
  maxWidth: "100%",
1771
1683
  height: "auto",
@@ -1773,33 +1685,26 @@ var MarkdownRenderer = ({
1773
1685
  margin: "1rem 0"
1774
1686
  },
1775
1687
  alt: props.alt || ""
1776
- })
1688
+ }
1777
1689
  )
1778
1690
  );
1779
1691
  },
1780
1692
  // Override the default table to add responsive wrapper
1781
- table: (_c) => {
1782
- var _d = _c, { node } = _d, props = __objRest(_d, ["node"]);
1783
- return /* @__PURE__ */ React28__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React28__default.createElement("table", __spreadProps(__spreadValues({}, props), { className: "my-4 w-full text-sm" })));
1784
- },
1693
+ table: ({ node, ...props }) => /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsx("table", { ...props, className: "my-4 w-full text-sm" }) }),
1785
1694
  // Override default blockquote for better styling
1786
- blockquote: (_e) => {
1787
- var _f = _e, { node } = _f, props = __objRest(_f, ["node"]);
1788
- return /* @__PURE__ */ React28__default.createElement(
1789
- "blockquote",
1790
- __spreadProps(__spreadValues({}, props), {
1791
- className: "border-l-4 border-primary bg-muted/50 p-4 my-4 italic"
1792
- })
1793
- );
1794
- }
1795
- }
1796
- },
1797
- processedContent
1798
- ))
1695
+ blockquote: ({ node, ...props }) => /* @__PURE__ */ jsx(
1696
+ "blockquote",
1697
+ {
1698
+ ...props,
1699
+ className: "border-l-4 border-primary bg-muted/50 p-4 my-4 italic"
1700
+ }
1701
+ )
1702
+ },
1703
+ children: processedContent
1704
+ }
1705
+ ) })
1799
1706
  );
1800
1707
  };
1801
-
1802
- // src/react-ui/components/ui/MultipleChoiceQuestionUI.tsx
1803
1708
  var MultipleChoiceQuestionUI = ({
1804
1709
  question,
1805
1710
  onAnswerChange,
@@ -1810,40 +1715,58 @@ var MultipleChoiceQuestionUI = ({
1810
1715
  const handleSelection = (value) => {
1811
1716
  onAnswerChange(value);
1812
1717
  };
1813
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: prompt })), points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0" }, /* @__PURE__ */ React28__default.createElement(
1814
- RadioGroup,
1815
- {
1816
- value: userAnswer || void 0,
1817
- onValueChange: handleSelection,
1818
- className: "space-y-3",
1819
- "aria-labelledby": `question-prompt-${questionId}`
1820
- },
1821
- options.map((option) => {
1822
- const isSelected = userAnswer === option.id;
1823
- const isCorrect = option.id === correctAnswerId;
1824
- let itemClassName = "p-4 rounded-lg border-2 transition-all cursor-pointer hover:border-primary";
1825
- if (showCorrectAnswer) {
1826
- if (isCorrect) {
1827
- itemClassName += " border-green-500 bg-green-500/10";
1828
- } else if (isSelected && !isCorrect) {
1829
- itemClassName += " border-destructive bg-destructive/10";
1830
- } else {
1831
- itemClassName += " border-muted";
1832
- }
1833
- } else {
1834
- itemClassName += isSelected ? " border-primary bg-primary/10" : " border-muted";
1835
- }
1836
- return /* @__PURE__ */ React28__default.createElement(
1837
- Label,
1718
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
1719
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
1720
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: prompt }) }),
1721
+ points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
1722
+ "Points: ",
1723
+ points
1724
+ ] })
1725
+ ] }),
1726
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0", children: [
1727
+ /* @__PURE__ */ jsx(
1728
+ RadioGroup,
1838
1729
  {
1839
- key: option.id,
1840
- htmlFor: option.id,
1841
- className: itemClassName
1842
- },
1843
- /* @__PURE__ */ React28__default.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React28__default.createElement(RadioGroupItem, { value: option.id, id: option.id, className: "mr-3" }), /* @__PURE__ */ React28__default.createElement("div", { className: "text-base flex-1" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: option.text })))
1844
- );
1845
- })
1846
- ), showCorrectAnswer && explanation && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Explanation:"), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" }))));
1730
+ value: userAnswer || void 0,
1731
+ onValueChange: handleSelection,
1732
+ className: "space-y-3",
1733
+ "aria-labelledby": `question-prompt-${questionId}`,
1734
+ children: options.map((option) => {
1735
+ const isSelected = userAnswer === option.id;
1736
+ const isCorrect = option.id === correctAnswerId;
1737
+ let itemClassName = "p-4 rounded-lg border-2 transition-all cursor-pointer hover:border-primary";
1738
+ if (showCorrectAnswer) {
1739
+ if (isCorrect) {
1740
+ itemClassName += " border-green-500 bg-green-500/10";
1741
+ } else if (isSelected && !isCorrect) {
1742
+ itemClassName += " border-destructive bg-destructive/10";
1743
+ } else {
1744
+ itemClassName += " border-muted";
1745
+ }
1746
+ } else {
1747
+ itemClassName += isSelected ? " border-primary bg-primary/10" : " border-muted";
1748
+ }
1749
+ return /* @__PURE__ */ jsx(
1750
+ Label,
1751
+ {
1752
+ htmlFor: option.id,
1753
+ className: itemClassName,
1754
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
1755
+ /* @__PURE__ */ jsx(RadioGroupItem, { value: option.id, id: option.id, className: "mr-3" }),
1756
+ /* @__PURE__ */ jsx("div", { className: "text-base flex-1", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: option.text }) })
1757
+ ] })
1758
+ },
1759
+ option.id
1760
+ );
1761
+ })
1762
+ }
1763
+ ),
1764
+ showCorrectAnswer && explanation && /* @__PURE__ */ jsxs("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md", children: [
1765
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Explanation:" }),
1766
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" })
1767
+ ] })
1768
+ ] })
1769
+ ] });
1847
1770
  };
1848
1771
  var TrueFalseQuestionUI = ({
1849
1772
  question,
@@ -1859,64 +1782,78 @@ var TrueFalseQuestionUI = ({
1859
1782
  const handleSelection = (value) => {
1860
1783
  onAnswerChange(value);
1861
1784
  };
1862
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: prompt })), points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0" }, /* @__PURE__ */ React28__default.createElement(
1863
- RadioGroup,
1864
- {
1865
- value: userAnswer || void 0,
1866
- onValueChange: handleSelection,
1867
- className: "space-y-3",
1868
- "aria-labelledby": `question-prompt-${questionId}`
1869
- },
1870
- options.map((option) => {
1871
- const isSelected = userAnswer === option.value;
1872
- const isOptionCorrect = option.value === "true" && correctAnswer === true || option.value === "false" && correctAnswer === false;
1873
- let itemClassName = "p-4 rounded-lg border-2 transition-all cursor-pointer hover:border-primary";
1874
- if (showCorrectAnswer) {
1875
- if (isOptionCorrect) {
1876
- itemClassName += " border-green-500 bg-green-500/10";
1877
- } else if (isSelected && !isOptionCorrect) {
1878
- itemClassName += " border-destructive bg-destructive/10";
1879
- } else {
1880
- itemClassName += " border-muted";
1881
- }
1882
- } else {
1883
- itemClassName += isSelected ? " border-primary bg-primary/10" : " border-muted";
1884
- }
1885
- return /* @__PURE__ */ React28__default.createElement(
1886
- Label,
1785
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
1786
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
1787
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: prompt }) }),
1788
+ points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
1789
+ "Points: ",
1790
+ points
1791
+ ] })
1792
+ ] }),
1793
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0", children: [
1794
+ /* @__PURE__ */ jsx(
1795
+ RadioGroup,
1887
1796
  {
1888
- key: option.id,
1889
- htmlFor: option.id,
1890
- className: itemClassName
1891
- },
1892
- /* @__PURE__ */ React28__default.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React28__default.createElement(RadioGroupItem, { value: option.value, id: option.id, className: "mr-3" }), /* @__PURE__ */ React28__default.createElement("span", { className: "text-base" }, option.label))
1893
- );
1894
- })
1895
- ), showCorrectAnswer && explanation && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Explanation:"), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" }))));
1797
+ value: userAnswer || void 0,
1798
+ onValueChange: handleSelection,
1799
+ className: "space-y-3",
1800
+ "aria-labelledby": `question-prompt-${questionId}`,
1801
+ children: options.map((option) => {
1802
+ const isSelected = userAnswer === option.value;
1803
+ const isOptionCorrect = option.value === "true" && correctAnswer === true || option.value === "false" && correctAnswer === false;
1804
+ let itemClassName = "p-4 rounded-lg border-2 transition-all cursor-pointer hover:border-primary";
1805
+ if (showCorrectAnswer) {
1806
+ if (isOptionCorrect) {
1807
+ itemClassName += " border-green-500 bg-green-500/10";
1808
+ } else if (isSelected && !isOptionCorrect) {
1809
+ itemClassName += " border-destructive bg-destructive/10";
1810
+ } else {
1811
+ itemClassName += " border-muted";
1812
+ }
1813
+ } else {
1814
+ itemClassName += isSelected ? " border-primary bg-primary/10" : " border-muted";
1815
+ }
1816
+ return /* @__PURE__ */ jsx(
1817
+ Label,
1818
+ {
1819
+ htmlFor: option.id,
1820
+ className: itemClassName,
1821
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
1822
+ /* @__PURE__ */ jsx(RadioGroupItem, { value: option.value, id: option.id, className: "mr-3" }),
1823
+ /* @__PURE__ */ jsx("span", { className: "text-base", children: option.label })
1824
+ ] })
1825
+ },
1826
+ option.id
1827
+ );
1828
+ })
1829
+ }
1830
+ ),
1831
+ showCorrectAnswer && explanation && /* @__PURE__ */ jsxs("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md", children: [
1832
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Explanation:" }),
1833
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" })
1834
+ ] })
1835
+ ] })
1836
+ ] });
1896
1837
  };
1897
- var Checkbox = React28.forwardRef((_a, ref) => {
1898
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
1899
- return /* @__PURE__ */ React28.createElement(
1900
- CheckboxPrimitive.Root,
1901
- __spreadValues({
1902
- ref,
1903
- className: cn(
1904
- "peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
1905
- className
1906
- )
1907
- }, props),
1908
- /* @__PURE__ */ React28.createElement(
1838
+ var Checkbox = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1839
+ CheckboxPrimitive.Root,
1840
+ {
1841
+ ref,
1842
+ className: cn(
1843
+ "peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
1844
+ className
1845
+ ),
1846
+ ...props,
1847
+ children: /* @__PURE__ */ jsx(
1909
1848
  CheckboxPrimitive.Indicator,
1910
1849
  {
1911
- className: cn("flex items-center justify-center text-current")
1912
- },
1913
- /* @__PURE__ */ React28.createElement(Check, { className: "h-4 w-4" })
1850
+ className: cn("flex items-center justify-center text-current"),
1851
+ children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" })
1852
+ }
1914
1853
  )
1915
- );
1916
- });
1854
+ }
1855
+ ));
1917
1856
  Checkbox.displayName = CheckboxPrimitive.Root.displayName;
1918
-
1919
- // src/react-ui/components/ui/MultipleResponseQuestionUI.tsx
1920
1857
  var MultipleResponseQuestionUI = ({
1921
1858
  question,
1922
1859
  onAnswerChange,
@@ -1938,59 +1875,74 @@ var MultipleResponseQuestionUI = ({
1938
1875
  }
1939
1876
  onAnswerChange(newAnswers.length > 0 ? newAnswers : null);
1940
1877
  };
1941
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: prompt })), points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0" }, /* @__PURE__ */ React28__default.createElement("div", { className: "space-y-3", role: "group", "aria-labelledby": `question-prompt-${questionId}` }, options.map((option) => {
1942
- const isSelected = Array.isArray(userAnswer) && userAnswer.includes(option.id);
1943
- const isCorrectOption = correctAnswerIds.includes(option.id);
1944
- let itemClassName = "p-4 rounded-lg border-2 transition-all cursor-pointer hover:border-primary flex items-center";
1945
- if (showCorrectAnswer) {
1946
- if (isCorrectOption) {
1947
- itemClassName += isSelected ? " border-green-500 bg-green-500/10" : " border-green-500";
1948
- } else {
1949
- itemClassName += isSelected ? " border-destructive bg-destructive/10" : " border-muted";
1950
- }
1951
- } else {
1952
- itemClassName += isSelected ? " border-primary bg-primary/10" : " border-muted";
1953
- }
1954
- return /* @__PURE__ */ React28__default.createElement(
1955
- Label,
1956
- {
1957
- key: option.id,
1958
- htmlFor: option.id,
1959
- className: itemClassName
1960
- },
1961
- /* @__PURE__ */ React28__default.createElement(
1962
- Checkbox,
1963
- {
1964
- id: option.id,
1965
- checked: isSelected,
1966
- onCheckedChange: (checked) => handleSelectionChange(option.id, !!checked),
1967
- className: "mr-3",
1968
- "aria-label": option.text.replace(/<[^>]*>?/gm, "")
1878
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
1879
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
1880
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: prompt }) }),
1881
+ points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
1882
+ "Points: ",
1883
+ points
1884
+ ] })
1885
+ ] }),
1886
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0", children: [
1887
+ /* @__PURE__ */ jsx("div", { className: "space-y-3", role: "group", "aria-labelledby": `question-prompt-${questionId}`, children: options.map((option) => {
1888
+ const isSelected = Array.isArray(userAnswer) && userAnswer.includes(option.id);
1889
+ const isCorrectOption = correctAnswerIds.includes(option.id);
1890
+ let itemClassName = "p-4 rounded-lg border-2 transition-all cursor-pointer hover:border-primary flex items-center";
1891
+ if (showCorrectAnswer) {
1892
+ if (isCorrectOption) {
1893
+ itemClassName += isSelected ? " border-green-500 bg-green-500/10" : " border-green-500";
1894
+ } else {
1895
+ itemClassName += isSelected ? " border-destructive bg-destructive/10" : " border-muted";
1896
+ }
1897
+ } else {
1898
+ itemClassName += isSelected ? " border-primary bg-primary/10" : " border-muted";
1969
1899
  }
1970
- ),
1971
- /* @__PURE__ */ React28__default.createElement("div", { className: "text-base flex-1" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: option.text }))
1972
- );
1973
- })), showCorrectAnswer && explanation && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Explanation:"), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" }))));
1900
+ return /* @__PURE__ */ jsxs(
1901
+ Label,
1902
+ {
1903
+ htmlFor: option.id,
1904
+ className: itemClassName,
1905
+ children: [
1906
+ /* @__PURE__ */ jsx(
1907
+ Checkbox,
1908
+ {
1909
+ id: option.id,
1910
+ checked: isSelected,
1911
+ onCheckedChange: (checked) => handleSelectionChange(option.id, !!checked),
1912
+ className: "mr-3",
1913
+ "aria-label": option.text.replace(/<[^>]*>?/gm, "")
1914
+ }
1915
+ ),
1916
+ /* @__PURE__ */ jsx("div", { className: "text-base flex-1", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: option.text }) })
1917
+ ]
1918
+ },
1919
+ option.id
1920
+ );
1921
+ }) }),
1922
+ showCorrectAnswer && explanation && /* @__PURE__ */ jsxs("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md", children: [
1923
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Explanation:" }),
1924
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" })
1925
+ ] })
1926
+ ] })
1927
+ ] });
1974
1928
  };
1975
- var Input = React28.forwardRef(
1976
- (_a, ref) => {
1977
- var _b = _a, { className, type } = _b, props = __objRest(_b, ["className", "type"]);
1978
- return /* @__PURE__ */ React28.createElement(
1929
+ var Input = React9.forwardRef(
1930
+ ({ className, type, ...props }, ref) => {
1931
+ return /* @__PURE__ */ jsx(
1979
1932
  "input",
1980
- __spreadValues({
1933
+ {
1981
1934
  type,
1982
1935
  className: cn(
1983
1936
  "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
1984
1937
  className
1985
1938
  ),
1986
- ref
1987
- }, props)
1939
+ ref,
1940
+ ...props
1941
+ }
1988
1942
  );
1989
1943
  }
1990
1944
  );
1991
1945
  Input.displayName = "Input";
1992
-
1993
- // src/react-ui/components/ui/ShortAnswerQuestionUI.tsx
1994
1946
  var ShortAnswerQuestionUI = ({
1995
1947
  question,
1996
1948
  onAnswerChange,
@@ -2009,20 +1961,44 @@ var ShortAnswerQuestionUI = ({
2009
1961
  (accAns) => isCaseSensitive ? accAns.trim() === userAnswerTrimmed : accAns.trim().toLowerCase() === userAnswerTrimmed.toLowerCase()
2010
1962
  );
2011
1963
  }
2012
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: prompt })), points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0" }, /* @__PURE__ */ React28__default.createElement(Label, { htmlFor: `short-answer-input-${questionId}`, className: "sr-only" }, "Your Answer"), /* @__PURE__ */ React28__default.createElement(
2013
- Input,
2014
- {
2015
- id: `short-answer-input-${questionId}`,
2016
- type: "text",
2017
- value: displayUserAnswer,
2018
- onChange: handleInputChange,
2019
- placeholder: "Type your answer here...",
2020
- "aria-describedby": explanation ? `explanation-${questionId}` : void 0,
2021
- className: `
1964
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
1965
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
1966
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: prompt }) }),
1967
+ points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
1968
+ "Points: ",
1969
+ points
1970
+ ] })
1971
+ ] }),
1972
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0", children: [
1973
+ /* @__PURE__ */ jsx(Label, { htmlFor: `short-answer-input-${questionId}`, className: "sr-only", children: "Your Answer" }),
1974
+ /* @__PURE__ */ jsx(
1975
+ Input,
1976
+ {
1977
+ id: `short-answer-input-${questionId}`,
1978
+ type: "text",
1979
+ value: displayUserAnswer,
1980
+ onChange: handleInputChange,
1981
+ placeholder: "Type your answer here...",
1982
+ "aria-describedby": explanation ? `explanation-${questionId}` : void 0,
1983
+ className: `
2022
1984
  ${showCorrectAnswer && userAnswer ? isActuallyCorrect ? "border-green-500 focus-visible:ring-green-500" : "border-destructive focus-visible:ring-destructive" : "border-input"}
2023
1985
  `
2024
- }
2025
- ), showCorrectAnswer && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 space-y-2" }, userAnswer && !isActuallyCorrect && /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm text-destructive" }, "Your answer was marked incorrect."), /* @__PURE__ */ React28__default.createElement("div", { className: "p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Accepted Answers:"), /* @__PURE__ */ React28__default.createElement("ul", { className: "list-disc list-inside text-sm text-accent-foreground/80" }, acceptedAnswers.map((ans, idx) => /* @__PURE__ */ React28__default.createElement("li", { key: idx }, ans))), isCaseSensitive && /* @__PURE__ */ React28__default.createElement("p", { className: "text-xs text-muted-foreground mt-1" }, "(Case-sensitive)")), explanation && /* @__PURE__ */ React28__default.createElement("div", { id: `explanation-${questionId}`, className: "mt-2 p-3 bg-muted/30 border border-muted rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold" }, "Explanation:"), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: explanation, className: "text-sm text-muted-foreground" })))));
1986
+ }
1987
+ ),
1988
+ showCorrectAnswer && /* @__PURE__ */ jsxs("div", { className: "mt-4 space-y-2", children: [
1989
+ userAnswer && !isActuallyCorrect && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: "Your answer was marked incorrect." }),
1990
+ /* @__PURE__ */ jsxs("div", { className: "p-3 bg-accent/20 border border-accent rounded-md", children: [
1991
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Accepted Answers:" }),
1992
+ /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside text-sm text-accent-foreground/80", children: acceptedAnswers.map((ans, idx) => /* @__PURE__ */ jsx("li", { children: ans }, idx)) }),
1993
+ isCaseSensitive && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-1", children: "(Case-sensitive)" })
1994
+ ] }),
1995
+ explanation && /* @__PURE__ */ jsxs("div", { id: `explanation-${questionId}`, className: "mt-2 p-3 bg-muted/30 border border-muted rounded-md", children: [
1996
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: "Explanation:" }),
1997
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: explanation, className: "text-sm text-muted-foreground" })
1998
+ ] })
1999
+ ] })
2000
+ ] })
2001
+ ] });
2026
2002
  };
2027
2003
  var NumericQuestionUI = ({
2028
2004
  question,
@@ -2045,22 +2021,48 @@ var NumericQuestionUI = ({
2045
2021
  isActuallyCorrect = tolerance !== void 0 && tolerance !== null ? Math.abs(userAnswerNum - correctAnswerValue) <= tolerance : userAnswerNum === correctAnswerValue;
2046
2022
  }
2047
2023
  }
2048
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: prompt })), points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0" }, /* @__PURE__ */ React28__default.createElement(Label, { htmlFor: `numeric-input-${questionId}`, className: "sr-only" }, "Your Answer"), /* @__PURE__ */ React28__default.createElement(
2049
- Input,
2050
- {
2051
- id: `numeric-input-${questionId}`,
2052
- type: "text",
2053
- inputMode: "numeric",
2054
- pattern: "[0-9]*\\.?[0-9]*",
2055
- value: displayUserAnswer,
2056
- onChange: handleInputChange,
2057
- placeholder: "Enter a number",
2058
- "aria-describedby": explanation ? `explanation-${questionId}` : void 0,
2059
- className: `
2024
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
2025
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
2026
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: prompt }) }),
2027
+ points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
2028
+ "Points: ",
2029
+ points
2030
+ ] })
2031
+ ] }),
2032
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0", children: [
2033
+ /* @__PURE__ */ jsx(Label, { htmlFor: `numeric-input-${questionId}`, className: "sr-only", children: "Your Answer" }),
2034
+ /* @__PURE__ */ jsx(
2035
+ Input,
2036
+ {
2037
+ id: `numeric-input-${questionId}`,
2038
+ type: "text",
2039
+ inputMode: "numeric",
2040
+ pattern: "[0-9]*\\.?[0-9]*",
2041
+ value: displayUserAnswer,
2042
+ onChange: handleInputChange,
2043
+ placeholder: "Enter a number",
2044
+ "aria-describedby": explanation ? `explanation-${questionId}` : void 0,
2045
+ className: `
2060
2046
  ${showCorrectAnswer && userAnswer !== null && userAnswer !== "" ? isActuallyCorrect ? "border-green-500 focus-visible:ring-green-500" : "border-destructive focus-visible:ring-destructive" : "border-input"}
2061
2047
  `
2062
- }
2063
- ), showCorrectAnswer && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 space-y-2" }, userAnswer !== null && userAnswer !== "" && !isActuallyCorrect && /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm text-destructive" }, "Your answer was marked incorrect."), /* @__PURE__ */ React28__default.createElement("div", { className: "p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Correct Answer:"), /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm text-accent-foreground/80" }, correctAnswerValue, tolerance !== void 0 && tolerance !== null && tolerance > 0 && ` (Tolerance: \xB1${tolerance}, Accepted range: ${correctAnswerValue - tolerance} to ${correctAnswerValue + tolerance})`)), explanation && /* @__PURE__ */ React28__default.createElement("div", { id: `explanation-${questionId}`, className: "mt-2 p-3 bg-muted/30 border border-muted rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold" }, "Explanation:"), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: explanation, className: "text-sm text-muted-foreground" })))));
2048
+ }
2049
+ ),
2050
+ showCorrectAnswer && /* @__PURE__ */ jsxs("div", { className: "mt-4 space-y-2", children: [
2051
+ userAnswer !== null && userAnswer !== "" && !isActuallyCorrect && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: "Your answer was marked incorrect." }),
2052
+ /* @__PURE__ */ jsxs("div", { className: "p-3 bg-accent/20 border border-accent rounded-md", children: [
2053
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Correct Answer:" }),
2054
+ /* @__PURE__ */ jsxs("p", { className: "text-sm text-accent-foreground/80", children: [
2055
+ correctAnswerValue,
2056
+ tolerance !== void 0 && tolerance !== null && tolerance > 0 && ` (Tolerance: \xB1${tolerance}, Accepted range: ${correctAnswerValue - tolerance} to ${correctAnswerValue + tolerance})`
2057
+ ] })
2058
+ ] }),
2059
+ explanation && /* @__PURE__ */ jsxs("div", { id: `explanation-${questionId}`, className: "mt-2 p-3 bg-muted/30 border border-muted rounded-md", children: [
2060
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: "Explanation:" }),
2061
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: explanation, className: "text-sm text-muted-foreground" })
2062
+ ] })
2063
+ ] })
2064
+ ] })
2065
+ ] });
2064
2066
  };
2065
2067
  var FillInTheBlanksQuestionUI = ({
2066
2068
  question,
@@ -2084,15 +2086,14 @@ var FillInTheBlanksQuestionUI = ({
2084
2086
  }
2085
2087
  }, [segments, userAnswer]);
2086
2088
  const handleInputChange = (blankId, value) => {
2087
- const newInputs = __spreadProps(__spreadValues({}, userInputs), { [blankId]: value });
2089
+ const newInputs = { ...userInputs, [blankId]: value };
2088
2090
  setUserInputs(newInputs);
2089
2091
  const hasValue = Object.values(newInputs).some((val) => val.trim() !== "");
2090
2092
  onAnswerChange(hasValue ? newInputs : null);
2091
2093
  };
2092
2094
  const getCorrectnessForBlank = (blankId) => {
2093
- var _a;
2094
2095
  if (!showCorrectAnswer || !userInputs[blankId]) return null;
2095
- const userAnswerForBlank = (_a = userInputs[blankId]) == null ? void 0 : _a.trim();
2096
+ const userAnswerForBlank = userInputs[blankId]?.trim();
2096
2097
  const correctAnswerDef = correctAnswersMap.find((a) => a.blankId === blankId);
2097
2098
  if (!correctAnswerDef || !userAnswerForBlank) return false;
2098
2099
  const caseSensitive = isCaseSensitive === void 0 ? false : isCaseSensitive;
@@ -2100,49 +2101,78 @@ var FillInTheBlanksQuestionUI = ({
2100
2101
  (accVal) => caseSensitive ? accVal.trim() === userAnswerForBlank : accVal.trim().toLowerCase() === userAnswerForBlank.toLowerCase()
2101
2102
  );
2102
2103
  };
2103
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: prompt })), points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0" }, /* @__PURE__ */ React28__default.createElement("div", { className: "text-base leading-relaxed flex flex-wrap items-center gap-x-1", "aria-labelledby": `question-prompt-${questionId}` }, segments.map((segment, index) => {
2104
- var _a;
2105
- if (segment.type === "text") {
2106
- return /* @__PURE__ */ React28__default.createElement(
2107
- MarkdownRenderer,
2108
- {
2109
- key: `text-${index}`,
2110
- content: segment.content || "",
2111
- className: "inline"
2104
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
2105
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
2106
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: prompt }) }),
2107
+ points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
2108
+ "Points: ",
2109
+ points
2110
+ ] })
2111
+ ] }),
2112
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0", children: [
2113
+ /* @__PURE__ */ jsx("div", { className: "text-base leading-relaxed flex flex-wrap items-center gap-x-1", "aria-labelledby": `question-prompt-${questionId}`, children: segments.map((segment, index) => {
2114
+ if (segment.type === "text") {
2115
+ return /* @__PURE__ */ jsx(
2116
+ MarkdownRenderer,
2117
+ {
2118
+ content: segment.content || "",
2119
+ className: "inline"
2120
+ },
2121
+ `text-${index}`
2122
+ );
2112
2123
  }
2113
- );
2114
- }
2115
- if (segment.type === "blank" && segment.id) {
2116
- const blankId = segment.id;
2117
- const isCorrect = getCorrectnessForBlank(blankId);
2118
- let inputClassName = "inline-block w-auto min-w-[100px] max-w-[200px] h-8 mx-1 align-baseline text-base";
2119
- if (showCorrectAnswer && ((_a = userInputs[blankId]) == null ? void 0 : _a.trim())) {
2120
- inputClassName += isCorrect ? " border-green-500 focus-visible:ring-green-500" : " border-destructive focus-visible:ring-destructive";
2121
- } else {
2122
- inputClassName += " border-input";
2123
- }
2124
- return /* @__PURE__ */ React28__default.createElement(
2125
- Input,
2126
- {
2127
- key: blankId,
2128
- id: blankId,
2129
- type: "text",
2130
- value: userInputs[blankId] || "",
2131
- onChange: (e) => handleInputChange(blankId, e.target.value),
2132
- placeholder: "\u0110i\u1EC1n...",
2133
- className: inputClassName,
2134
- "aria-label": `Blank ${index + 1}`,
2135
- disabled: showCorrectAnswer
2124
+ if (segment.type === "blank" && segment.id) {
2125
+ const blankId = segment.id;
2126
+ const isCorrect = getCorrectnessForBlank(blankId);
2127
+ let inputClassName = "inline-block w-auto min-w-[100px] max-w-[200px] h-8 mx-1 align-baseline text-base";
2128
+ if (showCorrectAnswer && userInputs[blankId]?.trim()) {
2129
+ inputClassName += isCorrect ? " border-green-500 focus-visible:ring-green-500" : " border-destructive focus-visible:ring-destructive";
2130
+ } else {
2131
+ inputClassName += " border-input";
2132
+ }
2133
+ return /* @__PURE__ */ jsx(
2134
+ Input,
2135
+ {
2136
+ id: blankId,
2137
+ type: "text",
2138
+ value: userInputs[blankId] || "",
2139
+ onChange: (e) => handleInputChange(blankId, e.target.value),
2140
+ placeholder: "\u0110i\u1EC1n...",
2141
+ className: inputClassName,
2142
+ "aria-label": `Blank ${index + 1}`,
2143
+ disabled: showCorrectAnswer
2144
+ },
2145
+ blankId
2146
+ );
2136
2147
  }
2137
- );
2138
- }
2139
- return null;
2140
- })), showCorrectAnswer && explanation && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-6 p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Gi\u1EA3i th\xEDch chung:"), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" })), showCorrectAnswer && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 space-y-3" }, correctAnswersMap.map((ansDef) => {
2141
- var _a;
2142
- const isBlankCorrect = getCorrectnessForBlank(ansDef.blankId);
2143
- const userAnswerDisplay = userInputs[ansDef.blankId] || "Ch\u01B0a tr\u1EA3 l\u1EDDi";
2144
- return /* @__PURE__ */ React28__default.createElement("div", { key: `feedback-${ansDef.blankId}`, className: `p-2 border rounded-md ${isBlankCorrect ? "border-green-500/50 bg-green-500/10" : "border-destructive/50 bg-destructive/10"}` }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm" }, /* @__PURE__ */ React28__default.createElement("span", { className: "font-semibold" }, "\xD4 tr\u1ED1ng '", ((_a = segments.find((s) => s.id === ansDef.blankId && s.type === "blank")) == null ? void 0 : _a.id) || ansDef.blankId, "':"), ' B\u1EA1n \u0111\xE3 \u0111i\u1EC1n: "', userAnswerDisplay, '".'), /* @__PURE__ */ React28__default.createElement("p", { className: "text-xs" }, "\u0110\xE1p \xE1n ch\u1EA5p nh\u1EADn: ", ansDef.acceptedValues.join(", ")));
2145
- }))));
2148
+ return null;
2149
+ }) }),
2150
+ showCorrectAnswer && explanation && /* @__PURE__ */ jsxs("div", { className: "mt-6 p-3 bg-accent/20 border border-accent rounded-md", children: [
2151
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Gi\u1EA3i th\xEDch chung:" }),
2152
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" })
2153
+ ] }),
2154
+ showCorrectAnswer && /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-3", children: correctAnswersMap.map((ansDef) => {
2155
+ const isBlankCorrect = getCorrectnessForBlank(ansDef.blankId);
2156
+ const userAnswerDisplay = userInputs[ansDef.blankId] || "Ch\u01B0a tr\u1EA3 l\u1EDDi";
2157
+ return /* @__PURE__ */ jsxs("div", { className: `p-2 border rounded-md ${isBlankCorrect ? "border-green-500/50 bg-green-500/10" : "border-destructive/50 bg-destructive/10"}`, children: [
2158
+ /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
2159
+ /* @__PURE__ */ jsxs("span", { className: "font-semibold", children: [
2160
+ "\xD4 tr\u1ED1ng '",
2161
+ segments.find((s) => s.id === ansDef.blankId && s.type === "blank")?.id || ansDef.blankId,
2162
+ "':"
2163
+ ] }),
2164
+ ' B\u1EA1n \u0111\xE3 \u0111i\u1EC1n: "',
2165
+ userAnswerDisplay,
2166
+ '".'
2167
+ ] }),
2168
+ /* @__PURE__ */ jsxs("p", { className: "text-xs", children: [
2169
+ "\u0110\xE1p \xE1n ch\u1EA5p nh\u1EADn: ",
2170
+ ansDef.acceptedValues.join(", ")
2171
+ ] })
2172
+ ] }, `feedback-${ansDef.blankId}`);
2173
+ }) })
2174
+ ] })
2175
+ ] });
2146
2176
  };
2147
2177
  var buttonVariants = cva(
2148
2178
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
@@ -2169,16 +2199,16 @@ var buttonVariants = cva(
2169
2199
  }
2170
2200
  }
2171
2201
  );
2172
- var Button = React28.forwardRef(
2173
- (_a, ref) => {
2174
- var _b = _a, { className, variant, size, asChild = false } = _b, props = __objRest(_b, ["className", "variant", "size", "asChild"]);
2202
+ var Button = React9.forwardRef(
2203
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
2175
2204
  const Comp = asChild ? Slot : "button";
2176
- return /* @__PURE__ */ React28.createElement(
2205
+ return /* @__PURE__ */ jsx(
2177
2206
  Comp,
2178
- __spreadValues({
2207
+ {
2179
2208
  className: cn(buttonVariants({ variant, size, className })),
2180
- ref
2181
- }, props)
2209
+ ref,
2210
+ ...props
2211
+ }
2182
2212
  );
2183
2213
  }
2184
2214
  );
@@ -2233,145 +2263,180 @@ var SequenceQuestionUI = ({
2233
2263
  if (!showCorrectAnswer || !Array.isArray(userAnswer) || userAnswer.length <= index) return null;
2234
2264
  const userItemId = userAnswer[index];
2235
2265
  const correctItemId = correctOrder[index];
2236
- return userItemId === correctItemId ? /* @__PURE__ */ React28__default.createElement(CheckCircle, { className: "h-4 w-4 text-green-500 ml-2 flex-shrink-0" }) : /* @__PURE__ */ React28__default.createElement(XCircle, { className: "h-4 w-4 text-destructive ml-2 flex-shrink-0" });
2266
+ return userItemId === correctItemId ? /* @__PURE__ */ jsx(CheckCircle, { className: "h-4 w-4 text-green-500 ml-2 flex-shrink-0" }) : /* @__PURE__ */ jsx(XCircle, { className: "h-4 w-4 text-destructive ml-2 flex-shrink-0" });
2237
2267
  };
2238
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: prompt })), points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0 space-y-6" }, /* @__PURE__ */ React28__default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ React28__default.createElement(Label, { className: "font-semibold" }, "S\u1EAFp x\u1EBFp c\xE1c m\u1EE5c sau theo \u0111\xFAng th\u1EE9 t\u1EF1:"), /* @__PURE__ */ React28__default.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-2" }, availableItems.map((item) => /* @__PURE__ */ React28__default.createElement(
2239
- Button,
2240
- {
2241
- key: item.id,
2242
- variant: "outline",
2243
- onClick: () => handleSelectItem(item),
2244
- className: "justify-start text-left h-auto py-2 px-3 whitespace-normal",
2245
- disabled: showCorrectAnswer
2246
- },
2247
- /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: item.content })
2248
- ))), availableItems.length === 0 && selectedSequence.length > 0 && /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm text-muted-foreground" }, 'T\u1EA5t c\u1EA3 c\xE1c m\u1EE5c \u0111\xE3 \u0111\u01B0\u1EE3c ch\u1ECDn. Nh\u1EA5p v\xE0o m\u1EE5c trong "Th\u1EE9 t\u1EF1 b\u1EA1n \u0111\xE3 ch\u1ECDn" \u0111\u1EC3 b\u1ECF ch\u1ECDn.')), /* @__PURE__ */ React28__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React28__default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React28__default.createElement(Label, { className: "font-semibold" }, "Th\u1EE9 t\u1EF1 b\u1EA1n \u0111\xE3 ch\u1ECDn:"), /* @__PURE__ */ React28__default.createElement(Button, { variant: "ghost", size: "sm", onClick: handleResetSequence, disabled: showCorrectAnswer || selectedSequence.length === 0 }, /* @__PURE__ */ React28__default.createElement(RotateCcw, { className: "mr-2 h-3.5 w-3.5" }), " \u0110\u1EB7t l\u1EA1i")), selectedSequence.length === 0 ? /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm text-muted-foreground p-3 border border-dashed rounded-md" }, "Ch\u01B0a ch\u1ECDn m\u1EE5c n\xE0o. Nh\u1EA5p v\xE0o c\xE1c m\u1EE5c \u1EDF tr\xEAn \u0111\u1EC3 b\u1EAFt \u0111\u1EA7u.") : /* @__PURE__ */ React28__default.createElement("ul", { className: "space-y-2" }, selectedSequence.map((item, index) => /* @__PURE__ */ React28__default.createElement(
2249
- "li",
2250
- {
2251
- key: item.id,
2252
- onClick: () => handleRemoveFromSequence(item, index),
2253
- className: `flex items-center justify-between p-3 border rounded-md whitespace-normal ${showCorrectAnswer ? (userAnswer == null ? void 0 : userAnswer[index]) === correctOrder[index] ? "border-green-500 bg-green-500/10" : "border-destructive bg-destructive/10" : "bg-muted/30 cursor-pointer hover:border-destructive/50"} transition-colors`
2254
- },
2255
- /* @__PURE__ */ React28__default.createElement("div", { className: "flex-grow flex items-center" }, /* @__PURE__ */ React28__default.createElement("span", { className: "font-semibold mr-2" }, index + 1, "."), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: item.content })),
2256
- showCorrectAnswer ? getFeedbackIcon(index) : /* @__PURE__ */ React28__default.createElement(XCircle, { className: "h-4 w-4 text-muted-foreground hover:text-destructive flex-shrink-0" })
2257
- )))), showCorrectAnswer && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 space-y-2" }, /* @__PURE__ */ React28__default.createElement("div", { className: "p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Th\u1EE9 t\u1EF1 \u0111\xFAng:"), /* @__PURE__ */ React28__default.createElement("ol", { className: "list-decimal list-inside text-sm text-accent-foreground/80 space-y-1 mt-1" }, correctOrder.map((itemId) => {
2258
- const item = items.find((i) => i.id === itemId);
2259
- return /* @__PURE__ */ React28__default.createElement("li", { key: itemId }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: item ? item.content : "Kh\xF4ng t\xECm th\u1EA5y m\u1EE5c" }));
2260
- }))), explanation && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-2 p-3 bg-muted/30 border border-muted rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold" }, "Gi\u1EA3i th\xEDch:"), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: explanation, className: "text-sm text-muted-foreground" })))));
2268
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
2269
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
2270
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: prompt }) }),
2271
+ points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
2272
+ "Points: ",
2273
+ points
2274
+ ] })
2275
+ ] }),
2276
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0 space-y-6", children: [
2277
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
2278
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold", children: "S\u1EAFp x\u1EBFp c\xE1c m\u1EE5c sau theo \u0111\xFAng th\u1EE9 t\u1EF1:" }),
2279
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-2", children: availableItems.map((item) => /* @__PURE__ */ jsx(
2280
+ Button,
2281
+ {
2282
+ variant: "outline",
2283
+ onClick: () => handleSelectItem(item),
2284
+ className: "justify-start text-left h-auto py-2 px-3 whitespace-normal",
2285
+ disabled: showCorrectAnswer,
2286
+ children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: item.content })
2287
+ },
2288
+ item.id
2289
+ )) }),
2290
+ availableItems.length === 0 && selectedSequence.length > 0 && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: 'T\u1EA5t c\u1EA3 c\xE1c m\u1EE5c \u0111\xE3 \u0111\u01B0\u1EE3c ch\u1ECDn. Nh\u1EA5p v\xE0o m\u1EE5c trong "Th\u1EE9 t\u1EF1 b\u1EA1n \u0111\xE3 ch\u1ECDn" \u0111\u1EC3 b\u1ECF ch\u1ECDn.' })
2291
+ ] }),
2292
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2293
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
2294
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold", children: "Th\u1EE9 t\u1EF1 b\u1EA1n \u0111\xE3 ch\u1ECDn:" }),
2295
+ /* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: handleResetSequence, disabled: showCorrectAnswer || selectedSequence.length === 0, children: [
2296
+ /* @__PURE__ */ jsx(RotateCcw, { className: "mr-2 h-3.5 w-3.5" }),
2297
+ " \u0110\u1EB7t l\u1EA1i"
2298
+ ] })
2299
+ ] }),
2300
+ selectedSequence.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground p-3 border border-dashed rounded-md", children: "Ch\u01B0a ch\u1ECDn m\u1EE5c n\xE0o. Nh\u1EA5p v\xE0o c\xE1c m\u1EE5c \u1EDF tr\xEAn \u0111\u1EC3 b\u1EAFt \u0111\u1EA7u." }) : /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: selectedSequence.map((item, index) => /* @__PURE__ */ jsxs(
2301
+ "li",
2302
+ {
2303
+ onClick: () => handleRemoveFromSequence(item, index),
2304
+ className: `flex items-center justify-between p-3 border rounded-md whitespace-normal ${showCorrectAnswer ? userAnswer?.[index] === correctOrder[index] ? "border-green-500 bg-green-500/10" : "border-destructive bg-destructive/10" : "bg-muted/30 cursor-pointer hover:border-destructive/50"} transition-colors`,
2305
+ children: [
2306
+ /* @__PURE__ */ jsxs("div", { className: "flex-grow flex items-center", children: [
2307
+ /* @__PURE__ */ jsxs("span", { className: "font-semibold mr-2", children: [
2308
+ index + 1,
2309
+ "."
2310
+ ] }),
2311
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: item.content })
2312
+ ] }),
2313
+ showCorrectAnswer ? getFeedbackIcon(index) : /* @__PURE__ */ jsx(XCircle, { className: "h-4 w-4 text-muted-foreground hover:text-destructive flex-shrink-0" })
2314
+ ]
2315
+ },
2316
+ item.id
2317
+ )) })
2318
+ ] }),
2319
+ showCorrectAnswer && /* @__PURE__ */ jsxs("div", { className: "mt-4 space-y-2", children: [
2320
+ /* @__PURE__ */ jsxs("div", { className: "p-3 bg-accent/20 border border-accent rounded-md", children: [
2321
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Th\u1EE9 t\u1EF1 \u0111\xFAng:" }),
2322
+ /* @__PURE__ */ jsx("ol", { className: "list-decimal list-inside text-sm text-accent-foreground/80 space-y-1 mt-1", children: correctOrder.map((itemId) => {
2323
+ const item = items.find((i) => i.id === itemId);
2324
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: item ? item.content : "Kh\xF4ng t\xECm th\u1EA5y m\u1EE5c" }) }, itemId);
2325
+ }) })
2326
+ ] }),
2327
+ explanation && /* @__PURE__ */ jsxs("div", { className: "mt-2 p-3 bg-muted/30 border border-muted rounded-md", children: [
2328
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: "Gi\u1EA3i th\xEDch:" }),
2329
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: explanation, className: "text-sm text-muted-foreground" })
2330
+ ] })
2331
+ ] })
2332
+ ] })
2333
+ ] });
2261
2334
  };
2262
2335
  var Select = SelectPrimitive.Root;
2263
2336
  var SelectValue = SelectPrimitive.Value;
2264
- var SelectTrigger = React28.forwardRef((_a, ref) => {
2265
- var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
2266
- return /* @__PURE__ */ React28.createElement(
2267
- SelectPrimitive.Trigger,
2268
- __spreadValues({
2269
- ref,
2270
- className: cn(
2271
- "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
2272
- className
2273
- )
2274
- }, props),
2275
- children,
2276
- /* @__PURE__ */ React28.createElement(SelectPrimitive.Icon, { asChild: true }, /* @__PURE__ */ React28.createElement(ChevronDown, { className: "h-4 w-4 opacity-50" }))
2277
- );
2278
- });
2337
+ var SelectTrigger = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
2338
+ SelectPrimitive.Trigger,
2339
+ {
2340
+ ref,
2341
+ className: cn(
2342
+ "flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
2343
+ className
2344
+ ),
2345
+ ...props,
2346
+ children: [
2347
+ children,
2348
+ /* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
2349
+ ]
2350
+ }
2351
+ ));
2279
2352
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
2280
- var SelectScrollUpButton = React28.forwardRef((_a, ref) => {
2281
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
2282
- return /* @__PURE__ */ React28.createElement(
2283
- SelectPrimitive.ScrollUpButton,
2284
- __spreadValues({
2285
- ref,
2286
- className: cn(
2287
- "flex cursor-default items-center justify-center py-1",
2288
- className
2289
- )
2290
- }, props),
2291
- /* @__PURE__ */ React28.createElement(ChevronUp, { className: "h-4 w-4" })
2292
- );
2293
- });
2353
+ var SelectScrollUpButton = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2354
+ SelectPrimitive.ScrollUpButton,
2355
+ {
2356
+ ref,
2357
+ className: cn(
2358
+ "flex cursor-default items-center justify-center py-1",
2359
+ className
2360
+ ),
2361
+ ...props,
2362
+ children: /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4" })
2363
+ }
2364
+ ));
2294
2365
  SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
2295
- var SelectScrollDownButton = React28.forwardRef((_a, ref) => {
2296
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
2297
- return /* @__PURE__ */ React28.createElement(
2298
- SelectPrimitive.ScrollDownButton,
2299
- __spreadValues({
2300
- ref,
2301
- className: cn(
2302
- "flex cursor-default items-center justify-center py-1",
2303
- className
2304
- )
2305
- }, props),
2306
- /* @__PURE__ */ React28.createElement(ChevronDown, { className: "h-4 w-4" })
2307
- );
2308
- });
2366
+ var SelectScrollDownButton = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2367
+ SelectPrimitive.ScrollDownButton,
2368
+ {
2369
+ ref,
2370
+ className: cn(
2371
+ "flex cursor-default items-center justify-center py-1",
2372
+ className
2373
+ ),
2374
+ ...props,
2375
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4" })
2376
+ }
2377
+ ));
2309
2378
  SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
2310
- var SelectContent = React28.forwardRef((_a, ref) => {
2311
- var _b = _a, { className, children, position = "popper" } = _b, props = __objRest(_b, ["className", "children", "position"]);
2312
- return /* @__PURE__ */ React28.createElement(SelectPrimitive.Portal, null, /* @__PURE__ */ React28.createElement(
2313
- SelectPrimitive.Content,
2314
- __spreadValues({
2315
- ref,
2316
- className: cn(
2317
- "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
2318
- position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
2319
- className
2320
- ),
2321
- position
2322
- }, props),
2323
- /* @__PURE__ */ React28.createElement(SelectScrollUpButton, null),
2324
- /* @__PURE__ */ React28.createElement(
2325
- SelectPrimitive.Viewport,
2326
- {
2327
- className: cn(
2328
- "p-1",
2329
- position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
2330
- )
2331
- },
2332
- children
2379
+ var SelectContent = React9.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
2380
+ SelectPrimitive.Content,
2381
+ {
2382
+ ref,
2383
+ className: cn(
2384
+ "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
2385
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
2386
+ className
2333
2387
  ),
2334
- /* @__PURE__ */ React28.createElement(SelectScrollDownButton, null)
2335
- ));
2336
- });
2388
+ position,
2389
+ ...props,
2390
+ children: [
2391
+ /* @__PURE__ */ jsx(SelectScrollUpButton, {}),
2392
+ /* @__PURE__ */ jsx(
2393
+ SelectPrimitive.Viewport,
2394
+ {
2395
+ className: cn(
2396
+ "p-1",
2397
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
2398
+ ),
2399
+ children
2400
+ }
2401
+ ),
2402
+ /* @__PURE__ */ jsx(SelectScrollDownButton, {})
2403
+ ]
2404
+ }
2405
+ ) }));
2337
2406
  SelectContent.displayName = SelectPrimitive.Content.displayName;
2338
- var SelectLabel = React28.forwardRef((_a, ref) => {
2339
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
2340
- return /* @__PURE__ */ React28.createElement(
2341
- SelectPrimitive.Label,
2342
- __spreadValues({
2343
- ref,
2344
- className: cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)
2345
- }, props)
2346
- );
2347
- });
2407
+ var SelectLabel = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2408
+ SelectPrimitive.Label,
2409
+ {
2410
+ ref,
2411
+ className: cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className),
2412
+ ...props
2413
+ }
2414
+ ));
2348
2415
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
2349
- var SelectItem = React28.forwardRef((_a, ref) => {
2350
- var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
2351
- return /* @__PURE__ */ React28.createElement(
2352
- SelectPrimitive.Item,
2353
- __spreadValues({
2354
- ref,
2355
- className: cn(
2356
- "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
2357
- className
2358
- )
2359
- }, props),
2360
- /* @__PURE__ */ React28.createElement("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center" }, /* @__PURE__ */ React28.createElement(SelectPrimitive.ItemIndicator, null, /* @__PURE__ */ React28.createElement(Check, { className: "h-4 w-4" }))),
2361
- /* @__PURE__ */ React28.createElement(SelectPrimitive.ItemText, null, children)
2362
- );
2363
- });
2416
+ var SelectItem = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
2417
+ SelectPrimitive.Item,
2418
+ {
2419
+ ref,
2420
+ className: cn(
2421
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
2422
+ className
2423
+ ),
2424
+ ...props,
2425
+ children: [
2426
+ /* @__PURE__ */ jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) }) }),
2427
+ /* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
2428
+ ]
2429
+ }
2430
+ ));
2364
2431
  SelectItem.displayName = SelectPrimitive.Item.displayName;
2365
- var SelectSeparator = React28.forwardRef((_a, ref) => {
2366
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
2367
- return /* @__PURE__ */ React28.createElement(
2368
- SelectPrimitive.Separator,
2369
- __spreadValues({
2370
- ref,
2371
- className: cn("-mx-1 my-1 h-px bg-muted", className)
2372
- }, props)
2373
- );
2374
- });
2432
+ var SelectSeparator = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2433
+ SelectPrimitive.Separator,
2434
+ {
2435
+ ref,
2436
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
2437
+ ...props
2438
+ }
2439
+ ));
2375
2440
  SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
2376
2441
  var MatchingQuestionUI = ({
2377
2442
  question,
@@ -2399,14 +2464,13 @@ var MatchingQuestionUI = ({
2399
2464
  }
2400
2465
  }, [userAnswer, prompts]);
2401
2466
  const handleSelectChange = (promptId, optionId) => {
2402
- const newAnswers = __spreadProps(__spreadValues({}, currentAnswers), { [promptId]: optionId });
2467
+ const newAnswers = { ...currentAnswers, [promptId]: optionId };
2403
2468
  setCurrentAnswers(newAnswers);
2404
2469
  const hasSelection = Object.values(newAnswers).some((val) => val && val !== "");
2405
2470
  onAnswerChange(hasSelection ? newAnswers : null);
2406
2471
  };
2407
2472
  const getCorrectOptionIdForPrompt = (promptId) => {
2408
- var _a;
2409
- return (_a = correctAnswerMap.find((map) => map.promptId === promptId)) == null ? void 0 : _a.optionId;
2473
+ return correctAnswerMap.find((map) => map.promptId === promptId)?.optionId;
2410
2474
  };
2411
2475
  const getPlainText = (htmlString) => {
2412
2476
  if (!htmlString) return "";
@@ -2417,31 +2481,58 @@ var MatchingQuestionUI = ({
2417
2481
  }
2418
2482
  return htmlString.replace(/<[^>]*>?/gm, "");
2419
2483
  };
2420
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: prompt })), points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0 space-y-4" }, /* @__PURE__ */ React28__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-x-8 gap-y-4" }, prompts.map((promptItem) => {
2421
- var _a;
2422
- const selectedOptionId = currentAnswers[promptItem.id] || "";
2423
- const correctOptionId = getCorrectOptionIdForPrompt(promptItem.id);
2424
- const isSelectionCorrect = showCorrectAnswer && selectedOptionId ? selectedOptionId === correctOptionId : null;
2425
- let borderColor = "border-muted";
2426
- if (showCorrectAnswer && selectedOptionId) {
2427
- borderColor = isSelectionCorrect ? "border-green-500" : "border-destructive";
2428
- }
2429
- return /* @__PURE__ */ React28__default.createElement("div", { key: promptItem.id, className: `p-3 border rounded-md ${borderColor} transition-colors bg-background` }, /* @__PURE__ */ React28__default.createElement(Label, { htmlFor: `select-prompt-${promptItem.id}`, className: "font-medium text-base block mb-2 whitespace-normal" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: promptItem.content })), /* @__PURE__ */ React28__default.createElement(
2430
- Select,
2431
- {
2432
- value: selectedOptionId,
2433
- onValueChange: (value) => handleSelectChange(promptItem.id, value),
2434
- disabled: showCorrectAnswer
2435
- },
2436
- /* @__PURE__ */ React28__default.createElement(SelectTrigger, { id: `select-prompt-${promptItem.id}` }, /* @__PURE__ */ React28__default.createElement(SelectValue, { placeholder: "Ch\u1ECDn \u0111\xE1p \xE1n..." })),
2437
- /* @__PURE__ */ React28__default.createElement(SelectContent, null, shuffledOptions.map((option) => /* @__PURE__ */ React28__default.createElement(SelectItem, { key: option.id, value: option.id, className: "whitespace-normal" }, getPlainText(option.content))))
2438
- ), showCorrectAnswer && selectedOptionId && (isSelectionCorrect ? /* @__PURE__ */ React28__default.createElement(CheckCircle, { className: "h-5 w-5 text-green-500 mt-2 inline-block" }) : /* @__PURE__ */ React28__default.createElement(XCircle, { className: "h-5 w-5 text-destructive mt-2 inline-block" })), showCorrectAnswer && !selectedOptionId && correctOptionId && /* @__PURE__ */ React28__default.createElement("p", { className: "text-xs text-muted-foreground mt-1" }, "Ch\u01B0a ch\u1ECDn. \u0110\xE1p \xE1n \u0111\xFAng: ", getPlainText((_a = shuffledOptions.find((o) => o.id === correctOptionId)) == null ? void 0 : _a.content)));
2439
- })), showCorrectAnswer && explanation && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-6 p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Gi\u1EA3i th\xEDch:"), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" })), showCorrectAnswer && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 space-y-2" }, /* @__PURE__ */ React28__default.createElement("p", { className: "font-semibold text-md" }, "\u0110\xE1p \xE1n \u0111\xFAng:"), /* @__PURE__ */ React28__default.createElement("ul", { className: "list-disc list-inside space-y-1 text-sm" }, correctAnswerMap.map((map) => {
2440
- var _a, _b;
2441
- const promptText = (_a = prompts.find((p) => p.id === map.promptId)) == null ? void 0 : _a.content;
2442
- const optionText = (_b = initialOptions.find((o) => o.id === map.optionId)) == null ? void 0 : _b.content;
2443
- return /* @__PURE__ */ React28__default.createElement("li", { key: map.promptId }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: `<strong>${getPlainText(promptText) || "N/A"}</strong> gh\xE9p v\u1EDBi <strong>${getPlainText(optionText) || "N/A"}</strong>` }));
2444
- })))));
2484
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
2485
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
2486
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: prompt }) }),
2487
+ points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
2488
+ "Points: ",
2489
+ points
2490
+ ] })
2491
+ ] }),
2492
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0 space-y-4", children: [
2493
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-x-8 gap-y-4", children: prompts.map((promptItem) => {
2494
+ const selectedOptionId = currentAnswers[promptItem.id] || "";
2495
+ const correctOptionId = getCorrectOptionIdForPrompt(promptItem.id);
2496
+ const isSelectionCorrect = showCorrectAnswer && selectedOptionId ? selectedOptionId === correctOptionId : null;
2497
+ let borderColor = "border-muted";
2498
+ if (showCorrectAnswer && selectedOptionId) {
2499
+ borderColor = isSelectionCorrect ? "border-green-500" : "border-destructive";
2500
+ }
2501
+ return /* @__PURE__ */ jsxs("div", { className: `p-3 border rounded-md ${borderColor} transition-colors bg-background`, children: [
2502
+ /* @__PURE__ */ jsx(Label, { htmlFor: `select-prompt-${promptItem.id}`, className: "font-medium text-base block mb-2 whitespace-normal", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: promptItem.content }) }),
2503
+ /* @__PURE__ */ jsxs(
2504
+ Select,
2505
+ {
2506
+ value: selectedOptionId,
2507
+ onValueChange: (value) => handleSelectChange(promptItem.id, value),
2508
+ disabled: showCorrectAnswer,
2509
+ children: [
2510
+ /* @__PURE__ */ jsx(SelectTrigger, { id: `select-prompt-${promptItem.id}`, children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Ch\u1ECDn \u0111\xE1p \xE1n..." }) }),
2511
+ /* @__PURE__ */ jsx(SelectContent, { children: shuffledOptions.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.id, className: "whitespace-normal", children: getPlainText(option.content) }, option.id)) })
2512
+ ]
2513
+ }
2514
+ ),
2515
+ showCorrectAnswer && selectedOptionId && (isSelectionCorrect ? /* @__PURE__ */ jsx(CheckCircle, { className: "h-5 w-5 text-green-500 mt-2 inline-block" }) : /* @__PURE__ */ jsx(XCircle, { className: "h-5 w-5 text-destructive mt-2 inline-block" })),
2516
+ showCorrectAnswer && !selectedOptionId && correctOptionId && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground mt-1", children: [
2517
+ "Ch\u01B0a ch\u1ECDn. \u0110\xE1p \xE1n \u0111\xFAng: ",
2518
+ getPlainText(shuffledOptions.find((o) => o.id === correctOptionId)?.content)
2519
+ ] })
2520
+ ] }, promptItem.id);
2521
+ }) }),
2522
+ showCorrectAnswer && explanation && /* @__PURE__ */ jsxs("div", { className: "mt-6 p-3 bg-accent/20 border border-accent rounded-md", children: [
2523
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Gi\u1EA3i th\xEDch:" }),
2524
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" })
2525
+ ] }),
2526
+ showCorrectAnswer && /* @__PURE__ */ jsxs("div", { className: "mt-4 space-y-2", children: [
2527
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-md", children: "\u0110\xE1p \xE1n \u0111\xFAng:" }),
2528
+ /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside space-y-1 text-sm", children: correctAnswerMap.map((map) => {
2529
+ const promptText = prompts.find((p) => p.id === map.promptId)?.content;
2530
+ const optionText = initialOptions.find((o) => o.id === map.optionId)?.content;
2531
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: `<strong>${getPlainText(promptText) || "N/A"}</strong> gh\xE9p v\u1EDBi <strong>${getPlainText(optionText) || "N/A"}</strong>` }) }, map.promptId);
2532
+ }) })
2533
+ ] })
2534
+ ] })
2535
+ ] });
2445
2536
  };
2446
2537
  var DragAndDropQuestionUI = ({
2447
2538
  question,
@@ -2461,41 +2552,70 @@ var DragAndDropQuestionUI = ({
2461
2552
  }
2462
2553
  }, [userAnswer, draggableItems]);
2463
2554
  const handleSelectChange = (draggableItemId, dropZoneId) => {
2464
- const newAnswers = __spreadProps(__spreadValues({}, currentAnswers), { [draggableItemId]: dropZoneId });
2555
+ const newAnswers = { ...currentAnswers, [draggableItemId]: dropZoneId };
2465
2556
  setCurrentAnswers(newAnswers);
2466
2557
  const hasSelection = Object.values(newAnswers).some((val) => val && val !== "");
2467
2558
  onAnswerChange(hasSelection ? newAnswers : null);
2468
2559
  };
2469
2560
  const getCorrectDropZoneIdForDraggable = (draggableItemId) => {
2470
- var _a;
2471
- return (_a = answerMap.find((map) => map.draggableId === draggableItemId)) == null ? void 0 : _a.dropZoneId;
2561
+ return answerMap.find((map) => map.draggableId === draggableItemId)?.dropZoneId;
2472
2562
  };
2473
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: prompt })), points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0 space-y-4" }, backgroundImageUrl && /* @__PURE__ */ React28__default.createElement("div", { className: "mb-4 overflow-hidden rounded-md border" }, /* @__PURE__ */ React28__default.createElement("img", { src: backgroundImageUrl, alt: question.imageAltText || "Drag and drop background", className: "w-full h-auto object-contain max-h-[300px]", "data-ai-hint": "abstract pattern" })), /* @__PURE__ */ React28__default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ React28__default.createElement(Label, { className: "font-semibold" }, "Gh\xE9p c\xE1c m\u1EE5c sau v\xE0o \u0111\xFAng v\u1ECB tr\xED:"), draggableItems.map((item) => {
2474
- const selectedDropZoneId = currentAnswers[item.id] || "";
2475
- const correctDropZoneId = getCorrectDropZoneIdForDraggable(item.id);
2476
- const isSelectionCorrect = showCorrectAnswer && selectedDropZoneId ? selectedDropZoneId === correctDropZoneId : null;
2477
- let itemStyle = "flex flex-col sm:flex-row items-start sm:items-center justify-between p-3 border rounded-md transition-colors bg-background";
2478
- if (showCorrectAnswer && selectedDropZoneId) {
2479
- itemStyle += isSelectionCorrect ? " border-green-500" : " border-destructive";
2480
- } else {
2481
- itemStyle += " border-muted";
2482
- }
2483
- return /* @__PURE__ */ React28__default.createElement("div", { key: item.id, className: itemStyle }, /* @__PURE__ */ React28__default.createElement(Label, { htmlFor: `select-draggable-${item.id}`, className: "font-medium text-base mb-2 sm:mb-0 sm:mr-4 flex-1" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: item.content })), /* @__PURE__ */ React28__default.createElement("div", { className: "flex items-center space-x-2 w-full sm:w-auto" }, /* @__PURE__ */ React28__default.createElement(
2484
- Select,
2485
- {
2486
- value: selectedDropZoneId,
2487
- onValueChange: (value) => handleSelectChange(item.id, value),
2488
- disabled: showCorrectAnswer
2489
- },
2490
- /* @__PURE__ */ React28__default.createElement(SelectTrigger, { id: `select-draggable-${item.id}`, className: "w-full sm:min-w-[200px]" }, /* @__PURE__ */ React28__default.createElement(SelectValue, { placeholder: "Ch\u1ECDn v\u1ECB tr\xED..." })),
2491
- /* @__PURE__ */ React28__default.createElement(SelectContent, null, dropZones.map((zone) => /* @__PURE__ */ React28__default.createElement(SelectItem, { key: zone.id, value: zone.id }, zone.label.replace(/<[^>]*>?/gm, ""))))
2492
- ), showCorrectAnswer && selectedDropZoneId && (isSelectionCorrect ? /* @__PURE__ */ React28__default.createElement(CheckCircle, { className: "h-5 w-5 text-green-500 flex-shrink-0" }) : /* @__PURE__ */ React28__default.createElement(XCircle, { className: "h-5 w-5 text-destructive flex-shrink-0" }))));
2493
- })), showCorrectAnswer && explanation && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-6 p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Gi\u1EA3i th\xEDch:"), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" })), showCorrectAnswer && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 space-y-2" }, /* @__PURE__ */ React28__default.createElement("p", { className: "font-semibold text-md" }, "\u0110\xE1p \xE1n \u0111\xFAng:"), /* @__PURE__ */ React28__default.createElement("ul", { className: "list-disc list-inside space-y-1 text-sm" }, answerMap.map((map) => {
2494
- var _a, _b;
2495
- const draggableText = (_a = draggableItems.find((d) => d.id === map.draggableId)) == null ? void 0 : _a.content;
2496
- const dropZoneText = (_b = dropZones.find((z3) => z3.id === map.dropZoneId)) == null ? void 0 : _b.label;
2497
- return /* @__PURE__ */ React28__default.createElement("li", { key: map.draggableId }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: `<strong>${draggableText || "N/A"}</strong> v\xE0o <strong>${dropZoneText || "N/A"}</strong>` }));
2498
- })))));
2563
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
2564
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
2565
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: prompt }) }),
2566
+ points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
2567
+ "Points: ",
2568
+ points
2569
+ ] })
2570
+ ] }),
2571
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0 space-y-4", children: [
2572
+ backgroundImageUrl && /* @__PURE__ */ jsx("div", { className: "mb-4 overflow-hidden rounded-md border", children: /* @__PURE__ */ jsx("img", { src: backgroundImageUrl, alt: question.imageAltText || "Drag and drop background", className: "w-full h-auto object-contain max-h-[300px]", "data-ai-hint": "abstract pattern" }) }),
2573
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
2574
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold", children: "Gh\xE9p c\xE1c m\u1EE5c sau v\xE0o \u0111\xFAng v\u1ECB tr\xED:" }),
2575
+ draggableItems.map((item) => {
2576
+ const selectedDropZoneId = currentAnswers[item.id] || "";
2577
+ const correctDropZoneId = getCorrectDropZoneIdForDraggable(item.id);
2578
+ const isSelectionCorrect = showCorrectAnswer && selectedDropZoneId ? selectedDropZoneId === correctDropZoneId : null;
2579
+ let itemStyle = "flex flex-col sm:flex-row items-start sm:items-center justify-between p-3 border rounded-md transition-colors bg-background";
2580
+ if (showCorrectAnswer && selectedDropZoneId) {
2581
+ itemStyle += isSelectionCorrect ? " border-green-500" : " border-destructive";
2582
+ } else {
2583
+ itemStyle += " border-muted";
2584
+ }
2585
+ return /* @__PURE__ */ jsxs("div", { className: itemStyle, children: [
2586
+ /* @__PURE__ */ jsx(Label, { htmlFor: `select-draggable-${item.id}`, className: "font-medium text-base mb-2 sm:mb-0 sm:mr-4 flex-1", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: item.content }) }),
2587
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2 w-full sm:w-auto", children: [
2588
+ /* @__PURE__ */ jsxs(
2589
+ Select,
2590
+ {
2591
+ value: selectedDropZoneId,
2592
+ onValueChange: (value) => handleSelectChange(item.id, value),
2593
+ disabled: showCorrectAnswer,
2594
+ children: [
2595
+ /* @__PURE__ */ jsx(SelectTrigger, { id: `select-draggable-${item.id}`, className: "w-full sm:min-w-[200px]", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Ch\u1ECDn v\u1ECB tr\xED..." }) }),
2596
+ /* @__PURE__ */ jsx(SelectContent, { children: dropZones.map((zone) => /* @__PURE__ */ jsx(SelectItem, { value: zone.id, children: zone.label.replace(/<[^>]*>?/gm, "") }, zone.id)) })
2597
+ ]
2598
+ }
2599
+ ),
2600
+ showCorrectAnswer && selectedDropZoneId && (isSelectionCorrect ? /* @__PURE__ */ jsx(CheckCircle, { className: "h-5 w-5 text-green-500 flex-shrink-0" }) : /* @__PURE__ */ jsx(XCircle, { className: "h-5 w-5 text-destructive flex-shrink-0" }))
2601
+ ] })
2602
+ ] }, item.id);
2603
+ })
2604
+ ] }),
2605
+ showCorrectAnswer && explanation && /* @__PURE__ */ jsxs("div", { className: "mt-6 p-3 bg-accent/20 border border-accent rounded-md", children: [
2606
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Gi\u1EA3i th\xEDch:" }),
2607
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" })
2608
+ ] }),
2609
+ showCorrectAnswer && /* @__PURE__ */ jsxs("div", { className: "mt-4 space-y-2", children: [
2610
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-md", children: "\u0110\xE1p \xE1n \u0111\xFAng:" }),
2611
+ /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside space-y-1 text-sm", children: answerMap.map((map) => {
2612
+ const draggableText = draggableItems.find((d) => d.id === map.draggableId)?.content;
2613
+ const dropZoneText = dropZones.find((z3) => z3.id === map.dropZoneId)?.label;
2614
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: `<strong>${draggableText || "N/A"}</strong> v\xE0o <strong>${dropZoneText || "N/A"}</strong>` }) }, map.draggableId);
2615
+ }) })
2616
+ ] })
2617
+ ] })
2618
+ ] });
2499
2619
  };
2500
2620
  var HotspotQuestionUI = ({
2501
2621
  question,
@@ -2565,32 +2685,54 @@ var HotspotQuestionUI = ({
2565
2685
  tempDiv.innerHTML = htmlString;
2566
2686
  return tempDiv.textContent || tempDiv.innerText || "";
2567
2687
  };
2568
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: prompt })), points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0 space-y-4" }, /* @__PURE__ */ React28__default.createElement("div", { className: "relative w-full border border-muted rounded-md overflow-hidden", style: { maxWidth: "100%", maxHeight: "500px" } }, /* @__PURE__ */ React28__default.createElement(
2569
- "img",
2570
- {
2571
- src: imageUrl,
2572
- alt: imageAltText || "Hotspot image",
2573
- className: "block max-w-full max-h-full object-contain",
2574
- "data-ai-hint": question.imageAltText ? question.imageAltText.split(" ").slice(0, 2).join(" ") : "diagram illustration"
2575
- }
2576
- ), hotspots.map((hotspot) => /* @__PURE__ */ React28__default.createElement(
2577
- "div",
2578
- {
2579
- key: hotspot.id,
2580
- title: getPlainText(hotspot.description) || `Hotspot ${hotspot.id}`,
2581
- style: getHotspotStyle(hotspot),
2582
- onClick: () => handleHotspotClick(hotspot.id),
2583
- "aria-pressed": selectedIds.includes(hotspot.id),
2584
- role: "button",
2585
- tabIndex: showCorrectAnswer ? -1 : 0,
2586
- onKeyDown: (e) => {
2587
- if (e.key === "Enter" || e.key === " ") handleHotspotClick(hotspot.id);
2588
- }
2589
- }
2590
- ))), showCorrectAnswer && explanation && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Explanation:"), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" })), showCorrectAnswer && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 space-y-2" }, /* @__PURE__ */ React28__default.createElement("p", { className: "font-semibold text-md" }, "Correct Hotspots:"), /* @__PURE__ */ React28__default.createElement("ul", { className: "list-disc list-inside space-y-1 text-sm" }, (correctAnswerIds || []).map((id) => {
2591
- const hotspot = hotspots.find((h) => h.id === id);
2592
- return /* @__PURE__ */ React28__default.createElement("li", { key: id }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: (hotspot == null ? void 0 : hotspot.description) || (hotspot == null ? void 0 : hotspot.id) || "N/A", className: "inline" }));
2593
- })))));
2688
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
2689
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
2690
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: prompt }) }),
2691
+ points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
2692
+ "Points: ",
2693
+ points
2694
+ ] })
2695
+ ] }),
2696
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0 space-y-4", children: [
2697
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full border border-muted rounded-md overflow-hidden", style: { maxWidth: "100%", maxHeight: "500px" }, children: [
2698
+ /* @__PURE__ */ jsx(
2699
+ "img",
2700
+ {
2701
+ src: imageUrl,
2702
+ alt: imageAltText || "Hotspot image",
2703
+ className: "block max-w-full max-h-full object-contain",
2704
+ "data-ai-hint": question.imageAltText ? question.imageAltText.split(" ").slice(0, 2).join(" ") : "diagram illustration"
2705
+ }
2706
+ ),
2707
+ hotspots.map((hotspot) => /* @__PURE__ */ jsx(
2708
+ "div",
2709
+ {
2710
+ title: getPlainText(hotspot.description) || `Hotspot ${hotspot.id}`,
2711
+ style: getHotspotStyle(hotspot),
2712
+ onClick: () => handleHotspotClick(hotspot.id),
2713
+ "aria-pressed": selectedIds.includes(hotspot.id),
2714
+ role: "button",
2715
+ tabIndex: showCorrectAnswer ? -1 : 0,
2716
+ onKeyDown: (e) => {
2717
+ if (e.key === "Enter" || e.key === " ") handleHotspotClick(hotspot.id);
2718
+ }
2719
+ },
2720
+ hotspot.id
2721
+ ))
2722
+ ] }),
2723
+ showCorrectAnswer && explanation && /* @__PURE__ */ jsxs("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md", children: [
2724
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Explanation:" }),
2725
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: explanation, className: "text-sm text-accent-foreground/80" })
2726
+ ] }),
2727
+ showCorrectAnswer && /* @__PURE__ */ jsxs("div", { className: "mt-4 space-y-2", children: [
2728
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-md", children: "Correct Hotspots:" }),
2729
+ /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside space-y-1 text-sm", children: (correctAnswerIds || []).map((id) => {
2730
+ const hotspot = hotspots.find((h) => h.id === id);
2731
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: hotspot?.description || hotspot?.id || "N/A", className: "inline" }) }, id);
2732
+ }) })
2733
+ ] })
2734
+ ] })
2735
+ ] });
2594
2736
  };
2595
2737
  var loadScript = (src, async = true) => {
2596
2738
  return new Promise((resolve, reject) => {
@@ -2623,8 +2765,7 @@ var loadScript = (src, async = true) => {
2623
2765
  };
2624
2766
  var loadBlocklyScript = () => {
2625
2767
  return new Promise((resolve, reject) => {
2626
- var _a, _b;
2627
- if (typeof ((_a = window.Blockly) == null ? void 0 : _a.Blocks) !== "undefined" && typeof ((_b = window.Blockly) == null ? void 0 : _b.JavaScript) !== "undefined") {
2768
+ if (typeof window.Blockly?.Blocks !== "undefined" && typeof window.Blockly?.JavaScript !== "undefined") {
2628
2769
  resolve();
2629
2770
  return;
2630
2771
  }
@@ -2652,7 +2793,6 @@ var loadBlocklyScript = () => {
2652
2793
  }
2653
2794
  ];
2654
2795
  const tryLoadFromCDN = async (cdnIndex) => {
2655
- var _a2, _b2, _c;
2656
2796
  if (cdnIndex >= cdnOptions.length) {
2657
2797
  throw new Error("All Blockly CDN loading options failed");
2658
2798
  }
@@ -2661,9 +2801,9 @@ var loadBlocklyScript = () => {
2661
2801
  await loadScript(cdn.mainSrc);
2662
2802
  const BlocklyGlobal = window.Blockly;
2663
2803
  if (typeof BlocklyGlobal === "undefined") throw new Error(`Blockly global not found from ${cdn.name}.`);
2664
- if ((_b2 = (_a2 = BlocklyGlobal.utils) == null ? void 0 : _a2.global) == null ? void 0 : _b2.setPaths) {
2804
+ if (BlocklyGlobal.utils?.global?.setPaths) {
2665
2805
  BlocklyGlobal.utils.global.setPaths(cdn.mediaPath);
2666
- } else if ((_c = BlocklyGlobal.utils) == null ? void 0 : _c.global) {
2806
+ } else if (BlocklyGlobal.utils?.global) {
2667
2807
  BlocklyGlobal.utils.global.blocklyPath = cdn.mediaPath;
2668
2808
  BlocklyGlobal.MEDIA = cdn.mediaPath;
2669
2809
  } else {
@@ -2707,7 +2847,7 @@ var useBlocklyLoader = () => {
2707
2847
  }, []);
2708
2848
  return { isLoading, loadError, isReady, retry };
2709
2849
  };
2710
- var BlocklyProgrammingQuestionUI = React28__default.forwardRef(({
2850
+ var BlocklyProgrammingQuestionUI = React9__default.forwardRef(({
2711
2851
  question,
2712
2852
  userAnswer,
2713
2853
  showCorrectAnswer = false
@@ -2719,10 +2859,9 @@ var BlocklyProgrammingQuestionUI = React28__default.forwardRef(({
2719
2859
  const { isLoading: blocklyLoading, loadError: blocklyLoadError, isReady: blocklyReady, retry } = useBlocklyLoader();
2720
2860
  useImperativeHandle(ref, () => ({
2721
2861
  getWorkspaceXml: () => {
2722
- var _a, _b;
2723
2862
  if (workspaceRef.current && blocklyReady) {
2724
2863
  const LocalBlockly = window.Blockly;
2725
- if (!((_a = LocalBlockly == null ? void 0 : LocalBlockly.Xml) == null ? void 0 : _a.workspaceToDom) || !((_b = LocalBlockly == null ? void 0 : LocalBlockly.Xml) == null ? void 0 : _b.domToText)) {
2864
+ if (!LocalBlockly?.Xml?.workspaceToDom || !LocalBlockly?.Xml?.domToText) {
2726
2865
  console.warn("Blockly.Xml methods not available for XML serialization in getWorkspaceXml.");
2727
2866
  return null;
2728
2867
  }
@@ -2738,10 +2877,9 @@ var BlocklyProgrammingQuestionUI = React28__default.forwardRef(({
2738
2877
  }
2739
2878
  }));
2740
2879
  const initializeBlocklyWorkspace = useCallback(() => {
2741
- var _a;
2742
2880
  if (!blocklyReady || !blocklyDivRef.current) return;
2743
2881
  const LocalBlockly = window.Blockly;
2744
- if (!(LocalBlockly == null ? void 0 : LocalBlockly.inject) || !(LocalBlockly == null ? void 0 : LocalBlockly.Xml) || !(LocalBlockly == null ? void 0 : LocalBlockly.Events) || !(LocalBlockly == null ? void 0 : LocalBlockly.Themes)) {
2882
+ if (!LocalBlockly?.inject || !LocalBlockly?.Xml || !LocalBlockly?.Events || !LocalBlockly?.Themes) {
2745
2883
  setComponentError("Blockly library not fully loaded.");
2746
2884
  setIsInitializingComponent(false);
2747
2885
  return;
@@ -2773,7 +2911,7 @@ var BlocklyProgrammingQuestionUI = React28__default.forwardRef(({
2773
2911
  }
2774
2912
  }
2775
2913
  setIsInitializingComponent(true);
2776
- if ((_a = workspaceRef.current) == null ? void 0 : _a.dispose) {
2914
+ if (workspaceRef.current?.dispose) {
2777
2915
  try {
2778
2916
  workspaceRef.current.dispose();
2779
2917
  } catch (e) {
@@ -2850,8 +2988,7 @@ var BlocklyProgrammingQuestionUI = React28__default.forwardRef(({
2850
2988
  initializeBlocklyWorkspace();
2851
2989
  }
2852
2990
  return () => {
2853
- var _a;
2854
- if ((_a = workspaceRef.current) == null ? void 0 : _a.dispose) {
2991
+ if (workspaceRef.current?.dispose) {
2855
2992
  try {
2856
2993
  workspaceRef.current.dispose();
2857
2994
  } catch (disposeError) {
@@ -2868,7 +3005,7 @@ var BlocklyProgrammingQuestionUI = React28__default.forwardRef(({
2868
3005
  resizeTimeout = setTimeout(() => {
2869
3006
  if (workspaceRef.current && blocklyReady) {
2870
3007
  const LocalBlockly = window.Blockly;
2871
- if (LocalBlockly == null ? void 0 : LocalBlockly.svgResize) {
3008
+ if (LocalBlockly?.svgResize) {
2872
3009
  LocalBlockly.svgResize(workspaceRef.current);
2873
3010
  }
2874
3011
  }
@@ -2882,64 +3019,91 @@ var BlocklyProgrammingQuestionUI = React28__default.forwardRef(({
2882
3019
  }, [blocklyReady]);
2883
3020
  const workspaceHeight = showCorrectAnswer ? "300px" : "450px";
2884
3021
  const workspaceContainerId = `blockly-workspace-container-${question.id}`;
2885
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: question.prompt })), question.points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", question.points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0" }, blocklyLoading && /* @__PURE__ */ React28__default.createElement(
2886
- "div",
2887
- {
2888
- style: {
2889
- height: workspaceHeight,
2890
- width: "100%",
2891
- borderRadius: "0.375rem",
2892
- border: "1px solid hsl(var(--border))",
2893
- backgroundColor: "hsl(var(--background))"
2894
- },
2895
- className: "flex items-center justify-center"
2896
- },
2897
- /* @__PURE__ */ React28__default.createElement("div", { className: "text-center" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-muted-foreground animate-pulse mb-2" }, "Loading Blockly Environment..."), /* @__PURE__ */ React28__default.createElement("div", { className: "w-8 h-8 border-4 border-muted border-t-primary rounded-full animate-spin mx-auto" }))
2898
- ), blocklyLoadError && !blocklyLoading && /* @__PURE__ */ React28__default.createElement(
2899
- "div",
2900
- {
2901
- style: {
2902
- height: workspaceHeight,
2903
- width: "100%",
2904
- borderRadius: "0.375rem",
2905
- border: "1px solid hsl(var(--destructive))",
2906
- backgroundColor: "hsl(var(--card))"
2907
- },
2908
- className: "flex items-center justify-center p-4"
2909
- },
2910
- /* @__PURE__ */ React28__default.createElement("div", { className: "text-destructive text-center" }, /* @__PURE__ */ React28__default.createElement("p", { className: "font-semibold text-lg" }, "Failed to load Blockly"), /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm mt-2 mb-3" }, blocklyLoadError), /* @__PURE__ */ React28__default.createElement("div", { className: "space-x-2" }, /* @__PURE__ */ React28__default.createElement(
2911
- "button",
2912
- {
2913
- onClick: retry,
2914
- className: "px-4 py-2 bg-primary text-primary-foreground rounded hover:bg-primary/90 transition-colors text-sm"
2915
- },
2916
- "Try Again"
2917
- ), /* @__PURE__ */ React28__default.createElement(
2918
- "button",
2919
- {
2920
- onClick: () => window.location.reload(),
2921
- className: "px-4 py-2 bg-destructive text-destructive-foreground rounded hover:bg-destructive/90 transition-colors text-sm"
2922
- },
2923
- "Refresh Page"
2924
- )))
2925
- ), !blocklyLoading && !blocklyLoadError && /* @__PURE__ */ React28__default.createElement(
2926
- "div",
2927
- {
2928
- id: workspaceContainerId,
2929
- ref: blocklyDivRef,
2930
- style: {
2931
- height: workspaceHeight,
2932
- width: "100%",
2933
- borderRadius: "0.375rem",
2934
- border: `1px solid ${componentError ? "hsl(var(--destructive))" : "hsl(var(--border))"}`,
2935
- backgroundColor: "hsl(var(--card))",
2936
- position: "relative",
2937
- userSelect: "none",
2938
- overflow: "hidden"
2939
- },
2940
- "aria-label": `Blockly programming workspace for question: ${question.prompt}`
2941
- }
2942
- ), showCorrectAnswer && question.explanation && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Explanation:"), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: question.explanation, className: "text-sm text-accent-foreground/80" }))));
3022
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
3023
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
3024
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: question.prompt }) }),
3025
+ question.points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
3026
+ "Points: ",
3027
+ question.points
3028
+ ] })
3029
+ ] }),
3030
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0", children: [
3031
+ blocklyLoading && /* @__PURE__ */ jsx(
3032
+ "div",
3033
+ {
3034
+ style: {
3035
+ height: workspaceHeight,
3036
+ width: "100%",
3037
+ borderRadius: "0.375rem",
3038
+ border: "1px solid hsl(var(--border))",
3039
+ backgroundColor: "hsl(var(--background))"
3040
+ },
3041
+ className: "flex items-center justify-center",
3042
+ children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
3043
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground animate-pulse mb-2", children: "Loading Blockly Environment..." }),
3044
+ /* @__PURE__ */ jsx("div", { className: "w-8 h-8 border-4 border-muted border-t-primary rounded-full animate-spin mx-auto" })
3045
+ ] })
3046
+ }
3047
+ ),
3048
+ blocklyLoadError && !blocklyLoading && /* @__PURE__ */ jsx(
3049
+ "div",
3050
+ {
3051
+ style: {
3052
+ height: workspaceHeight,
3053
+ width: "100%",
3054
+ borderRadius: "0.375rem",
3055
+ border: "1px solid hsl(var(--destructive))",
3056
+ backgroundColor: "hsl(var(--card))"
3057
+ },
3058
+ className: "flex items-center justify-center p-4",
3059
+ children: /* @__PURE__ */ jsxs("div", { className: "text-destructive text-center", children: [
3060
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-lg", children: "Failed to load Blockly" }),
3061
+ /* @__PURE__ */ jsx("p", { className: "text-sm mt-2 mb-3", children: blocklyLoadError }),
3062
+ /* @__PURE__ */ jsxs("div", { className: "space-x-2", children: [
3063
+ /* @__PURE__ */ jsx(
3064
+ "button",
3065
+ {
3066
+ onClick: retry,
3067
+ className: "px-4 py-2 bg-primary text-primary-foreground rounded hover:bg-primary/90 transition-colors text-sm",
3068
+ children: "Try Again"
3069
+ }
3070
+ ),
3071
+ /* @__PURE__ */ jsx(
3072
+ "button",
3073
+ {
3074
+ onClick: () => window.location.reload(),
3075
+ className: "px-4 py-2 bg-destructive text-destructive-foreground rounded hover:bg-destructive/90 transition-colors text-sm",
3076
+ children: "Refresh Page"
3077
+ }
3078
+ )
3079
+ ] })
3080
+ ] })
3081
+ }
3082
+ ),
3083
+ !blocklyLoading && !blocklyLoadError && /* @__PURE__ */ jsx(
3084
+ "div",
3085
+ {
3086
+ id: workspaceContainerId,
3087
+ ref: blocklyDivRef,
3088
+ style: {
3089
+ height: workspaceHeight,
3090
+ width: "100%",
3091
+ borderRadius: "0.375rem",
3092
+ border: `1px solid ${componentError ? "hsl(var(--destructive))" : "hsl(var(--border))"}`,
3093
+ backgroundColor: "hsl(var(--card))",
3094
+ position: "relative",
3095
+ userSelect: "none",
3096
+ overflow: "hidden"
3097
+ },
3098
+ "aria-label": `Blockly programming workspace for question: ${question.prompt}`
3099
+ }
3100
+ ),
3101
+ showCorrectAnswer && question.explanation && /* @__PURE__ */ jsxs("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md", children: [
3102
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Explanation:" }),
3103
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: question.explanation, className: "text-sm text-accent-foreground/80" })
3104
+ ] })
3105
+ ] })
3106
+ ] });
2943
3107
  });
2944
3108
  BlocklyProgrammingQuestionUI.displayName = "BlocklyProgrammingQuestionUI";
2945
3109
  var SCRATCH_JS_ENGINE_LAYOUT_PATH = "/static/scratch-blocks/js/blockly_compressed_vertical.js";
@@ -3020,7 +3184,6 @@ var ScratchProgrammingQuestionUI = forwardRef(({
3020
3184
  const [componentError, setComponentError] = useState(null);
3021
3185
  const [isLoadingScripts, setIsLoadingScripts] = useState(true);
3022
3186
  const attemptLoadScripts = useCallback(async () => {
3023
- var _a, _b, _c, _d;
3024
3187
  setIsLoadingScripts(true);
3025
3188
  setComponentError(null);
3026
3189
  console.log("ScratchUI: Starting script loading sequence...");
@@ -3031,19 +3194,19 @@ var ScratchProgrammingQuestionUI = forwardRef(({
3031
3194
  if (typeof BlocklyGlobalEngine === "undefined") {
3032
3195
  throw new Error(`Blockly global object (window.Blockly) not found after loading engine script: ${SCRATCH_JS_ENGINE_LAYOUT_PATH}.`);
3033
3196
  }
3034
- console.log(`ScratchUI: After engine/layout load: Blockly defined: ${!!BlocklyGlobalEngine}, Blockly.Blocks defined: ${!!(BlocklyGlobalEngine == null ? void 0 : BlocklyGlobalEngine.Blocks)}, Blockly.Msg defined: ${!!(BlocklyGlobalEngine == null ? void 0 : BlocklyGlobalEngine.Msg)}, Blockly.ScratchMsgs defined: ${!!(BlocklyGlobalEngine == null ? void 0 : BlocklyGlobalEngine.ScratchMsgs)}`);
3197
+ console.log(`ScratchUI: After engine/layout load: Blockly defined: ${!!BlocklyGlobalEngine}, Blockly.Blocks defined: ${!!BlocklyGlobalEngine?.Blocks}, Blockly.Msg defined: ${!!BlocklyGlobalEngine?.Msg}, Blockly.ScratchMsgs defined: ${!!BlocklyGlobalEngine?.ScratchMsgs}`);
3035
3198
  console.log("ScratchUI: Attempting to load Messages:", SCRATCH_JS_MSG_EN_PATH);
3036
3199
  await loadScript2(SCRATCH_JS_MSG_EN_PATH);
3037
3200
  let BlocklyGlobalAfterMsg = window.Blockly;
3038
3201
  if (!BlocklyGlobalAfterMsg) throw new Error("Blockly global disappeared after loading message script.");
3039
- console.log(`ScratchUI: After en.js load: Blockly defined: ${!!BlocklyGlobalAfterMsg}, Blockly.Msg defined: ${!!(BlocklyGlobalAfterMsg == null ? void 0 : BlocklyGlobalAfterMsg.Msg)}, Keys in Blockly.Msg: ${(BlocklyGlobalAfterMsg == null ? void 0 : BlocklyGlobalAfterMsg.Msg) ? Object.keys(BlocklyGlobalAfterMsg.Msg).length : "N/A"}. Sample Blockly.Msg.LOGIC_HUE: ${(_a = BlocklyGlobalAfterMsg == null ? void 0 : BlocklyGlobalAfterMsg.Msg) == null ? void 0 : _a.LOGIC_HUE}`);
3202
+ console.log(`ScratchUI: After en.js load: Blockly defined: ${!!BlocklyGlobalAfterMsg}, Blockly.Msg defined: ${!!BlocklyGlobalAfterMsg?.Msg}, Keys in Blockly.Msg: ${BlocklyGlobalAfterMsg?.Msg ? Object.keys(BlocklyGlobalAfterMsg.Msg).length : "N/A"}. Sample Blockly.Msg.LOGIC_HUE: ${BlocklyGlobalAfterMsg?.Msg?.LOGIC_HUE}`);
3040
3203
  if (!BlocklyGlobalAfterMsg.Msg || Object.keys(BlocklyGlobalAfterMsg.Msg).length === 0) {
3041
3204
  console.warn("ScratchUI: Blockly.Msg appears unpopulated or empty. Checking if Blockly.ScratchMsgs.addLocaleData can be used...");
3042
3205
  if (BlocklyGlobalAfterMsg.ScratchMsgs && typeof BlocklyGlobalAfterMsg.ScratchMsgs.addLocaleData === "function") {
3043
3206
  console.log("ScratchUI: Blockly.ScratchMsgs.addLocaleData is available. Attempting to call Blockly.ScratchMsgs.addLocaleData('en').");
3044
3207
  BlocklyGlobalAfterMsg.ScratchMsgs.addLocaleData("en");
3045
3208
  BlocklyGlobalAfterMsg = window.Blockly;
3046
- console.log(`ScratchUI: After attempting addLocaleData('en'): Keys in Blockly.Msg: ${(BlocklyGlobalAfterMsg == null ? void 0 : BlocklyGlobalAfterMsg.Msg) ? Object.keys(BlocklyGlobalAfterMsg.Msg).length : "N/A"}. Sample Blockly.Msg.LOGIC_HUE: ${(_b = BlocklyGlobalAfterMsg == null ? void 0 : BlocklyGlobalAfterMsg.Msg) == null ? void 0 : _b.LOGIC_HUE}`);
3209
+ console.log(`ScratchUI: After attempting addLocaleData('en'): Keys in Blockly.Msg: ${BlocklyGlobalAfterMsg?.Msg ? Object.keys(BlocklyGlobalAfterMsg.Msg).length : "N/A"}. Sample Blockly.Msg.LOGIC_HUE: ${BlocklyGlobalAfterMsg?.Msg?.LOGIC_HUE}`);
3047
3210
  if (!BlocklyGlobalAfterMsg.Msg || Object.keys(BlocklyGlobalAfterMsg.Msg).length === 0) {
3048
3211
  throw new Error("Blockly.Msg still empty after calling addLocaleData. Message loading failed critically.");
3049
3212
  }
@@ -3057,8 +3220,8 @@ var ScratchProgrammingQuestionUI = forwardRef(({
3057
3220
  if (!BlocklyGlobalBlocks || !BlocklyGlobalBlocks.Blocks) {
3058
3221
  throw new Error(`Blockly.Blocks not defined after loading ${SCRATCH_JS_BLOCK_DEFINITIONS_PATH}.`);
3059
3222
  }
3060
- console.log(`ScratchUI: After block definitions load: Blockly.Blocks defined: ${!!BlocklyGlobalBlocks.Blocks}. Keys: ${BlocklyGlobalBlocks.Blocks ? Object.keys(BlocklyGlobalBlocks.Blocks).slice(0, 10).join(", ") + "..." : "N/A"}. Essential block motion_movesteps defined: ${!!((_c = BlocklyGlobalBlocks.Blocks) == null ? void 0 : _c.motion_movesteps)}`);
3061
- if (typeof ((_d = BlocklyGlobalBlocks.Blocks) == null ? void 0 : _d.motion_movesteps) === "undefined") {
3223
+ console.log(`ScratchUI: After block definitions load: Blockly.Blocks defined: ${!!BlocklyGlobalBlocks.Blocks}. Keys: ${BlocklyGlobalBlocks.Blocks ? Object.keys(BlocklyGlobalBlocks.Blocks).slice(0, 10).join(", ") + "..." : "N/A"}. Essential block motion_movesteps defined: ${!!BlocklyGlobalBlocks.Blocks?.motion_movesteps}`);
3224
+ if (typeof BlocklyGlobalBlocks.Blocks?.motion_movesteps === "undefined") {
3062
3225
  throw new Error(`Essential Scratch blocks (e.g., motion_movesteps) not found after loading block definitions. Available blocks: ${Object.keys(BlocklyGlobalBlocks.Blocks || {}).join(", ")}`);
3063
3226
  }
3064
3227
  setIsBlocklyReady(true);
@@ -3077,7 +3240,7 @@ var ScratchProgrammingQuestionUI = forwardRef(({
3077
3240
  useImperativeHandle(ref, () => ({
3078
3241
  getWorkspaceXml: () => {
3079
3242
  const LocalBlockly = window.Blockly;
3080
- if (workspaceRef.current && (LocalBlockly == null ? void 0 : LocalBlockly.Xml)) {
3243
+ if (workspaceRef.current && LocalBlockly?.Xml) {
3081
3244
  try {
3082
3245
  const xml = LocalBlockly.Xml.workspaceToDom(workspaceRef.current);
3083
3246
  return LocalBlockly.Xml.domToText(xml);
@@ -3090,7 +3253,6 @@ var ScratchProgrammingQuestionUI = forwardRef(({
3090
3253
  }
3091
3254
  }));
3092
3255
  const initializeWorkspace = useCallback(() => {
3093
- var _a, _b;
3094
3256
  const LocalBlockly = window.Blockly;
3095
3257
  if (!isBlocklyReady || !blocklyDivRef.current || !LocalBlockly) {
3096
3258
  console.warn("ScratchUI: Conditions not met for workspace initialization. isBlocklyReady:", isBlocklyReady, "blocklyDivRef.current:", !!blocklyDivRef.current, "LocalBlockly:", !!LocalBlockly);
@@ -3105,7 +3267,7 @@ var ScratchProgrammingQuestionUI = forwardRef(({
3105
3267
  console.error("ScratchUI: Blockly.Msg is empty or missing common keys before injection. Current Msg keys count:", Object.keys(LocalBlockly.Msg).length, "CATEGORY_MOTION:", LocalBlockly.Msg.CATEGORY_MOTION);
3106
3268
  return;
3107
3269
  }
3108
- if (typeof ((_a = LocalBlockly.Blocks) == null ? void 0 : _a.motion_movesteps) === "undefined" || typeof ((_b = LocalBlockly.Blocks) == null ? void 0 : _b.event_whenflagclicked) === "undefined") {
3270
+ if (typeof LocalBlockly.Blocks?.motion_movesteps === "undefined" || typeof LocalBlockly.Blocks?.event_whenflagclicked === "undefined") {
3109
3271
  const availableBlocks = Object.keys(LocalBlockly.Blocks || {}).join(", ");
3110
3272
  setComponentError(`ScratchUI: Essential Scratch block definitions (e.g., motion_movesteps, event_whenflagclicked) are missing before injection. Available blocks: ${availableBlocks}`);
3111
3273
  return;
@@ -3199,7 +3361,7 @@ var ScratchProgrammingQuestionUI = forwardRef(({
3199
3361
  }
3200
3362
  const handleResize = () => {
3201
3363
  const LocalBlocklyResize = window.Blockly;
3202
- if (workspaceRef.current && (LocalBlocklyResize == null ? void 0 : LocalBlocklyResize.svgResize)) {
3364
+ if (workspaceRef.current && LocalBlocklyResize?.svgResize) {
3203
3365
  LocalBlocklyResize.svgResize(workspaceRef.current);
3204
3366
  }
3205
3367
  };
@@ -3220,75 +3382,106 @@ var ScratchProgrammingQuestionUI = forwardRef(({
3220
3382
  }, [isBlocklyReady, initializeWorkspace]);
3221
3383
  const workspaceHeight = showCorrectAnswer ? "300px" : "450px";
3222
3384
  if (isLoadingScripts) {
3223
- return /* @__PURE__ */ React28__default.createElement("div", { style: { height: workspaceHeight, width: "100%", display: "flex", alignItems: "center", justifyContent: "center", border: "1px solid hsl(var(--border))", borderRadius: "0.375rem", backgroundColor: "hsl(var(--background))" } }, /* @__PURE__ */ React28__default.createElement("div", { className: "text-center" }, /* @__PURE__ */ React28__default.createElement("div", { className: "w-8 h-8 border-4 border-muted border-t-primary rounded-full animate-spin mx-auto mb-2" }), /* @__PURE__ */ React28__default.createElement("p", { className: "text-muted-foreground" }, "Loading Scratch Assets...")));
3385
+ return /* @__PURE__ */ jsx("div", { style: { height: workspaceHeight, width: "100%", display: "flex", alignItems: "center", justifyContent: "center", border: "1px solid hsl(var(--border))", borderRadius: "0.375rem", backgroundColor: "hsl(var(--background))" }, children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
3386
+ /* @__PURE__ */ jsx("div", { className: "w-8 h-8 border-4 border-muted border-t-primary rounded-full animate-spin mx-auto mb-2" }),
3387
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Loading Scratch Assets..." })
3388
+ ] }) });
3224
3389
  }
3225
3390
  if (componentError) {
3226
- return /* @__PURE__ */ React28__default.createElement("div", { style: { height: workspaceHeight, width: "100%", color: "hsl(var(--destructive))", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", border: "1px solid hsl(var(--destructive))", borderRadius: "0.375rem", padding: "1rem", backgroundColor: "hsl(var(--card))" } }, /* @__PURE__ */ React28__default.createElement("p", { className: "font-semibold text-lg mb-2" }, "Failed to load Scratch Workspace."), /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm text-muted-foreground mb-3 text-center" }, componentError), /* @__PURE__ */ React28__default.createElement("p", { className: "text-xs text-muted-foreground mb-4 text-center" }, "Please ensure all Scratch/Blockly JavaScript files are correctly copied to your", /* @__PURE__ */ React28__default.createElement("code", null, "public/static/scratch-blocks/js"), " directory. Check browser console for more details.", /* @__PURE__ */ React28__default.createElement("br", null), /* @__PURE__ */ React28__default.createElement("strong", null, "CRITICAL: Ensure you have copied the CSS files from ", /* @__PURE__ */ React28__default.createElement("code", null, "node_modules/scratch-blocks/css/"), " (e.g., ", /* @__PURE__ */ React28__default.createElement("code", null, "vertical.css"), ") to ", /* @__PURE__ */ React28__default.createElement("code", null, "public/static/scratch-blocks/css/"), " and linked it in your main layout. Without CSS, blocks will not render correctly.")), /* @__PURE__ */ React28__default.createElement(Button, { onClick: attemptLoadScripts, variant: "outline" }, "Try Reloading Scripts"));
3391
+ return /* @__PURE__ */ jsxs("div", { style: { height: workspaceHeight, width: "100%", color: "hsl(var(--destructive))", display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", border: "1px solid hsl(var(--destructive))", borderRadius: "0.375rem", padding: "1rem", backgroundColor: "hsl(var(--card))" }, children: [
3392
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-lg mb-2", children: "Failed to load Scratch Workspace." }),
3393
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-3 text-center", children: componentError }),
3394
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground mb-4 text-center", children: [
3395
+ "Please ensure all Scratch/Blockly JavaScript files are correctly copied to your",
3396
+ /* @__PURE__ */ jsx("code", { children: "public/static/scratch-blocks/js" }),
3397
+ " directory. Check browser console for more details.",
3398
+ /* @__PURE__ */ jsx("br", {}),
3399
+ /* @__PURE__ */ jsxs("strong", { children: [
3400
+ "CRITICAL: Ensure you have copied the CSS files from ",
3401
+ /* @__PURE__ */ jsx("code", { children: "node_modules/scratch-blocks/css/" }),
3402
+ " (e.g., ",
3403
+ /* @__PURE__ */ jsx("code", { children: "vertical.css" }),
3404
+ ") to ",
3405
+ /* @__PURE__ */ jsx("code", { children: "public/static/scratch-blocks/css/" }),
3406
+ " and linked it in your main layout. Without CSS, blocks will not render correctly."
3407
+ ] })
3408
+ ] }),
3409
+ /* @__PURE__ */ jsx(Button, { onClick: attemptLoadScripts, variant: "outline", children: "Try Reloading Scripts" })
3410
+ ] });
3227
3411
  }
3228
3412
  if (!isBlocklyReady && !isLoadingScripts) {
3229
- return /* @__PURE__ */ React28__default.createElement("div", { style: { height: workspaceHeight, width: "100%", display: "flex", alignItems: "center", justifyContent: "center", border: "1px solid hsl(var(--border))", borderRadius: "0.375rem", backgroundColor: "hsl(var(--background))" } }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-muted-foreground" }, "Scratch environment did not initialize (Blockly not ready). Check console for script loading errors."));
3413
+ return /* @__PURE__ */ jsx("div", { style: { height: workspaceHeight, width: "100%", display: "flex", alignItems: "center", justifyContent: "center", border: "1px solid hsl(var(--border))", borderRadius: "0.375rem", backgroundColor: "hsl(var(--background))" }, children: /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Scratch environment did not initialize (Blockly not ready). Check console for script loading errors." }) });
3230
3414
  }
3231
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, question.prompt), question.points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", question.points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0" }, /* @__PURE__ */ React28__default.createElement(
3232
- "div",
3233
- {
3234
- ref: blocklyDivRef,
3235
- style: {
3236
- height: workspaceHeight,
3237
- width: "100%",
3238
- borderRadius: "0.375rem",
3239
- backgroundColor: "hsl(var(--card))",
3240
- position: "relative",
3241
- userSelect: "none",
3242
- overflow: "hidden",
3243
- display: isLoadingScripts || componentError || !isBlocklyReady ? "none" : "block"
3244
- },
3245
- "aria-label": `Scratch programming workspace for question: ${question.prompt}`
3246
- }
3247
- ), showCorrectAnswer && question.explanation && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Explanation:"), /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm text-accent-foreground/80" }, question.explanation))));
3415
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
3416
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
3417
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: question.prompt }),
3418
+ question.points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
3419
+ "Points: ",
3420
+ question.points
3421
+ ] })
3422
+ ] }),
3423
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0", children: [
3424
+ /* @__PURE__ */ jsx(
3425
+ "div",
3426
+ {
3427
+ ref: blocklyDivRef,
3428
+ style: {
3429
+ height: workspaceHeight,
3430
+ width: "100%",
3431
+ borderRadius: "0.375rem",
3432
+ backgroundColor: "hsl(var(--card))",
3433
+ position: "relative",
3434
+ userSelect: "none",
3435
+ overflow: "hidden",
3436
+ display: isLoadingScripts || componentError || !isBlocklyReady ? "none" : "block"
3437
+ },
3438
+ "aria-label": `Scratch programming workspace for question: ${question.prompt}`
3439
+ }
3440
+ ),
3441
+ showCorrectAnswer && question.explanation && /* @__PURE__ */ jsxs("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md", children: [
3442
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Explanation:" }),
3443
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-accent-foreground/80", children: question.explanation })
3444
+ ] })
3445
+ ] })
3446
+ ] });
3248
3447
  });
3249
3448
  ScratchProgrammingQuestionUI.displayName = "ScratchProgrammingQuestionUI";
3250
3449
  var Tabs = TabsPrimitive.Root;
3251
- var TabsList = React28.forwardRef((_a, ref) => {
3252
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
3253
- return /* @__PURE__ */ React28.createElement(
3254
- TabsPrimitive.List,
3255
- __spreadValues({
3256
- ref,
3257
- className: cn(
3258
- "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
3259
- className
3260
- )
3261
- }, props)
3262
- );
3263
- });
3450
+ var TabsList = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3451
+ TabsPrimitive.List,
3452
+ {
3453
+ ref,
3454
+ className: cn(
3455
+ "inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
3456
+ className
3457
+ ),
3458
+ ...props
3459
+ }
3460
+ ));
3264
3461
  TabsList.displayName = TabsPrimitive.List.displayName;
3265
- var TabsTrigger = React28.forwardRef((_a, ref) => {
3266
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
3267
- return /* @__PURE__ */ React28.createElement(
3268
- TabsPrimitive.Trigger,
3269
- __spreadValues({
3270
- ref,
3271
- className: cn(
3272
- "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
3273
- className
3274
- )
3275
- }, props)
3276
- );
3277
- });
3462
+ var TabsTrigger = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3463
+ TabsPrimitive.Trigger,
3464
+ {
3465
+ ref,
3466
+ className: cn(
3467
+ "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
3468
+ className
3469
+ ),
3470
+ ...props
3471
+ }
3472
+ ));
3278
3473
  TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
3279
- var TabsContent = React28.forwardRef((_a, ref) => {
3280
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
3281
- return /* @__PURE__ */ React28.createElement(
3282
- TabsPrimitive.Content,
3283
- __spreadValues({
3284
- ref,
3285
- className: cn(
3286
- "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
3287
- className
3288
- )
3289
- }, props)
3290
- );
3291
- });
3474
+ var TabsContent = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3475
+ TabsPrimitive.Content,
3476
+ {
3477
+ ref,
3478
+ className: cn(
3479
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
3480
+ className
3481
+ ),
3482
+ ...props
3483
+ }
3484
+ ));
3292
3485
  TabsContent.displayName = TabsPrimitive.Content.displayName;
3293
3486
  var TOAST_LIMIT = 1;
3294
3487
  var TOAST_REMOVE_DELAY = 1e6;
@@ -3314,15 +3507,17 @@ var addToRemoveQueue = (toastId) => {
3314
3507
  var reducer = (state, action) => {
3315
3508
  switch (action.type) {
3316
3509
  case "ADD_TOAST":
3317
- return __spreadProps(__spreadValues({}, state), {
3510
+ return {
3511
+ ...state,
3318
3512
  toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT)
3319
- });
3513
+ };
3320
3514
  case "UPDATE_TOAST":
3321
- return __spreadProps(__spreadValues({}, state), {
3515
+ return {
3516
+ ...state,
3322
3517
  toasts: state.toasts.map(
3323
- (t) => t.id === action.toast.id ? __spreadValues(__spreadValues({}, t), action.toast) : t
3518
+ (t) => t.id === action.toast.id ? { ...t, ...action.toast } : t
3324
3519
  )
3325
- });
3520
+ };
3326
3521
  case "DISMISS_TOAST": {
3327
3522
  const { toastId } = action;
3328
3523
  if (toastId) {
@@ -3332,23 +3527,27 @@ var reducer = (state, action) => {
3332
3527
  addToRemoveQueue(toast2.id);
3333
3528
  });
3334
3529
  }
3335
- return __spreadProps(__spreadValues({}, state), {
3530
+ return {
3531
+ ...state,
3336
3532
  toasts: state.toasts.map(
3337
- (t) => t.id === toastId || toastId === void 0 ? __spreadProps(__spreadValues({}, t), {
3533
+ (t) => t.id === toastId || toastId === void 0 ? {
3534
+ ...t,
3338
3535
  open: false
3339
- }) : t
3536
+ } : t
3340
3537
  )
3341
- });
3538
+ };
3342
3539
  }
3343
3540
  case "REMOVE_TOAST":
3344
3541
  if (action.toastId === void 0) {
3345
- return __spreadProps(__spreadValues({}, state), {
3542
+ return {
3543
+ ...state,
3346
3544
  toasts: []
3347
- });
3545
+ };
3348
3546
  }
3349
- return __spreadProps(__spreadValues({}, state), {
3547
+ return {
3548
+ ...state,
3350
3549
  toasts: state.toasts.filter((t) => t.id !== action.toastId)
3351
- });
3550
+ };
3352
3551
  }
3353
3552
  };
3354
3553
  var listeners = [];
@@ -3359,23 +3558,23 @@ function dispatch(action) {
3359
3558
  listener(memoryState);
3360
3559
  });
3361
3560
  }
3362
- function toast(_a) {
3363
- var props = __objRest(_a, []);
3561
+ function toast({ ...props }) {
3364
3562
  const id = genId();
3365
3563
  const update = (props2) => dispatch({
3366
3564
  type: "UPDATE_TOAST",
3367
- toast: __spreadProps(__spreadValues({}, props2), { id })
3565
+ toast: { ...props2, id }
3368
3566
  });
3369
3567
  const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
3370
3568
  dispatch({
3371
3569
  type: "ADD_TOAST",
3372
- toast: __spreadProps(__spreadValues({}, props), {
3570
+ toast: {
3571
+ ...props,
3373
3572
  id,
3374
3573
  open: true,
3375
3574
  onOpenChange: (open) => {
3376
3575
  if (!open) dismiss();
3377
3576
  }
3378
- })
3577
+ }
3379
3578
  });
3380
3579
  return {
3381
3580
  id,
@@ -3384,8 +3583,8 @@ function toast(_a) {
3384
3583
  };
3385
3584
  }
3386
3585
  function useToast() {
3387
- const [state, setState] = React28.useState(memoryState);
3388
- React28.useEffect(() => {
3586
+ const [state, setState] = React9.useState(memoryState);
3587
+ React9.useEffect(() => {
3389
3588
  listeners.push(setState);
3390
3589
  return () => {
3391
3590
  const index = listeners.indexOf(setState);
@@ -3394,13 +3593,12 @@ function useToast() {
3394
3593
  }
3395
3594
  };
3396
3595
  }, [state]);
3397
- return __spreadProps(__spreadValues({}, state), {
3596
+ return {
3597
+ ...state,
3398
3598
  toast,
3399
3599
  dismiss: (toastId) => dispatch({ type: "DISMISS_TOAST", toastId })
3400
- });
3600
+ };
3401
3601
  }
3402
-
3403
- // src/react-ui/components/ui/CodingQuestionUI.tsx
3404
3602
  var languageMap = {
3405
3603
  cpp: cpp(),
3406
3604
  javascript: javascript({ typescript: true }),
@@ -3447,28 +3645,67 @@ var CodingQuestionUI = ({
3447
3645
  }
3448
3646
  };
3449
3647
  const langExtension = languageMap[question.codingLanguage];
3450
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full border-none shadow-none" }, /* @__PURE__ */ React28__default.createElement(CardHeader, { className: "p-0 pb-4" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl mb-1 font-body" }, /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: question.prompt })), question.points && /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-sm text-muted-foreground" }, "Points: ", question.points)), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "p-0 space-y-4" }, /* @__PURE__ */ React28__default.createElement("div", { className: "font-mono text-sm border rounded-md overflow-hidden" }, /* @__PURE__ */ React28__default.createElement(
3451
- CodeMirror,
3452
- {
3453
- value: code,
3454
- height: "300px",
3455
- extensions: [langExtension],
3456
- onChange: handleCodeChange,
3457
- readOnly: showCorrectAnswer,
3458
- theme: "dark"
3459
- }
3460
- )), !showCorrectAnswer && /* @__PURE__ */ React28__default.createElement(Button, { onClick: handleRunPublicTests, disabled: isRunningTests }, isRunningTests ? /* @__PURE__ */ React28__default.createElement(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React28__default.createElement(Play, { className: "mr-2 h-4 w-4" }), isRunningTests ? "Running..." : "Run Public Tests"), /* @__PURE__ */ React28__default.createElement(Tabs, { defaultValue: "tests", className: "w-full" }, /* @__PURE__ */ React28__default.createElement(TabsList, null, /* @__PURE__ */ React28__default.createElement(TabsTrigger, { value: "tests" }, "Test Cases"), showCorrectAnswer && /* @__PURE__ */ React28__default.createElement(TabsTrigger, { value: "solution" }, "Solution")), /* @__PURE__ */ React28__default.createElement(TabsContent, { value: "tests" }, /* @__PURE__ */ React28__default.createElement("div", { className: "space-y-2 p-2 border rounded-md min-h-[100px]" }, testResults.length > 0 ? testResults.map((result, index) => /* @__PURE__ */ React28__default.createElement("div", { key: result.testCaseId, className: "flex items-center text-sm" }, result.passed ? /* @__PURE__ */ React28__default.createElement(CheckCircle, { className: "h-4 w-4 text-green-500 mr-2" }) : /* @__PURE__ */ React28__default.createElement(XCircle, { className: "h-4 w-4 text-destructive mr-2" }), /* @__PURE__ */ React28__default.createElement("span", null, "Test Case #", index + 1, ": ", result.passed ? "Passed" : "Failed"), !result.passed && /* @__PURE__ */ React28__default.createElement("p", { className: "text-xs text-muted-foreground ml-2" }, "- ", result.reasoning))) : /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm text-muted-foreground" }, showCorrectAnswer ? "Final results are shown in the quiz summary." : "Click 'Run Public Tests' to see results."))), showCorrectAnswer && /* @__PURE__ */ React28__default.createElement(TabsContent, { value: "solution" }, /* @__PURE__ */ React28__default.createElement("div", { className: "font-mono text-sm border rounded-md overflow-hidden" }, /* @__PURE__ */ React28__default.createElement(
3461
- CodeMirror,
3462
- {
3463
- value: question.solutionCode,
3464
- height: "300px",
3465
- extensions: [langExtension],
3466
- readOnly: true,
3467
- theme: "dark"
3468
- }
3469
- )))), showCorrectAnswer && question.explanation && /* @__PURE__ */ React28__default.createElement("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm font-semibold text-accent-foreground" }, "Explanation:"), /* @__PURE__ */ React28__default.createElement(MarkdownRenderer, { content: question.explanation, className: "text-sm text-accent-foreground/80" }))));
3648
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full border-none shadow-none", children: [
3649
+ /* @__PURE__ */ jsxs(CardHeader, { className: "p-0 pb-4", children: [
3650
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xl mb-1 font-body", children: /* @__PURE__ */ jsx(MarkdownRenderer, { content: question.prompt }) }),
3651
+ question.points && /* @__PURE__ */ jsxs(CardDescription, { className: "text-sm text-muted-foreground", children: [
3652
+ "Points: ",
3653
+ question.points
3654
+ ] })
3655
+ ] }),
3656
+ /* @__PURE__ */ jsxs(CardContent, { className: "p-0 space-y-4", children: [
3657
+ /* @__PURE__ */ jsx("div", { className: "font-mono text-sm border rounded-md overflow-hidden", children: /* @__PURE__ */ jsx(
3658
+ CodeMirror,
3659
+ {
3660
+ value: code,
3661
+ height: "300px",
3662
+ extensions: [langExtension],
3663
+ onChange: handleCodeChange,
3664
+ readOnly: showCorrectAnswer,
3665
+ theme: "dark"
3666
+ }
3667
+ ) }),
3668
+ !showCorrectAnswer && /* @__PURE__ */ jsxs(Button, { onClick: handleRunPublicTests, disabled: isRunningTests, children: [
3669
+ isRunningTests ? /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Play, { className: "mr-2 h-4 w-4" }),
3670
+ isRunningTests ? "Running..." : "Run Public Tests"
3671
+ ] }),
3672
+ /* @__PURE__ */ jsxs(Tabs, { defaultValue: "tests", className: "w-full", children: [
3673
+ /* @__PURE__ */ jsxs(TabsList, { children: [
3674
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "tests", children: "Test Cases" }),
3675
+ showCorrectAnswer && /* @__PURE__ */ jsx(TabsTrigger, { value: "solution", children: "Solution" })
3676
+ ] }),
3677
+ /* @__PURE__ */ jsx(TabsContent, { value: "tests", children: /* @__PURE__ */ jsx("div", { className: "space-y-2 p-2 border rounded-md min-h-[100px]", children: testResults.length > 0 ? testResults.map((result, index) => /* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm", children: [
3678
+ result.passed ? /* @__PURE__ */ jsx(CheckCircle, { className: "h-4 w-4 text-green-500 mr-2" }) : /* @__PURE__ */ jsx(XCircle, { className: "h-4 w-4 text-destructive mr-2" }),
3679
+ /* @__PURE__ */ jsxs("span", { children: [
3680
+ "Test Case #",
3681
+ index + 1,
3682
+ ": ",
3683
+ result.passed ? "Passed" : "Failed"
3684
+ ] }),
3685
+ !result.passed && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground ml-2", children: [
3686
+ "- ",
3687
+ result.reasoning
3688
+ ] })
3689
+ ] }, result.testCaseId)) : /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: showCorrectAnswer ? "Final results are shown in the quiz summary." : "Click 'Run Public Tests' to see results." }) }) }),
3690
+ showCorrectAnswer && /* @__PURE__ */ jsx(TabsContent, { value: "solution", children: /* @__PURE__ */ jsx("div", { className: "font-mono text-sm border rounded-md overflow-hidden", children: /* @__PURE__ */ jsx(
3691
+ CodeMirror,
3692
+ {
3693
+ value: question.solutionCode,
3694
+ height: "300px",
3695
+ extensions: [langExtension],
3696
+ readOnly: true,
3697
+ theme: "dark"
3698
+ }
3699
+ ) }) })
3700
+ ] }),
3701
+ showCorrectAnswer && question.explanation && /* @__PURE__ */ jsxs("div", { className: "mt-4 p-3 bg-accent/20 border border-accent rounded-md", children: [
3702
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-accent-foreground", children: "Explanation:" }),
3703
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: question.explanation, className: "text-sm text-accent-foreground/80" })
3704
+ ] })
3705
+ ] })
3706
+ ] });
3470
3707
  };
3471
- var QuestionRenderer = React28__default.forwardRef(({
3708
+ var QuestionRenderer = React9__default.forwardRef(({
3472
3709
  question,
3473
3710
  onAnswerChange,
3474
3711
  userAnswer,
@@ -3483,131 +3720,125 @@ var QuestionRenderer = React28__default.forwardRef(({
3483
3720
  };
3484
3721
  switch (question.questionType) {
3485
3722
  case "multiple_choice":
3486
- return /* @__PURE__ */ React28__default.createElement(MultipleChoiceQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question }));
3723
+ return /* @__PURE__ */ jsx(MultipleChoiceQuestionUI, { ...commonProps, question });
3487
3724
  case "true_false":
3488
- return /* @__PURE__ */ React28__default.createElement(TrueFalseQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question }));
3725
+ return /* @__PURE__ */ jsx(TrueFalseQuestionUI, { ...commonProps, question });
3489
3726
  case "multiple_response":
3490
- return /* @__PURE__ */ React28__default.createElement(MultipleResponseQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question }));
3727
+ return /* @__PURE__ */ jsx(MultipleResponseQuestionUI, { ...commonProps, question });
3491
3728
  case "short_answer":
3492
- return /* @__PURE__ */ React28__default.createElement(ShortAnswerQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question }));
3729
+ return /* @__PURE__ */ jsx(ShortAnswerQuestionUI, { ...commonProps, question });
3493
3730
  case "numeric":
3494
- return /* @__PURE__ */ React28__default.createElement(NumericQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question }));
3731
+ return /* @__PURE__ */ jsx(NumericQuestionUI, { ...commonProps, question });
3495
3732
  case "fill_in_the_blanks":
3496
- return /* @__PURE__ */ React28__default.createElement(FillInTheBlanksQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question }));
3733
+ return /* @__PURE__ */ jsx(FillInTheBlanksQuestionUI, { ...commonProps, question });
3497
3734
  case "sequence":
3498
- return /* @__PURE__ */ React28__default.createElement(SequenceQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question }));
3735
+ return /* @__PURE__ */ jsx(SequenceQuestionUI, { ...commonProps, question });
3499
3736
  case "matching":
3500
- return /* @__PURE__ */ React28__default.createElement(MatchingQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question }));
3737
+ return /* @__PURE__ */ jsx(MatchingQuestionUI, { ...commonProps, question });
3501
3738
  case "drag_and_drop":
3502
- return /* @__PURE__ */ React28__default.createElement(DragAndDropQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question }));
3739
+ return /* @__PURE__ */ jsx(DragAndDropQuestionUI, { ...commonProps, question });
3503
3740
  case "hotspot":
3504
- return /* @__PURE__ */ React28__default.createElement(HotspotQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question }));
3741
+ return /* @__PURE__ */ jsx(HotspotQuestionUI, { ...commonProps, question });
3505
3742
  case "blockly_programming":
3506
- return /* @__PURE__ */ React28__default.createElement(BlocklyProgrammingQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question, ref }));
3743
+ return /* @__PURE__ */ jsx(BlocklyProgrammingQuestionUI, { ...commonProps, question, ref });
3507
3744
  case "scratch_programming":
3508
- return /* @__PURE__ */ React28__default.createElement(ScratchProgrammingQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question, ref }));
3745
+ return /* @__PURE__ */ jsx(ScratchProgrammingQuestionUI, { ...commonProps, question, ref });
3509
3746
  case "coding":
3510
- return /* @__PURE__ */ React28__default.createElement(CodingQuestionUI, __spreadProps(__spreadValues({}, commonProps), { question }));
3747
+ return /* @__PURE__ */ jsx(CodingQuestionUI, { ...commonProps, question });
3511
3748
  default:
3512
- return /* @__PURE__ */ React28__default.createElement("div", { className: "p-4 border border-destructive bg-destructive/10 rounded-md" }, /* @__PURE__ */ React28__default.createElement("p", { className: "font-semibold text-destructive" }, t("unsupportedQuestionType")), /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm text-muted-foreground" }, t("unsupportedQuestionTypeDescription")), /* @__PURE__ */ React28__default.createElement("pre", { className: "mt-2 p-2 bg-muted rounded text-xs font-code overflow-x-auto" }, JSON.stringify(question, null, 2)));
3749
+ return /* @__PURE__ */ jsxs("div", { className: "p-4 border border-destructive bg-destructive/10 rounded-md", children: [
3750
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-destructive", children: t("unsupportedQuestionType") }),
3751
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("unsupportedQuestionTypeDescription") }),
3752
+ /* @__PURE__ */ jsx("pre", { className: "mt-2 p-2 bg-muted rounded text-xs font-code overflow-x-auto", children: JSON.stringify(question, null, 2) })
3753
+ ] });
3513
3754
  }
3514
3755
  });
3515
3756
  QuestionRenderer.displayName = "QuestionRenderer";
3516
- var Progress = React28.forwardRef((_a, ref) => {
3517
- var _b = _a, { className, value } = _b, props = __objRest(_b, ["className", "value"]);
3518
- return /* @__PURE__ */ React28.createElement(
3519
- ProgressPrimitive.Root,
3520
- __spreadValues({
3521
- ref,
3522
- className: cn(
3523
- "relative h-4 w-full overflow-hidden rounded-full bg-secondary",
3524
- className
3525
- )
3526
- }, props),
3527
- /* @__PURE__ */ React28.createElement(
3757
+ var Progress = React9.forwardRef(({ className, value, ...props }, ref) => /* @__PURE__ */ jsx(
3758
+ ProgressPrimitive.Root,
3759
+ {
3760
+ ref,
3761
+ className: cn(
3762
+ "relative h-4 w-full overflow-hidden rounded-full bg-secondary",
3763
+ className
3764
+ ),
3765
+ ...props,
3766
+ children: /* @__PURE__ */ jsx(
3528
3767
  ProgressPrimitive.Indicator,
3529
3768
  {
3530
3769
  className: "h-full w-full flex-1 bg-primary transition-all",
3531
3770
  style: { transform: `translateX(-${100 - (value || 0)}%)` }
3532
3771
  }
3533
3772
  )
3534
- );
3535
- });
3773
+ }
3774
+ ));
3536
3775
  Progress.displayName = ProgressPrimitive.Root.displayName;
3537
3776
  var Accordion = AccordionPrimitive.Root;
3538
- var AccordionItem = React28.forwardRef((_a, ref) => {
3539
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
3540
- return /* @__PURE__ */ React28.createElement(
3541
- AccordionPrimitive.Item,
3542
- __spreadValues({
3543
- ref,
3544
- className: cn("border-b", className)
3545
- }, props)
3546
- );
3547
- });
3777
+ var AccordionItem = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3778
+ AccordionPrimitive.Item,
3779
+ {
3780
+ ref,
3781
+ className: cn("border-b", className),
3782
+ ...props
3783
+ }
3784
+ ));
3548
3785
  AccordionItem.displayName = "AccordionItem";
3549
- var AccordionTrigger = React28.forwardRef((_a, ref) => {
3550
- var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
3551
- return /* @__PURE__ */ React28.createElement(AccordionPrimitive.Header, { className: "flex" }, /* @__PURE__ */ React28.createElement(
3552
- AccordionPrimitive.Trigger,
3553
- __spreadValues({
3554
- ref,
3555
- className: cn(
3556
- "flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
3557
- className
3558
- )
3559
- }, props),
3560
- children,
3561
- /* @__PURE__ */ React28.createElement(ChevronDown, { className: "h-4 w-4 shrink-0 transition-transform duration-200" })
3562
- ));
3563
- });
3786
+ var AccordionTrigger = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(AccordionPrimitive.Header, { className: "flex", children: /* @__PURE__ */ jsxs(
3787
+ AccordionPrimitive.Trigger,
3788
+ {
3789
+ ref,
3790
+ className: cn(
3791
+ "flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
3792
+ className
3793
+ ),
3794
+ ...props,
3795
+ children: [
3796
+ children,
3797
+ /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 shrink-0 transition-transform duration-200" })
3798
+ ]
3799
+ }
3800
+ ) }));
3564
3801
  AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
3565
- var AccordionContent = React28.forwardRef((_a, ref) => {
3566
- var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
3567
- return /* @__PURE__ */ React28.createElement(
3568
- AccordionPrimitive.Content,
3569
- __spreadValues({
3570
- ref,
3571
- className: "overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
3572
- }, props),
3573
- /* @__PURE__ */ React28.createElement("div", { className: cn("pb-4 pt-0", className) }, children)
3574
- );
3575
- });
3802
+ var AccordionContent = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(
3803
+ AccordionPrimitive.Content,
3804
+ {
3805
+ ref,
3806
+ className: "overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",
3807
+ ...props,
3808
+ children: /* @__PURE__ */ jsx("div", { className: cn("pb-4 pt-0", className), children })
3809
+ }
3810
+ ));
3576
3811
  AccordionContent.displayName = AccordionPrimitive.Content.displayName;
3577
- var ScrollArea = React28.forwardRef((_a, ref) => {
3578
- var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
3579
- return /* @__PURE__ */ React28.createElement(
3580
- ScrollAreaPrimitive.Root,
3581
- __spreadValues({
3582
- ref,
3583
- className: cn("relative overflow-hidden", className)
3584
- }, props),
3585
- /* @__PURE__ */ React28.createElement(ScrollAreaPrimitive.Viewport, { className: "h-full w-full rounded-[inherit]" }, children),
3586
- /* @__PURE__ */ React28.createElement(ScrollBar, null),
3587
- /* @__PURE__ */ React28.createElement(ScrollAreaPrimitive.Corner, null)
3588
- );
3589
- });
3812
+ var ScrollArea = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
3813
+ ScrollAreaPrimitive.Root,
3814
+ {
3815
+ ref,
3816
+ className: cn("relative overflow-hidden", className),
3817
+ ...props,
3818
+ children: [
3819
+ /* @__PURE__ */ jsx(ScrollAreaPrimitive.Viewport, { className: "h-full w-full rounded-[inherit]", children }),
3820
+ /* @__PURE__ */ jsx(ScrollBar, {}),
3821
+ /* @__PURE__ */ jsx(ScrollAreaPrimitive.Corner, {})
3822
+ ]
3823
+ }
3824
+ ));
3590
3825
  ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
3591
- var ScrollBar = React28.forwardRef((_a, ref) => {
3592
- var _b = _a, { className, orientation = "vertical" } = _b, props = __objRest(_b, ["className", "orientation"]);
3593
- return /* @__PURE__ */ React28.createElement(
3594
- ScrollAreaPrimitive.ScrollAreaScrollbar,
3595
- __spreadValues({
3596
- ref,
3597
- orientation,
3598
- className: cn(
3599
- "flex touch-none select-none transition-colors",
3600
- orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
3601
- orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
3602
- className
3603
- )
3604
- }, props),
3605
- /* @__PURE__ */ React28.createElement(ScrollAreaPrimitive.ScrollAreaThumb, { className: "relative flex-1 rounded-full bg-border" })
3606
- );
3607
- });
3826
+ var ScrollBar = React9.forwardRef(({ className, orientation = "vertical", ...props }, ref) => /* @__PURE__ */ jsx(
3827
+ ScrollAreaPrimitive.ScrollAreaScrollbar,
3828
+ {
3829
+ ref,
3830
+ orientation,
3831
+ className: cn(
3832
+ "flex touch-none select-none transition-colors",
3833
+ orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent p-[1px]",
3834
+ orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent p-[1px]",
3835
+ className
3836
+ ),
3837
+ ...props,
3838
+ children: /* @__PURE__ */ jsx(ScrollAreaPrimitive.ScrollAreaThumb, { className: "relative flex-1 rounded-full bg-border" })
3839
+ }
3840
+ ));
3608
3841
  ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
3609
-
3610
- // src/react-ui/components/ui/QuizResult.tsx
3611
3842
  var QuizResult = ({
3612
3843
  result,
3613
3844
  quizTitle,
@@ -3616,7 +3847,6 @@ var QuizResult = ({
3616
3847
  showReviewButton = false,
3617
3848
  isReviewLoading = false
3618
3849
  }) => {
3619
- var _a, _b, _c, _d;
3620
3850
  const { t } = useTranslation();
3621
3851
  const getAnswerDisplay = (answer) => {
3622
3852
  if (answer === null || answer === void 0) return t("practiceFlow.results.notAnswered");
@@ -3635,24 +3865,150 @@ var QuizResult = ({
3635
3865
  }
3636
3866
  return String(answer);
3637
3867
  };
3638
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full max-w-3xl mx-auto shadow-xl" }, /* @__PURE__ */ React28__default.createElement(CardHeader, null, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-3xl font-headline text-center" }, t("practiceFlow.results.title", { quizTitle })), /* @__PURE__ */ React28__default.createElement(CardDescription, { className: "text-center text-lg" }, t("practiceFlow.results.description"))), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "space-y-6" }, /* @__PURE__ */ React28__default.createElement(Card, { className: "bg-secondary/50" }, /* @__PURE__ */ React28__default.createElement(CardHeader, null, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-xl flex items-center" }, /* @__PURE__ */ React28__default.createElement(BarChart2, { className: "mr-2 h-5 w-5 text-primary" }), t("practiceFlow.results.overallScore"))), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "grid grid-cols-1 md:grid-cols-3 gap-4 text-center" }, /* @__PURE__ */ React28__default.createElement("div", null, /* @__PURE__ */ React28__default.createElement("p", { className: "text-3xl font-bold text-primary" }, result.score, " / ", result.maxScore), /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm text-muted-foreground" }, t("practiceFlow.results.points"))), /* @__PURE__ */ React28__default.createElement("div", null, /* @__PURE__ */ React28__default.createElement("p", { className: "text-3xl font-bold text-primary" }, result.percentage.toFixed(2), "%"), /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm text-muted-foreground" }, t("practiceFlow.results.percentage"))), /* @__PURE__ */ React28__default.createElement("div", null, result.passed !== void 0 && (result.passed ? /* @__PURE__ */ React28__default.createElement("div", { className: "flex flex-col items-center text-green-600" }, /* @__PURE__ */ React28__default.createElement(CheckCircle, { className: "h-10 w-10" }), /* @__PURE__ */ React28__default.createElement("p", { className: "text-xl font-semibold mt-1" }, t("practiceFlow.results.passed"))) : /* @__PURE__ */ React28__default.createElement("div", { className: "flex flex-col items-center text-destructive" }, /* @__PURE__ */ React28__default.createElement(XCircle, { className: "h-10 w-10" }), /* @__PURE__ */ React28__default.createElement("p", { className: "text-xl font-semibold mt-1" }, t("practiceFlow.results.failed"))))))), /* @__PURE__ */ React28__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm" }, /* @__PURE__ */ React28__default.createElement("div", { className: "flex items-center space-x-2 p-3 bg-muted rounded-md" }, /* @__PURE__ */ React28__default.createElement(Clock, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ React28__default.createElement("span", null, t("practiceFlow.results.timeSpent")), /* @__PURE__ */ React28__default.createElement("span", { className: "font-semibold" }, (_b = (_a = result.totalTimeSpentSeconds) == null ? void 0 : _a.toFixed(0)) != null ? _b : "N/A", " ", t("practiceFlow.results.timeUnit"))), /* @__PURE__ */ React28__default.createElement("div", { className: "flex items-center space-x-2 p-3 bg-muted rounded-md" }, /* @__PURE__ */ React28__default.createElement(Percent, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ React28__default.createElement("span", null, t("practiceFlow.results.avgTimePerQuestion")), /* @__PURE__ */ React28__default.createElement("span", { className: "font-semibold" }, (_d = (_c = result.averageTimePerQuestionSeconds) == null ? void 0 : _c.toFixed(1)) != null ? _d : "N/A", " ", t("practiceFlow.results.timeUnit")))), result.scormStatus && result.scormStatus !== "idle" && result.scormStatus !== "no_api" && /* @__PURE__ */ React28__default.createElement(Card, null, /* @__PURE__ */ React28__default.createElement(CardHeader, null, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-lg" }, "SCORM Sync Status")), /* @__PURE__ */ React28__default.createElement(CardContent, null, /* @__PURE__ */ React28__default.createElement("p", { className: `flex items-center ${result.scormStatus === "error" ? "text-destructive" : "text-muted-foreground"}` }, result.scormStatus === "error" && /* @__PURE__ */ React28__default.createElement(AlertTriangle, { className: "mr-2 h-4 w-4" }), "Status: ", /* @__PURE__ */ React28__default.createElement("span", { className: "font-semibold ml-1" }, result.scormStatus)), result.scormError && /* @__PURE__ */ React28__default.createElement("p", { className: "text-xs text-destructive mt-1" }, "Details: ", result.scormError))), result.webhookStatus && result.webhookStatus !== "idle" && /* @__PURE__ */ React28__default.createElement(Card, null, /* @__PURE__ */ React28__default.createElement(CardHeader, null, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-lg" }, "Webhook Sync Status")), /* @__PURE__ */ React28__default.createElement(CardContent, null, /* @__PURE__ */ React28__default.createElement("p", { className: `flex items-center ${result.webhookStatus === "error" ? "text-destructive" : "text-muted-foreground"}` }, result.webhookStatus === "error" && /* @__PURE__ */ React28__default.createElement(AlertTriangle, { className: "mr-2 h-4 w-4" }), "Status: ", /* @__PURE__ */ React28__default.createElement("span", { className: "font-semibold ml-1" }, result.webhookStatus)), result.webhookError && /* @__PURE__ */ React28__default.createElement("p", { className: "text-xs text-destructive mt-1" }, "Details: ", result.webhookError))), /* @__PURE__ */ React28__default.createElement(Accordion, { type: "single", collapsible: true, className: "w-full" }, /* @__PURE__ */ React28__default.createElement(AccordionItem, { value: "question-breakdown" }, /* @__PURE__ */ React28__default.createElement(AccordionTrigger, { className: "text-lg font-semibold" }, t("practiceFlow.results.questionBreakdown")), /* @__PURE__ */ React28__default.createElement(AccordionContent, null, /* @__PURE__ */ React28__default.createElement(ScrollArea, { className: "h-[300px] pr-4" }, /* @__PURE__ */ React28__default.createElement("ul", { className: "space-y-4" }, result.questionResults.map((qResult, index) => {
3639
- var _a2, _b2;
3640
- return /* @__PURE__ */ React28__default.createElement("li", { key: qResult.questionId, className: "p-4 border rounded-md bg-background" }, /* @__PURE__ */ React28__default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ React28__default.createElement("h4", { className: "font-semibold" }, t("common.questions", { count: index + 1 })), qResult.isCorrect ? /* @__PURE__ */ React28__default.createElement("span", { className: "text-green-600 font-medium flex items-center" }, /* @__PURE__ */ React28__default.createElement(CheckCircle, { className: "mr-1 h-4 w-4" }), " ", t("practiceFlow.results.passed")) : /* @__PURE__ */ React28__default.createElement("span", { className: "text-destructive font-medium flex items-center" }, /* @__PURE__ */ React28__default.createElement(XCircle, { className: "mr-1 h-4 w-4" }), " ", t("practiceFlow.results.failed"))), /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm" }, /* @__PURE__ */ React28__default.createElement("span", { className: "font-medium" }, t("practiceFlow.results.yourAnswer")), " ", getAnswerDisplay(qResult.userAnswer)), !qResult.isCorrect && /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm" }, /* @__PURE__ */ React28__default.createElement("span", { className: "font-medium" }, t("practiceFlow.results.correctAnswer")), " ", getAnswerDisplay(qResult.correctAnswer)), /* @__PURE__ */ React28__default.createElement("p", { className: "text-xs text-muted-foreground" }, /* @__PURE__ */ React28__default.createElement("span", { className: "font-medium" }, t("practiceFlow.results.pointsEarned")), " ", qResult.pointsEarned), /* @__PURE__ */ React28__default.createElement("p", { className: "text-xs text-muted-foreground" }, /* @__PURE__ */ React28__default.createElement("span", { className: "font-medium" }, t("practiceFlow.results.timeSpent")), " ", (_b2 = (_a2 = qResult.timeSpentSeconds) == null ? void 0 : _a2.toFixed(0)) != null ? _b2 : "N/A", t("practiceFlow.results.timeUnit")));
3641
- }))))))), /* @__PURE__ */ React28__default.createElement(CardFooter, { className: "flex flex-col sm:flex-row justify-between gap-2" }, onExitQuiz && /* @__PURE__ */ React28__default.createElement(Button, { variant: "outline", onClick: onExitQuiz, className: "w-full sm:w-auto" }, /* @__PURE__ */ React28__default.createElement(LogOut, { className: "mr-2 h-4 w-4" }), t("common.exit")), showReviewButton && onGenerateReview && /* @__PURE__ */ React28__default.createElement(
3642
- Button,
3643
- {
3644
- onClick: onGenerateReview,
3645
- disabled: isReviewLoading,
3646
- className: "w-full sm:w-auto"
3647
- },
3648
- isReviewLoading ? /* @__PURE__ */ React28__default.createElement(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React28__default.createElement(Wand2, { className: "mr-2 h-4 w-4" }),
3649
- isReviewLoading ? t("practiceFlow.results.generatingReview") : t("practiceFlow.results.generateReview")
3650
- )));
3868
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full max-w-3xl mx-auto shadow-xl", children: [
3869
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
3870
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-3xl font-headline text-center", children: t("practiceFlow.results.title", { quizTitle }) }),
3871
+ /* @__PURE__ */ jsx(CardDescription, { className: "text-center text-lg", children: t("practiceFlow.results.description") })
3872
+ ] }),
3873
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-6", children: [
3874
+ /* @__PURE__ */ jsxs(Card, { className: "bg-secondary/50", children: [
3875
+ /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "text-xl flex items-center", children: [
3876
+ /* @__PURE__ */ jsx(BarChart2, { className: "mr-2 h-5 w-5 text-primary" }),
3877
+ t("practiceFlow.results.overallScore")
3878
+ ] }) }),
3879
+ /* @__PURE__ */ jsxs(CardContent, { className: "grid grid-cols-1 md:grid-cols-3 gap-4 text-center", children: [
3880
+ /* @__PURE__ */ jsxs("div", { children: [
3881
+ /* @__PURE__ */ jsxs("p", { className: "text-3xl font-bold text-primary", children: [
3882
+ result.score,
3883
+ " / ",
3884
+ result.maxScore
3885
+ ] }),
3886
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("practiceFlow.results.points") })
3887
+ ] }),
3888
+ /* @__PURE__ */ jsxs("div", { children: [
3889
+ /* @__PURE__ */ jsxs("p", { className: "text-3xl font-bold text-primary", children: [
3890
+ result.percentage.toFixed(2),
3891
+ "%"
3892
+ ] }),
3893
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("practiceFlow.results.percentage") })
3894
+ ] }),
3895
+ /* @__PURE__ */ jsx("div", { children: result.passed !== void 0 && (result.passed ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center text-green-600", children: [
3896
+ /* @__PURE__ */ jsx(CheckCircle, { className: "h-10 w-10" }),
3897
+ /* @__PURE__ */ jsx("p", { className: "text-xl font-semibold mt-1", children: t("practiceFlow.results.passed") })
3898
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center text-destructive", children: [
3899
+ /* @__PURE__ */ jsx(XCircle, { className: "h-10 w-10" }),
3900
+ /* @__PURE__ */ jsx("p", { className: "text-xl font-semibold mt-1", children: t("practiceFlow.results.failed") })
3901
+ ] })) })
3902
+ ] })
3903
+ ] }),
3904
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm", children: [
3905
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2 p-3 bg-muted rounded-md", children: [
3906
+ /* @__PURE__ */ jsx(Clock, { className: "h-5 w-5 text-primary" }),
3907
+ /* @__PURE__ */ jsx("span", { children: t("practiceFlow.results.timeSpent") }),
3908
+ /* @__PURE__ */ jsxs("span", { className: "font-semibold", children: [
3909
+ result.totalTimeSpentSeconds?.toFixed(0) ?? "N/A",
3910
+ " ",
3911
+ t("practiceFlow.results.timeUnit")
3912
+ ] })
3913
+ ] }),
3914
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2 p-3 bg-muted rounded-md", children: [
3915
+ /* @__PURE__ */ jsx(Percent, { className: "h-5 w-5 text-primary" }),
3916
+ /* @__PURE__ */ jsx("span", { children: t("practiceFlow.results.avgTimePerQuestion") }),
3917
+ /* @__PURE__ */ jsxs("span", { className: "font-semibold", children: [
3918
+ result.averageTimePerQuestionSeconds?.toFixed(1) ?? "N/A",
3919
+ " ",
3920
+ t("practiceFlow.results.timeUnit")
3921
+ ] })
3922
+ ] })
3923
+ ] }),
3924
+ result.scormStatus && result.scormStatus !== "idle" && result.scormStatus !== "no_api" && /* @__PURE__ */ jsxs(Card, { children: [
3925
+ /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { className: "text-lg", children: "SCORM Sync Status" }) }),
3926
+ /* @__PURE__ */ jsxs(CardContent, { children: [
3927
+ /* @__PURE__ */ jsxs("p", { className: `flex items-center ${result.scormStatus === "error" ? "text-destructive" : "text-muted-foreground"}`, children: [
3928
+ result.scormStatus === "error" && /* @__PURE__ */ jsx(AlertTriangle, { className: "mr-2 h-4 w-4" }),
3929
+ "Status: ",
3930
+ /* @__PURE__ */ jsx("span", { className: "font-semibold ml-1", children: result.scormStatus })
3931
+ ] }),
3932
+ result.scormError && /* @__PURE__ */ jsxs("p", { className: "text-xs text-destructive mt-1", children: [
3933
+ "Details: ",
3934
+ result.scormError
3935
+ ] })
3936
+ ] })
3937
+ ] }),
3938
+ result.webhookStatus && result.webhookStatus !== "idle" && /* @__PURE__ */ jsxs(Card, { children: [
3939
+ /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { className: "text-lg", children: "Webhook Sync Status" }) }),
3940
+ /* @__PURE__ */ jsxs(CardContent, { children: [
3941
+ /* @__PURE__ */ jsxs("p", { className: `flex items-center ${result.webhookStatus === "error" ? "text-destructive" : "text-muted-foreground"}`, children: [
3942
+ result.webhookStatus === "error" && /* @__PURE__ */ jsx(AlertTriangle, { className: "mr-2 h-4 w-4" }),
3943
+ "Status: ",
3944
+ /* @__PURE__ */ jsx("span", { className: "font-semibold ml-1", children: result.webhookStatus })
3945
+ ] }),
3946
+ result.webhookError && /* @__PURE__ */ jsxs("p", { className: "text-xs text-destructive mt-1", children: [
3947
+ "Details: ",
3948
+ result.webhookError
3949
+ ] })
3950
+ ] })
3951
+ ] }),
3952
+ /* @__PURE__ */ jsx(Accordion, { type: "single", collapsible: true, className: "w-full", children: /* @__PURE__ */ jsxs(AccordionItem, { value: "question-breakdown", children: [
3953
+ /* @__PURE__ */ jsx(AccordionTrigger, { className: "text-lg font-semibold", children: t("practiceFlow.results.questionBreakdown") }),
3954
+ /* @__PURE__ */ jsx(AccordionContent, { children: /* @__PURE__ */ jsx(ScrollArea, { className: "h-[300px] pr-4", children: /* @__PURE__ */ jsx("ul", { className: "space-y-4", children: result.questionResults.map((qResult, index) => /* @__PURE__ */ jsxs("li", { className: "p-4 border rounded-md bg-background", children: [
3955
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center mb-2", children: [
3956
+ /* @__PURE__ */ jsx("h4", { className: "font-semibold", children: t("common.questions", { count: index + 1 }) }),
3957
+ qResult.isCorrect ? /* @__PURE__ */ jsxs("span", { className: "text-green-600 font-medium flex items-center", children: [
3958
+ /* @__PURE__ */ jsx(CheckCircle, { className: "mr-1 h-4 w-4" }),
3959
+ " ",
3960
+ t("practiceFlow.results.passed")
3961
+ ] }) : /* @__PURE__ */ jsxs("span", { className: "text-destructive font-medium flex items-center", children: [
3962
+ /* @__PURE__ */ jsx(XCircle, { className: "mr-1 h-4 w-4" }),
3963
+ " ",
3964
+ t("practiceFlow.results.failed")
3965
+ ] })
3966
+ ] }),
3967
+ /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
3968
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: t("practiceFlow.results.yourAnswer") }),
3969
+ " ",
3970
+ getAnswerDisplay(qResult.userAnswer)
3971
+ ] }),
3972
+ !qResult.isCorrect && /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
3973
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: t("practiceFlow.results.correctAnswer") }),
3974
+ " ",
3975
+ getAnswerDisplay(qResult.correctAnswer)
3976
+ ] }),
3977
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
3978
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: t("practiceFlow.results.pointsEarned") }),
3979
+ " ",
3980
+ qResult.pointsEarned
3981
+ ] }),
3982
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
3983
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: t("practiceFlow.results.timeSpent") }),
3984
+ " ",
3985
+ qResult.timeSpentSeconds?.toFixed(0) ?? "N/A",
3986
+ t("practiceFlow.results.timeUnit")
3987
+ ] })
3988
+ ] }, qResult.questionId)) }) }) })
3989
+ ] }) })
3990
+ ] }),
3991
+ /* @__PURE__ */ jsxs(CardFooter, { className: "flex flex-col sm:flex-row justify-between gap-2", children: [
3992
+ onExitQuiz && /* @__PURE__ */ jsxs(Button, { variant: "outline", onClick: onExitQuiz, className: "w-full sm:w-auto", children: [
3993
+ /* @__PURE__ */ jsx(LogOut, { className: "mr-2 h-4 w-4" }),
3994
+ t("common.exit")
3995
+ ] }),
3996
+ showReviewButton && onGenerateReview && /* @__PURE__ */ jsxs(
3997
+ Button,
3998
+ {
3999
+ onClick: onGenerateReview,
4000
+ disabled: isReviewLoading,
4001
+ className: "w-full sm:w-auto",
4002
+ children: [
4003
+ isReviewLoading ? /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Wand2, { className: "mr-2 h-4 w-4" }),
4004
+ isReviewLoading ? t("practiceFlow.results.generatingReview") : t("practiceFlow.results.generateReview")
4005
+ ]
4006
+ }
4007
+ )
4008
+ ] })
4009
+ ] });
3651
4010
  };
3652
-
3653
- // src/react-ui/components/ui/QuizPlayer.tsx
3654
4011
  var QuizPlayer = ({ quizConfig, onQuizComplete, onExitQuiz }) => {
3655
- var _a;
3656
4012
  const [engine, setEngine] = useState(null);
3657
4013
  const [currentQuestion, setCurrentQuestion] = useState(null);
3658
4014
  const [currentQuestionNumber, setCurrentQuestionNumber] = useState(0);
@@ -3676,11 +4032,10 @@ var QuizPlayer = ({ quizConfig, onQuizComplete, onExitQuiz }) => {
3676
4032
  setIsLoading(false);
3677
4033
  },
3678
4034
  onQuestionChange: (question, qNum, total) => {
3679
- var _a2;
3680
4035
  setCurrentQuestion(question);
3681
4036
  setCurrentQuestionNumber(qNum);
3682
4037
  setTotalQuestions(total);
3683
- const existingAnswer = (_a2 = engineRef.current) == null ? void 0 : _a2.getUserAnswer((question == null ? void 0 : question.id) || "");
4038
+ const existingAnswer = engineRef.current?.getUserAnswer(question?.id || "");
3684
4039
  setUserAnswer(existingAnswer !== void 0 ? existingAnswer : null);
3685
4040
  },
3686
4041
  onQuizFinish: (results) => {
@@ -3697,10 +4052,10 @@ var QuizPlayer = ({ quizConfig, onQuizComplete, onExitQuiz }) => {
3697
4052
  }
3698
4053
  }), [onQuizComplete]);
3699
4054
  const handleAnswerChange = useCallback((answer) => {
3700
- if ((currentQuestion == null ? void 0 : currentQuestion.questionType) !== "blockly_programming" && (currentQuestion == null ? void 0 : currentQuestion.questionType) !== "scratch_programming") {
4055
+ if (currentQuestion?.questionType !== "blockly_programming" && currentQuestion?.questionType !== "scratch_programming") {
3701
4056
  setUserAnswer(answer);
3702
4057
  }
3703
- }, [currentQuestion == null ? void 0 : currentQuestion.questionType]);
4058
+ }, [currentQuestion?.questionType]);
3704
4059
  const quizConfigKey = useMemo(() => {
3705
4060
  return JSON.stringify({
3706
4061
  id: quizConfig.id,
@@ -3745,7 +4100,6 @@ var QuizPlayer = ({ quizConfig, onQuizComplete, onExitQuiz }) => {
3745
4100
  };
3746
4101
  }, [quizConfigKey, callbacks, quizConfig]);
3747
4102
  const handleSubmitAnswer = useCallback(() => {
3748
- var _a2;
3749
4103
  const currentEngine = engineRef.current;
3750
4104
  if (!currentEngine || !currentQuestion) return;
3751
4105
  let answerToSubmit = null;
@@ -3753,7 +4107,7 @@ var QuizPlayer = ({ quizConfig, onQuizComplete, onExitQuiz }) => {
3753
4107
  if (programmingQuestionRef.current && typeof programmingQuestionRef.current.getWorkspaceXml === "function") {
3754
4108
  answerToSubmit = programmingQuestionRef.current.getWorkspaceXml();
3755
4109
  } else {
3756
- answerToSubmit = (_a2 = currentEngine.getUserAnswer(currentQuestion.id)) != null ? _a2 : null;
4110
+ answerToSubmit = currentEngine.getUserAnswer(currentQuestion.id) ?? null;
3757
4111
  }
3758
4112
  } else {
3759
4113
  answerToSubmit = userAnswer;
@@ -3796,53 +4150,104 @@ var QuizPlayer = ({ quizConfig, onQuizComplete, onExitQuiz }) => {
3796
4150
  return `${mins}:${secs < 10 ? "0" : ""}${secs}`;
3797
4151
  }, []);
3798
4152
  if (isLoading) {
3799
- return /* @__PURE__ */ React28__default.createElement("div", { className: "flex flex-col items-center justify-center h-64" }, /* @__PURE__ */ React28__default.createElement(Loader2, { className: "h-12 w-12 animate-spin text-primary" }), /* @__PURE__ */ React28__default.createElement("p", { className: "mt-4 text-muted-foreground" }, t("common.loading")));
4153
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center h-64", children: [
4154
+ /* @__PURE__ */ jsx(Loader2, { className: "h-12 w-12 animate-spin text-primary" }),
4155
+ /* @__PURE__ */ jsx("p", { className: "mt-4 text-muted-foreground", children: t("common.loading") })
4156
+ ] });
3800
4157
  }
3801
4158
  if (error) {
3802
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full max-w-2xl mx-auto shadow-xl" }, /* @__PURE__ */ React28__default.createElement(CardHeader, null, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-destructive flex items-center" }, /* @__PURE__ */ React28__default.createElement(AlertCircle, { className: "mr-2 h-6 w-6" }), "Quiz Error")), /* @__PURE__ */ React28__default.createElement(CardContent, null, /* @__PURE__ */ React28__default.createElement("p", null, error)), /* @__PURE__ */ React28__default.createElement(CardFooter, null, onExitQuiz && /* @__PURE__ */ React28__default.createElement(Button, { variant: "outline", onClick: onExitQuiz }, /* @__PURE__ */ React28__default.createElement(LogOut, { className: "mr-2 h-4 w-4" }), " ", t("common.exit"))));
4159
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full max-w-2xl mx-auto shadow-xl", children: [
4160
+ /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "text-destructive flex items-center", children: [
4161
+ /* @__PURE__ */ jsx(AlertCircle, { className: "mr-2 h-6 w-6" }),
4162
+ "Quiz Error"
4163
+ ] }) }),
4164
+ /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx("p", { children: error }) }),
4165
+ /* @__PURE__ */ jsx(CardFooter, { children: onExitQuiz && /* @__PURE__ */ jsxs(Button, { variant: "outline", onClick: onExitQuiz, children: [
4166
+ /* @__PURE__ */ jsx(LogOut, { className: "mr-2 h-4 w-4" }),
4167
+ " ",
4168
+ t("common.exit")
4169
+ ] }) })
4170
+ ] });
3803
4171
  }
3804
4172
  if (quizFinished && finalResult) {
3805
- return /* @__PURE__ */ React28__default.createElement(QuizResult, { result: finalResult, onExitQuiz, quizTitle: quizConfig.title });
4173
+ return /* @__PURE__ */ jsx(QuizResult, { result: finalResult, onExitQuiz, quizTitle: quizConfig.title });
3806
4174
  }
3807
4175
  if (!currentQuestion) {
3808
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full max-w-2xl mx-auto shadow-xl" }, /* @__PURE__ */ React28__default.createElement(CardHeader, null, /* @__PURE__ */ React28__default.createElement(CardTitle, null, "Quiz Ended"), /* @__PURE__ */ React28__default.createElement(CardDescription, null, "No more questions, or quiz not loaded correctly.")), /* @__PURE__ */ React28__default.createElement(CardFooter, null, onExitQuiz && /* @__PURE__ */ React28__default.createElement(Button, { variant: "outline", onClick: onExitQuiz }, /* @__PURE__ */ React28__default.createElement(LogOut, { className: "mr-2 h-4 w-4" }), " ", t("common.exit"))));
4176
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full max-w-2xl mx-auto shadow-xl", children: [
4177
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
4178
+ /* @__PURE__ */ jsx(CardTitle, { children: "Quiz Ended" }),
4179
+ /* @__PURE__ */ jsx(CardDescription, { children: "No more questions, or quiz not loaded correctly." })
4180
+ ] }),
4181
+ /* @__PURE__ */ jsx(CardFooter, { children: onExitQuiz && /* @__PURE__ */ jsxs(Button, { variant: "outline", onClick: onExitQuiz, children: [
4182
+ /* @__PURE__ */ jsx(LogOut, { className: "mr-2 h-4 w-4" }),
4183
+ " ",
4184
+ t("common.exit")
4185
+ ] }) })
4186
+ ] });
3809
4187
  }
3810
- return /* @__PURE__ */ React28__default.createElement(Card, { className: "w-full max-w-3xl mx-auto shadow-xl" }, /* @__PURE__ */ React28__default.createElement(CardHeader, null, /* @__PURE__ */ React28__default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React28__default.createElement(CardTitle, { className: "text-2xl font-headline" }, quizConfig.title), timeLeft !== null && /* @__PURE__ */ React28__default.createElement("div", { className: "flex items-center text-sm text-muted-foreground" }, /* @__PURE__ */ React28__default.createElement(Clock, { className: "mr-1 h-4 w-4" }), t("practiceFlow.player.timeLeft", { time: formatTime(timeLeft) }))), quizConfig.description && /* @__PURE__ */ React28__default.createElement(CardDescription, null, quizConfig.description), /* @__PURE__ */ React28__default.createElement("div", { className: "mt-2" }, /* @__PURE__ */ React28__default.createElement(
3811
- Progress,
3812
- {
3813
- value: progressPercent,
3814
- "aria-label": `Quiz progress: ${currentQuestionNumber} of ${totalQuestions} questions`,
3815
- className: "w-full"
3816
- }
3817
- ), /* @__PURE__ */ React28__default.createElement("p", { className: "text-sm text-muted-foreground mt-1 text-right" }, t("practiceFlow.player.questionProgress", { current: currentQuestionNumber, total: totalQuestions })))), /* @__PURE__ */ React28__default.createElement(CardContent, { className: "min-h-[200px]" }, /* @__PURE__ */ React28__default.createElement(
3818
- QuestionRenderer,
3819
- {
3820
- question: currentQuestion,
3821
- onAnswerChange: handleAnswerChange,
3822
- userAnswer,
3823
- showCorrectAnswer: ((_a = quizConfig.settings) == null ? void 0 : _a.showCorrectAnswers) === "immediately",
3824
- key: currentQuestion.id,
3825
- ref: currentQuestion.questionType === "blockly_programming" || currentQuestion.questionType === "scratch_programming" ? programmingQuestionRef : null
3826
- }
3827
- )), /* @__PURE__ */ React28__default.createElement(CardFooter, { className: "flex justify-between items-center" }, /* @__PURE__ */ React28__default.createElement(
3828
- Button,
3829
- {
3830
- variant: "outline",
3831
- onClick: handlePrevious,
3832
- disabled: currentQuestionNumber <= 1
3833
- },
3834
- /* @__PURE__ */ React28__default.createElement(ChevronLeft, { className: "mr-2 h-4 w-4" }),
3835
- " ",
3836
- t("common.previous")
3837
- ), onExitQuiz && /* @__PURE__ */ React28__default.createElement(
3838
- Button,
3839
- {
3840
- variant: "ghost",
3841
- onClick: onExitQuiz,
3842
- className: "text-muted-foreground hover:text-destructive"
3843
- },
3844
- t("common.exit")
3845
- ), /* @__PURE__ */ React28__default.createElement(Button, { onClick: handleNext }, currentQuestionNumber === totalQuestions ? t("practiceFlow.player.finishQuiz") : t("common.next"), currentQuestionNumber !== totalQuestions && /* @__PURE__ */ React28__default.createElement(ChevronRight, { className: "ml-2 h-4 w-4" }), currentQuestionNumber === totalQuestions && /* @__PURE__ */ React28__default.createElement(CheckCircle, { className: "ml-2 h-4 w-4" }))));
4188
+ return /* @__PURE__ */ jsxs(Card, { className: "w-full max-w-3xl mx-auto shadow-xl", children: [
4189
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
4190
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center", children: [
4191
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-2xl font-headline", children: quizConfig.title }),
4192
+ timeLeft !== null && /* @__PURE__ */ jsxs("div", { className: "flex items-center text-sm text-muted-foreground", children: [
4193
+ /* @__PURE__ */ jsx(Clock, { className: "mr-1 h-4 w-4" }),
4194
+ t("practiceFlow.player.timeLeft", { time: formatTime(timeLeft) })
4195
+ ] })
4196
+ ] }),
4197
+ quizConfig.description && /* @__PURE__ */ jsx(CardDescription, { children: quizConfig.description }),
4198
+ /* @__PURE__ */ jsxs("div", { className: "mt-2", children: [
4199
+ /* @__PURE__ */ jsx(
4200
+ Progress,
4201
+ {
4202
+ value: progressPercent,
4203
+ "aria-label": `Quiz progress: ${currentQuestionNumber} of ${totalQuestions} questions`,
4204
+ className: "w-full"
4205
+ }
4206
+ ),
4207
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1 text-right", children: t("practiceFlow.player.questionProgress", { current: currentQuestionNumber, total: totalQuestions }) })
4208
+ ] })
4209
+ ] }),
4210
+ /* @__PURE__ */ jsx(CardContent, { className: "min-h-[200px]", children: /* @__PURE__ */ jsx(
4211
+ QuestionRenderer,
4212
+ {
4213
+ question: currentQuestion,
4214
+ onAnswerChange: handleAnswerChange,
4215
+ userAnswer,
4216
+ showCorrectAnswer: quizConfig.settings?.showCorrectAnswers === "immediately",
4217
+ ref: currentQuestion.questionType === "blockly_programming" || currentQuestion.questionType === "scratch_programming" ? programmingQuestionRef : null
4218
+ },
4219
+ currentQuestion.id
4220
+ ) }),
4221
+ /* @__PURE__ */ jsxs(CardFooter, { className: "flex justify-between items-center", children: [
4222
+ /* @__PURE__ */ jsxs(
4223
+ Button,
4224
+ {
4225
+ variant: "outline",
4226
+ onClick: handlePrevious,
4227
+ disabled: currentQuestionNumber <= 1,
4228
+ children: [
4229
+ /* @__PURE__ */ jsx(ChevronLeft, { className: "mr-2 h-4 w-4" }),
4230
+ " ",
4231
+ t("common.previous")
4232
+ ]
4233
+ }
4234
+ ),
4235
+ onExitQuiz && /* @__PURE__ */ jsx(
4236
+ Button,
4237
+ {
4238
+ variant: "ghost",
4239
+ onClick: onExitQuiz,
4240
+ className: "text-muted-foreground hover:text-destructive",
4241
+ children: t("common.exit")
4242
+ }
4243
+ ),
4244
+ /* @__PURE__ */ jsxs(Button, { onClick: handleNext, children: [
4245
+ currentQuestionNumber === totalQuestions ? t("practiceFlow.player.finishQuiz") : t("common.next"),
4246
+ currentQuestionNumber !== totalQuestions && /* @__PURE__ */ jsx(ChevronRight, { className: "ml-2 h-4 w-4" }),
4247
+ currentQuestionNumber === totalQuestions && /* @__PURE__ */ jsx(CheckCircle, { className: "ml-2 h-4 w-4" })
4248
+ ] })
4249
+ ] })
4250
+ ] });
3846
4251
  };
3847
4252
 
3848
4253
  // src/player.ts
@@ -3871,20 +4276,20 @@ function mountQuizPlayer(targetElementId, quizConfig) {
3871
4276
  }
3872
4277
  };
3873
4278
  if (quizResult) {
3874
- return React28__default.createElement(QuizResult, {
4279
+ return React9__default.createElement(QuizResult, {
3875
4280
  result: quizResult,
3876
4281
  quizTitle: quizConfig.title,
3877
4282
  onExitQuiz: handleExit
3878
4283
  });
3879
4284
  }
3880
- return React28__default.createElement(QuizPlayer, {
4285
+ return React9__default.createElement(QuizPlayer, {
3881
4286
  quizConfig,
3882
4287
  onQuizComplete: handleQuizComplete,
3883
4288
  onExitQuiz: handleExit
3884
4289
  });
3885
4290
  };
3886
4291
  const root = ReactDOM.createRoot(targetElement);
3887
- root.render(React28__default.createElement(React28__default.StrictMode, null, React28__default.createElement(AppContainer)));
4292
+ root.render(React9__default.createElement(React9__default.StrictMode, null, React9__default.createElement(AppContainer)));
3888
4293
  }
3889
4294
 
3890
4295
  export { mountQuizPlayer };