@thanh01.pmt/interactive-quiz-kit 1.0.70 → 1.0.72

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.
@@ -76430,11 +76430,17 @@ function MetadataImportControls({ metadataName, onImport }) {
76430
76430
  const fileInputRef = React119.useRef(null);
76431
76431
  const { toast: toast2 } = useToast();
76432
76432
  const processAndImportRecords = async (records, importSource) => {
76433
+ console.log(`[ImportControls] Processing ${records.length} records from ${importSource} for ${metadataName}.`);
76433
76434
  if (records.length === 0) {
76434
76435
  toast2({ title: "No Data", description: `The selected ${importSource === "file" ? "file" : "JSON string"} contains no data to import.`, variant: "destructive" });
76435
76436
  return;
76436
76437
  }
76437
- await onImport(records);
76438
+ try {
76439
+ await onImport(records);
76440
+ } catch (error) {
76441
+ console.error(`[ImportControls] Error during onImport callback for ${metadataName}:`, error);
76442
+ toast2({ title: "Import Failed", description: `An error occurred while saving the data: ${error instanceof Error ? error.message : String(error)}`, variant: "destructive" });
76443
+ }
76438
76444
  setIsOpen(false);
76439
76445
  setJsonString("");
76440
76446
  };
@@ -76466,8 +76472,10 @@ function MetadataImportControls({ metadataName, onImport }) {
76466
76472
  return record;
76467
76473
  });
76468
76474
  }
76475
+ console.log(`[ImportControls] File parsed successfully. Found ${records.length} records.`);
76469
76476
  await processAndImportRecords(records, "file");
76470
76477
  } catch (err) {
76478
+ console.error("[ImportControls] Error parsing file:", err);
76471
76479
  toast2({ title: "Import Error", description: `Failed to process file: ${err.message}`, variant: "destructive" });
76472
76480
  }
76473
76481
  });
@@ -77286,15 +77294,27 @@ function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onU
77286
77294
 
77287
77295
  // src/react-ui/components/metadata/LearningObjectiveManager.tsx
77288
77296
  init_react_shim();
77289
- function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
77297
+ function LearningObjectiveManager({
77298
+ initialData,
77299
+ subjects: subjectsProp,
77300
+ isLoading: isLoadingProp,
77301
+ onAdd,
77302
+ onUpdate,
77303
+ onDelete,
77304
+ onBulkAdd
77305
+ }) {
77290
77306
  const [items, setItems] = React119.useState([]);
77291
77307
  const [subjects, setSubjects] = React119.useState([]);
77292
77308
  const [isLoading, setIsLoading] = React119.useState(true);
77293
77309
  const [isDialogOpen, setIsDialogOpen] = React119.useState(false);
77294
77310
  const [isAlertOpen, setIsAlertOpen] = React119.useState(false);
77295
- const [currentItem, setCurrentItem] = React119.useState(null);
77311
+ const [currentItem, setCurrentItem] = React119.useState(
77312
+ null
77313
+ );
77296
77314
  const [formState, setFormState] = React119.useState({});
77297
- const [itemToDelete, setItemToDelete] = React119.useState(null);
77315
+ const [itemToDelete, setItemToDelete] = React119.useState(
77316
+ null
77317
+ );
77298
77318
  const [isPending, startTransition] = React119.useTransition();
77299
77319
  const { toast: toast2 } = useToast();
77300
77320
  const isControlled = initialData !== void 0;
@@ -77305,7 +77325,11 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
77305
77325
  setItems(MetadataService.getLearningObjectives());
77306
77326
  setSubjects(MetadataService.getSubjects());
77307
77327
  } catch (error) {
77308
- toast2({ title: "Error", description: "Failed to refresh data.", variant: "destructive" });
77328
+ toast2({
77329
+ title: "Error",
77330
+ description: "Failed to refresh data.",
77331
+ variant: "destructive"
77332
+ });
77309
77333
  } finally {
77310
77334
  setIsLoading(false);
77311
77335
  }
@@ -77325,7 +77349,9 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
77325
77349
  };
77326
77350
  const handleAddItem = () => {
77327
77351
  setCurrentItem(null);
77328
- setFormState({ subjectCode: subjects.length > 0 ? subjects[0].code : "" });
77352
+ setFormState({
77353
+ subjectCode: subjects.length > 0 ? subjects[0].code : ""
77354
+ });
77329
77355
  setIsDialogOpen(true);
77330
77356
  };
77331
77357
  const handleEditItem = (item) => {
@@ -77347,9 +77373,16 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
77347
77373
  MetadataService.deleteLearningObjective(itemToDelete.code);
77348
77374
  refreshData();
77349
77375
  }
77350
- toast2({ title: "Success", description: `Learning Objective "${itemToDelete.name}" deleted.` });
77376
+ toast2({
77377
+ title: "Success",
77378
+ description: `Learning Objective "${itemToDelete.name}" deleted.`
77379
+ });
77351
77380
  } catch (error) {
77352
- toast2({ title: "Error", description: error.message, variant: "destructive" });
77381
+ toast2({
77382
+ title: "Error",
77383
+ description: error.message,
77384
+ variant: "destructive"
77385
+ });
77353
77386
  } finally {
77354
77387
  setIsAlertOpen(false);
77355
77388
  setItemToDelete(null);
@@ -77358,7 +77391,11 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
77358
77391
  };
77359
77392
  const handleSubmit = () => {
77360
77393
  if (!formState.name?.trim() || !formState.code?.trim()) {
77361
- toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
77394
+ toast2({
77395
+ title: "Validation Error",
77396
+ description: "Code and Name are required.",
77397
+ variant: "destructive"
77398
+ });
77362
77399
  return;
77363
77400
  }
77364
77401
  startTransition(async () => {
@@ -77367,28 +77404,291 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
77367
77404
  if (isControlled && onUpdate) {
77368
77405
  await onUpdate({ ...currentItem, ...formState });
77369
77406
  } else {
77370
- MetadataService.updateLearningObjective(currentItem.id, formState);
77407
+ MetadataService.updateLearningObjective(
77408
+ currentItem.id,
77409
+ formState
77410
+ );
77371
77411
  refreshData();
77372
77412
  }
77373
- toast2({ title: "Success", description: "Learning Objective updated." });
77413
+ toast2({
77414
+ title: "Success",
77415
+ description: "Learning Objective updated."
77416
+ });
77374
77417
  } else {
77375
77418
  if (isControlled && onAdd) {
77376
77419
  await onAdd(formState);
77377
77420
  } else {
77378
- MetadataService.addLearningObjective(formState);
77421
+ MetadataService.addLearningObjective(
77422
+ formState
77423
+ );
77379
77424
  refreshData();
77380
77425
  }
77381
- toast2({ title: "Success", description: "Learning Objective added." });
77426
+ toast2({
77427
+ title: "Success",
77428
+ description: "Learning Objective added."
77429
+ });
77382
77430
  }
77383
77431
  setIsDialogOpen(false);
77384
77432
  } catch (error) {
77385
- toast2({ title: "Error", description: error.message, variant: "destructive" });
77433
+ toast2({
77434
+ title: "Error",
77435
+ description: error.message,
77436
+ variant: "destructive"
77437
+ });
77386
77438
  }
77387
77439
  });
77388
77440
  };
77389
77441
  const handleImport = async (records) => {
77442
+ console.log(
77443
+ `[LO Manager] handleImport called with ${records.length} raw records.`
77444
+ );
77445
+ if (!onBulkAdd) {
77446
+ console.error("[LO Manager] onBulkAdd handler is not provided.");
77447
+ return;
77448
+ }
77449
+ const parseStringToArray = (input) => {
77450
+ if (Array.isArray(input)) return input;
77451
+ if (typeof input === "string")
77452
+ return input.split(",").map((s2) => s2.trim()).filter(Boolean);
77453
+ return [];
77454
+ };
77455
+ const validationResult = records.reduce(
77456
+ (acc, rec) => {
77457
+ if (typeof rec["LO ID"] === "string" && rec["LO ID"].trim() && typeof rec["LO Description"] === "string" && rec["LO Description"].trim()) {
77458
+ acc.valid.push({
77459
+ code: rec["LO ID"],
77460
+ name: rec["LO ID"],
77461
+ description: rec["LO Description"],
77462
+ subject: rec["Subject"] || "",
77463
+ subjectCode: rec["Subject Code"] || rec["Subject"],
77464
+ category: rec["Category"] || "",
77465
+ categoryCode: rec["Category Code"] || rec["Category"],
77466
+ topic: rec["Topic"] || "",
77467
+ topicCode: rec["Topic Code"] || rec["Topic"],
77468
+ grade: rec["Grade"] || "",
77469
+ gradeCode: rec["Grade Code"] || rec["Grade"],
77470
+ keywords: parseStringToArray(rec["Keywords"]),
77471
+ stemElements: parseStringToArray(
77472
+ rec["STEM Element(s)"]
77473
+ ),
77474
+ bloomLevelsGuideline: parseStringToArray(
77475
+ rec["Bloom\u2019s Level(s) Guideline"]
77476
+ )
77477
+ });
77478
+ } else {
77479
+ acc.invalidCount++;
77480
+ }
77481
+ return acc;
77482
+ },
77483
+ { valid: [], invalidCount: 0 }
77484
+ );
77485
+ console.log(
77486
+ `[LO Manager] Validation complete. ${validationResult.valid.length} valid records found.`
77487
+ );
77488
+ if (validationResult.invalidCount > 0) {
77489
+ toast2({
77490
+ title: "Import Warning",
77491
+ description: `${validationResult.invalidCount} records had invalid or missing 'LO ID' or 'LO Description' fields and were ignored.`,
77492
+ variant: "destructive"
77493
+ });
77494
+ }
77495
+ if (validationResult.valid.length > 0) {
77496
+ console.log(
77497
+ "[LO Manager] Calling onBulkAdd prop with validated data..."
77498
+ );
77499
+ await onBulkAdd(validationResult.valid);
77500
+ } else {
77501
+ console.log("[LO Manager] No valid records to import.");
77502
+ }
77390
77503
  };
77391
- return /* @__PURE__ */ React119__namespace.default.createElement(Card, null, /* @__PURE__ */ React119__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React119__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React119__namespace.default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Learning Objectives"), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React119__namespace.default.createElement(MetadataImportControls, { metadataName: "Learning Objectives", onImport: handleImport }), /* @__PURE__ */ React119__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React119__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React119__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React119__namespace.default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React119__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React119__namespace.default.createElement(Table2, null, /* @__PURE__ */ React119__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React119__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React119__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React119__namespace.default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React119__namespace.default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React119__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React119__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React119__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React119__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React119__namespace.default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React119__namespace.default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React119__namespace.default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React119__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React119__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React119__namespace.default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React119__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React119__namespace.default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React119__namespace.default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React119__namespace.default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React119__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e2) => handleFormChange("code", e2.target.value.toUpperCase()), disabled: !!currentItem })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "name", value: formState.name || "", onChange: (e2) => handleFormChange("name", e2.target.value) }))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "subject", value: formState.subject || "", onChange: (e2) => handleFormChange("subject", e2.target.value) })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React119__namespace.default.createElement(EditableCombobox, { options: subjects.map((s2) => ({ value: s2.code, label: s2.name })), value: formState.subjectCode || "", onChange: (val) => handleFormChange("subjectCode", val), placeholder: "Select a subject..." }))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "category", value: formState.category || "", onChange: (e2) => handleFormChange("category", e2.target.value) })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "categoryCode", value: formState.categoryCode || "", onChange: (e2) => handleFormChange("categoryCode", e2.target.value) }))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "topic", value: formState.topic || "", onChange: (e2) => handleFormChange("topic", e2.target.value) })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "topicCode", value: formState.topicCode || "", onChange: (e2) => handleFormChange("topicCode", e2.target.value) }))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "grade", value: formState.grade || "", onChange: (e2) => handleFormChange("grade", e2.target.value) })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "gradeCode", value: formState.gradeCode || "", onChange: (e2) => handleFormChange("gradeCode", e2.target.value) }))), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React119__namespace.default.createElement(Textarea, { id: "keywords", value: formState.keywords?.join(", ") || "", onChange: (e2) => handleFormChange("keywords", e2.target.value.split(",").map((s2) => s2.trim())) })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React119__namespace.default.createElement(Textarea, { id: "stemElements", value: formState.stemElements?.join(", ") || "", onChange: (e2) => handleFormChange("stemElements", e2.target.value.split(",").map((s2) => s2.trim())) })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React119__namespace.default.createElement(Textarea, { id: "bloomLevelsGuideline", value: formState.bloomLevelsGuideline?.join(", ") || "", onChange: (e2) => handleFormChange("bloomLevelsGuideline", e2.target.value.split(",").map((s2) => s2.trim())) }))), /* @__PURE__ */ React119__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React119__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React119__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !formState.name?.trim() || !formState.code?.trim() }, isPending && /* @__PURE__ */ React119__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React119__namespace.default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React119__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
77504
+ return /* @__PURE__ */ React119__namespace.default.createElement(Card, null, /* @__PURE__ */ React119__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React119__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React119__namespace.default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " ", "Manage Learning Objectives"), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React119__namespace.default.createElement(
77505
+ MetadataImportControls,
77506
+ {
77507
+ metadataName: "Learning Objectives",
77508
+ onImport: handleImport
77509
+ }
77510
+ ), /* @__PURE__ */ React119__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React119__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React119__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React119__namespace.default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React119__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React119__namespace.default.createElement(Table2, null, /* @__PURE__ */ React119__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React119__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React119__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React119__namespace.default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React119__namespace.default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React119__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React119__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React119__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React119__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React119__namespace.default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React119__namespace.default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React119__namespace.default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React119__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React119__namespace.default.createElement(
77511
+ Button,
77512
+ {
77513
+ variant: "ghost",
77514
+ size: "icon",
77515
+ onClick: () => handleEditItem(item),
77516
+ className: "mr-2"
77517
+ },
77518
+ /* @__PURE__ */ React119__namespace.default.createElement(PenLine, { className: "h-4 w-4" })
77519
+ ), /* @__PURE__ */ React119__namespace.default.createElement(
77520
+ Button,
77521
+ {
77522
+ variant: "ghost",
77523
+ size: "icon",
77524
+ onClick: () => handleDeleteItem(item),
77525
+ className: "text-destructive hover:text-destructive"
77526
+ },
77527
+ /* @__PURE__ */ React119__namespace.default.createElement(Trash2, { className: "h-4 w-4" })
77528
+ ))))))), /* @__PURE__ */ React119__namespace.default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React119__namespace.default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React119__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React119__namespace.default.createElement(
77529
+ Input,
77530
+ {
77531
+ id: "code",
77532
+ value: formState.code || "",
77533
+ onChange: (e2) => handleFormChange(
77534
+ "code",
77535
+ e2.target.value.toUpperCase()
77536
+ ),
77537
+ disabled: !!currentItem
77538
+ }
77539
+ )), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React119__namespace.default.createElement(
77540
+ Input,
77541
+ {
77542
+ id: "name",
77543
+ value: formState.name || "",
77544
+ onChange: (e2) => handleFormChange(
77545
+ "name",
77546
+ e2.target.value
77547
+ )
77548
+ }
77549
+ ))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React119__namespace.default.createElement(
77550
+ Input,
77551
+ {
77552
+ id: "subject",
77553
+ value: formState.subject || "",
77554
+ onChange: (e2) => handleFormChange(
77555
+ "subject",
77556
+ e2.target.value
77557
+ )
77558
+ }
77559
+ )), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React119__namespace.default.createElement(
77560
+ EditableCombobox,
77561
+ {
77562
+ options: subjects.map((s2) => ({
77563
+ value: s2.code,
77564
+ label: s2.name
77565
+ })),
77566
+ value: formState.subjectCode || "",
77567
+ onChange: (val) => handleFormChange("subjectCode", val),
77568
+ placeholder: "Select a subject..."
77569
+ }
77570
+ ))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React119__namespace.default.createElement(
77571
+ Input,
77572
+ {
77573
+ id: "category",
77574
+ value: formState.category || "",
77575
+ onChange: (e2) => handleFormChange(
77576
+ "category",
77577
+ e2.target.value
77578
+ )
77579
+ }
77580
+ )), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React119__namespace.default.createElement(
77581
+ Input,
77582
+ {
77583
+ id: "categoryCode",
77584
+ value: formState.categoryCode || "",
77585
+ onChange: (e2) => handleFormChange(
77586
+ "categoryCode",
77587
+ e2.target.value
77588
+ )
77589
+ }
77590
+ ))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React119__namespace.default.createElement(
77591
+ Input,
77592
+ {
77593
+ id: "topic",
77594
+ value: formState.topic || "",
77595
+ onChange: (e2) => handleFormChange(
77596
+ "topic",
77597
+ e2.target.value
77598
+ )
77599
+ }
77600
+ )), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React119__namespace.default.createElement(
77601
+ Input,
77602
+ {
77603
+ id: "topicCode",
77604
+ value: formState.topicCode || "",
77605
+ onChange: (e2) => handleFormChange(
77606
+ "topicCode",
77607
+ e2.target.value
77608
+ )
77609
+ }
77610
+ ))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React119__namespace.default.createElement(
77611
+ Input,
77612
+ {
77613
+ id: "grade",
77614
+ value: formState.grade || "",
77615
+ onChange: (e2) => handleFormChange(
77616
+ "grade",
77617
+ e2.target.value
77618
+ )
77619
+ }
77620
+ )), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React119__namespace.default.createElement(
77621
+ Input,
77622
+ {
77623
+ id: "gradeCode",
77624
+ value: formState.gradeCode || "",
77625
+ onChange: (e2) => handleFormChange(
77626
+ "gradeCode",
77627
+ e2.target.value
77628
+ )
77629
+ }
77630
+ ))), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React119__namespace.default.createElement(
77631
+ Textarea,
77632
+ {
77633
+ id: "keywords",
77634
+ value: formState.keywords?.join(", ") || "",
77635
+ onChange: (e2) => handleFormChange(
77636
+ "keywords",
77637
+ e2.target.value.split(",").map((s2) => s2.trim())
77638
+ )
77639
+ }
77640
+ )), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React119__namespace.default.createElement(
77641
+ Textarea,
77642
+ {
77643
+ id: "stemElements",
77644
+ value: formState.stemElements?.join(", ") || "",
77645
+ onChange: (e2) => handleFormChange(
77646
+ "stemElements",
77647
+ e2.target.value.split(",").map((s2) => s2.trim())
77648
+ )
77649
+ }
77650
+ )), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React119__namespace.default.createElement(
77651
+ Textarea,
77652
+ {
77653
+ id: "bloomLevelsGuideline",
77654
+ value: formState.bloomLevelsGuideline?.join(
77655
+ ", "
77656
+ ) || "",
77657
+ onChange: (e2) => handleFormChange(
77658
+ "bloomLevelsGuideline",
77659
+ e2.target.value.split(",").map((s2) => s2.trim())
77660
+ )
77661
+ }
77662
+ ))), /* @__PURE__ */ React119__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React119__namespace.default.createElement(
77663
+ Button,
77664
+ {
77665
+ type: "button",
77666
+ variant: "outline",
77667
+ onClick: () => setIsDialogOpen(false),
77668
+ disabled: isPending
77669
+ },
77670
+ "Cancel"
77671
+ ), /* @__PURE__ */ React119__namespace.default.createElement(
77672
+ Button,
77673
+ {
77674
+ type: "submit",
77675
+ onClick: handleSubmit,
77676
+ disabled: isPending || !formState.name?.trim() || !formState.code?.trim()
77677
+ },
77678
+ isPending && /* @__PURE__ */ React119__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
77679
+ " ",
77680
+ "Save"
77681
+ )))), /* @__PURE__ */ React119__namespace.default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React119__namespace.default.createElement(
77682
+ AlertDialogAction2,
77683
+ {
77684
+ onClick: confirmDelete,
77685
+ disabled: isPending,
77686
+ className: "bg-destructive hover:bg-destructive/90"
77687
+ },
77688
+ isPending && /* @__PURE__ */ React119__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
77689
+ " ",
77690
+ "Delete"
77691
+ ))))));
77392
77692
  }
77393
77693
 
77394
77694
  // src/react-ui/components/metadata/ContextManager.tsx
@@ -2,7 +2,7 @@ export { B as BaseQuestion, e as BlocklyProgrammingQuestion, C as CodingQuestion
2
2
  export { APIKeyService, AchievementService, Approach, ApproachTableRawDifficulty, BloomLevelName, BloomLevelType, Category, CodeNamedEntity, Context, GEMINI_API_KEY_SERVICE_NAME, GradeLevel, KnowledgeCardService, KnowledgeDimension, LearningObjective, MetadataService, PracticeHistoryService, QuestionBankService, QuestionImportService, QuestionInBank, QuestionTypeType, QuizEditorService, QuizEngine, QuizEngineCallbacks, QuizEngineConstructorOptions, QuoteService, SCORMService, StandardDifficulty, Subject, Topic, UserConfigService, cn, emptyQuiz, exportQuizAsSCORMZip, generateLauncherHTML, generateSCORMManifest, generateUniqueId, sampleQuiz } from './index.cjs';
3
3
  export { i as Achievement, j as AchievementDefinition, r as ActivityCalendarData, u as AnalysisReport, A as AnswerDetail, x as ChatContext, C as ChatMessage, v as DashboardCardConfig, D as DashboardCardId, w as DashboardLayout, y as Goal, G as GoalType, t as ImageContextItem, I as ImportError, K as KnowledgeCard, L as LearningAnalysis, e as PerformanceByBloomLevel, b as PerformanceByCategory, d as PerformanceByDifficulty, P as PerformanceByLearningObjective, c as PerformanceByTopic, f as PerformanceMetric, s as PerformanceSummary, k as PracticeDifficulty, n as PracticeSession, p as PracticeSessionSummary, o as PracticeStats, m as PracticeSuggestion, l as PracticeSuggestionTopic, q as PracticeTopicSummary, g as QuestionReview, Q as QuizResultType, h as QuizReviewContent, R as RoadmapItem, T as TestCaseResult, U as UserAnswerType, a as UserAnswers, W as WeeklyRoadmap } from './ai-ecosystem-DyQYZbyX.cjs';
4
4
  export { AssessAndMapDocumentClientInput, AssessAndMapDocumentOutput, BloomLevelStringsForAI, GenerateCodingQuestionClientInput, GenerateCodingQuestionOutput, GenerateFillInTheBlanksQuestionClientInput, GenerateFillInTheBlanksQuestionOutput, GenerateLearningAnalysisClientInput, GenerateLearningAnalysisOutput, GenerateMCQQuestionClientInput, GenerateMCQQuestionOutput, GenerateMRQQuestionClientInput, GenerateMRQQuestionOutput, GenerateMatchingQuestionClientInput, GenerateMatchingQuestionOutput, GenerateMotivationalQuoteClientInput, GenerateMotivationalQuoteOutput, GenerateNumericQuestionClientInput, GenerateNumericQuestionOutput, GeneratePracticeSuggestionClientInput, GeneratePracticeSuggestionOutput, GenerateQuestionsFromQuizPlanClientInput, GenerateQuestionsFromQuizPlanOutput, GenerateQuizFromTextClientInput, GenerateQuizFromTextOutput, GenerateQuizPlanClientInput, GenerateQuizPlanOutput, GenerateQuizReviewClientInput, GenerateQuizReviewOutput, GenerateSequenceQuestionClientInput, GenerateSequenceQuestionOutput, GenerateShortAnswerQuestionClientInput, GenerateShortAnswerQuestionOutput, GenerateSingleKnowledgeCardClientInput, GenerateSingleKnowledgeCardOutput, GenerateTrueFalseQuestionClientInput, GenerateTrueFalseQuestionOutput, PlanKnowledgeCardsClientInput, PlanKnowledgeCardsOutput, PlannedQuestion, assessAndMapDocument, generateCodingQuestion, generateFillInTheBlanksQuestion, generateLearningAnalysis, generateMCQQuestion, generateMRQQuestion, generateMatchingQuestion, generateMotivationalQuote, generateNumericQuestion, generatePracticeSuggestion, generateQuestionsFromQuizPlan, generateQuizFromText, generateQuizPlan, generateQuizReview, generateSequenceQuestion, generateShortAnswerQuestion, generateSingleKnowledgeCard, generateTrueFalseQuestion, planKnowledgeCards } from './ai.cjs';
5
- export { c as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, e as APIKeyManagerModal, f as ApiKeySettings, m as ApproachManager, B as BloomLevelManager, C as CategoryManager, l as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, n as MetadataImportControls, M as MetadataTabs, h as QuestionFilters, i as QuestionFormDialog, g as QuestionList, a as QuestionPreviewModal, k as QuestionTypeManager, Q as QuizAuthoringTool, b as QuizSettingsForm, d as SCORMExportModal, S as SelectedQuestionsPanel, j as SubjectManager, o as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-BWaJj0l-.cjs';
5
+ export { c as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, e as APIKeyManagerModal, f as ApiKeySettings, m as ApproachManager, B as BloomLevelManager, C as CategoryManager, l as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, n as MetadataImportControls, M as MetadataTabs, h as QuestionFilters, i as QuestionFormDialog, g as QuestionList, a as QuestionPreviewModal, k as QuestionTypeManager, Q as QuizAuthoringTool, b as QuizSettingsForm, d as SCORMExportModal, S as SelectedQuestionsPanel, j as SubjectManager, o as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-6AR8w2TO.cjs';
6
6
  import 'clsx';
7
7
  import 'zod';
8
8
  import 'react';
@@ -2,7 +2,7 @@ export { B as BaseQuestion, e as BlocklyProgrammingQuestion, C as CodingQuestion
2
2
  export { APIKeyService, AchievementService, Approach, ApproachTableRawDifficulty, BloomLevelName, BloomLevelType, Category, CodeNamedEntity, Context, GEMINI_API_KEY_SERVICE_NAME, GradeLevel, KnowledgeCardService, KnowledgeDimension, LearningObjective, MetadataService, PracticeHistoryService, QuestionBankService, QuestionImportService, QuestionInBank, QuestionTypeType, QuizEditorService, QuizEngine, QuizEngineCallbacks, QuizEngineConstructorOptions, QuoteService, SCORMService, StandardDifficulty, Subject, Topic, UserConfigService, cn, emptyQuiz, exportQuizAsSCORMZip, generateLauncherHTML, generateSCORMManifest, generateUniqueId, sampleQuiz } from './index.js';
3
3
  export { i as Achievement, j as AchievementDefinition, r as ActivityCalendarData, u as AnalysisReport, A as AnswerDetail, x as ChatContext, C as ChatMessage, v as DashboardCardConfig, D as DashboardCardId, w as DashboardLayout, y as Goal, G as GoalType, t as ImageContextItem, I as ImportError, K as KnowledgeCard, L as LearningAnalysis, e as PerformanceByBloomLevel, b as PerformanceByCategory, d as PerformanceByDifficulty, P as PerformanceByLearningObjective, c as PerformanceByTopic, f as PerformanceMetric, s as PerformanceSummary, k as PracticeDifficulty, n as PracticeSession, p as PracticeSessionSummary, o as PracticeStats, m as PracticeSuggestion, l as PracticeSuggestionTopic, q as PracticeTopicSummary, g as QuestionReview, Q as QuizResultType, h as QuizReviewContent, R as RoadmapItem, T as TestCaseResult, U as UserAnswerType, a as UserAnswers, W as WeeklyRoadmap } from './ai-ecosystem-Qa_SdE2T.js';
4
4
  export { AssessAndMapDocumentClientInput, AssessAndMapDocumentOutput, BloomLevelStringsForAI, GenerateCodingQuestionClientInput, GenerateCodingQuestionOutput, GenerateFillInTheBlanksQuestionClientInput, GenerateFillInTheBlanksQuestionOutput, GenerateLearningAnalysisClientInput, GenerateLearningAnalysisOutput, GenerateMCQQuestionClientInput, GenerateMCQQuestionOutput, GenerateMRQQuestionClientInput, GenerateMRQQuestionOutput, GenerateMatchingQuestionClientInput, GenerateMatchingQuestionOutput, GenerateMotivationalQuoteClientInput, GenerateMotivationalQuoteOutput, GenerateNumericQuestionClientInput, GenerateNumericQuestionOutput, GeneratePracticeSuggestionClientInput, GeneratePracticeSuggestionOutput, GenerateQuestionsFromQuizPlanClientInput, GenerateQuestionsFromQuizPlanOutput, GenerateQuizFromTextClientInput, GenerateQuizFromTextOutput, GenerateQuizPlanClientInput, GenerateQuizPlanOutput, GenerateQuizReviewClientInput, GenerateQuizReviewOutput, GenerateSequenceQuestionClientInput, GenerateSequenceQuestionOutput, GenerateShortAnswerQuestionClientInput, GenerateShortAnswerQuestionOutput, GenerateSingleKnowledgeCardClientInput, GenerateSingleKnowledgeCardOutput, GenerateTrueFalseQuestionClientInput, GenerateTrueFalseQuestionOutput, PlanKnowledgeCardsClientInput, PlanKnowledgeCardsOutput, PlannedQuestion, assessAndMapDocument, generateCodingQuestion, generateFillInTheBlanksQuestion, generateLearningAnalysis, generateMCQQuestion, generateMRQQuestion, generateMatchingQuestion, generateMotivationalQuote, generateNumericQuestion, generatePracticeSuggestion, generateQuestionsFromQuizPlan, generateQuizFromText, generateQuizPlan, generateQuizReview, generateSequenceQuestion, generateShortAnswerQuestion, generateSingleKnowledgeCard, generateTrueFalseQuestion, planKnowledgeCards } from './ai.js';
5
- export { c as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, e as APIKeyManagerModal, f as ApiKeySettings, m as ApproachManager, B as BloomLevelManager, C as CategoryManager, l as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, n as MetadataImportControls, M as MetadataTabs, h as QuestionFilters, i as QuestionFormDialog, g as QuestionList, a as QuestionPreviewModal, k as QuestionTypeManager, Q as QuizAuthoringTool, b as QuizSettingsForm, d as SCORMExportModal, S as SelectedQuestionsPanel, j as SubjectManager, o as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-BVaUJA6E.js';
5
+ export { c as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, e as APIKeyManagerModal, f as ApiKeySettings, m as ApproachManager, B as BloomLevelManager, C as CategoryManager, l as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, n as MetadataImportControls, M as MetadataTabs, h as QuestionFilters, i as QuestionFormDialog, g as QuestionList, a as QuestionPreviewModal, k as QuestionTypeManager, Q as QuizAuthoringTool, b as QuizSettingsForm, d as SCORMExportModal, S as SelectedQuestionsPanel, j as SubjectManager, o as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-DAXYZdrz.js';
6
6
  import 'clsx';
7
7
  import 'zod';
8
8
  import 'react';