@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.
package/dist/react-ui.mjs CHANGED
@@ -138660,11 +138660,17 @@ function MetadataImportControls({ metadataName, onImport }) {
138660
138660
  const fileInputRef = useRef(null);
138661
138661
  const { toast: toast2 } = useToast();
138662
138662
  const processAndImportRecords = async (records, importSource) => {
138663
+ console.log(`[ImportControls] Processing ${records.length} records from ${importSource} for ${metadataName}.`);
138663
138664
  if (records.length === 0) {
138664
138665
  toast2({ title: "No Data", description: `The selected ${importSource === "file" ? "file" : "JSON string"} contains no data to import.`, variant: "destructive" });
138665
138666
  return;
138666
138667
  }
138667
- await onImport(records);
138668
+ try {
138669
+ await onImport(records);
138670
+ } catch (error) {
138671
+ console.error(`[ImportControls] Error during onImport callback for ${metadataName}:`, error);
138672
+ toast2({ title: "Import Failed", description: `An error occurred while saving the data: ${error instanceof Error ? error.message : String(error)}`, variant: "destructive" });
138673
+ }
138668
138674
  setIsOpen(false);
138669
138675
  setJsonString("");
138670
138676
  };
@@ -138696,8 +138702,10 @@ function MetadataImportControls({ metadataName, onImport }) {
138696
138702
  return record;
138697
138703
  });
138698
138704
  }
138705
+ console.log(`[ImportControls] File parsed successfully. Found ${records.length} records.`);
138699
138706
  await processAndImportRecords(records, "file");
138700
138707
  } catch (err) {
138708
+ console.error("[ImportControls] Error parsing file:", err);
138701
138709
  toast2({ title: "Import Error", description: `Failed to process file: ${err.message}`, variant: "destructive" });
138702
138710
  }
138703
138711
  });
@@ -139516,15 +139524,27 @@ function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onU
139516
139524
 
139517
139525
  // src/react-ui/components/metadata/LearningObjectiveManager.tsx
139518
139526
  init_react_shim();
139519
- function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
139527
+ function LearningObjectiveManager({
139528
+ initialData,
139529
+ subjects: subjectsProp,
139530
+ isLoading: isLoadingProp,
139531
+ onAdd,
139532
+ onUpdate,
139533
+ onDelete,
139534
+ onBulkAdd
139535
+ }) {
139520
139536
  const [items, setItems] = useState([]);
139521
139537
  const [subjects, setSubjects] = useState([]);
139522
139538
  const [isLoading, setIsLoading] = useState(true);
139523
139539
  const [isDialogOpen, setIsDialogOpen] = useState(false);
139524
139540
  const [isAlertOpen, setIsAlertOpen] = useState(false);
139525
- const [currentItem, setCurrentItem] = useState(null);
139541
+ const [currentItem, setCurrentItem] = useState(
139542
+ null
139543
+ );
139526
139544
  const [formState, setFormState] = useState({});
139527
- const [itemToDelete, setItemToDelete] = useState(null);
139545
+ const [itemToDelete, setItemToDelete] = useState(
139546
+ null
139547
+ );
139528
139548
  const [isPending, startTransition] = useTransition();
139529
139549
  const { toast: toast2 } = useToast();
139530
139550
  const isControlled = initialData !== void 0;
@@ -139535,7 +139555,11 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139535
139555
  setItems(MetadataService.getLearningObjectives());
139536
139556
  setSubjects(MetadataService.getSubjects());
139537
139557
  } catch (error) {
139538
- toast2({ title: "Error", description: "Failed to refresh data.", variant: "destructive" });
139558
+ toast2({
139559
+ title: "Error",
139560
+ description: "Failed to refresh data.",
139561
+ variant: "destructive"
139562
+ });
139539
139563
  } finally {
139540
139564
  setIsLoading(false);
139541
139565
  }
@@ -139555,7 +139579,9 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139555
139579
  };
139556
139580
  const handleAddItem = () => {
139557
139581
  setCurrentItem(null);
139558
- setFormState({ subjectCode: subjects.length > 0 ? subjects[0].code : "" });
139582
+ setFormState({
139583
+ subjectCode: subjects.length > 0 ? subjects[0].code : ""
139584
+ });
139559
139585
  setIsDialogOpen(true);
139560
139586
  };
139561
139587
  const handleEditItem = (item) => {
@@ -139577,9 +139603,16 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139577
139603
  MetadataService.deleteLearningObjective(itemToDelete.code);
139578
139604
  refreshData();
139579
139605
  }
139580
- toast2({ title: "Success", description: `Learning Objective "${itemToDelete.name}" deleted.` });
139606
+ toast2({
139607
+ title: "Success",
139608
+ description: `Learning Objective "${itemToDelete.name}" deleted.`
139609
+ });
139581
139610
  } catch (error) {
139582
- toast2({ title: "Error", description: error.message, variant: "destructive" });
139611
+ toast2({
139612
+ title: "Error",
139613
+ description: error.message,
139614
+ variant: "destructive"
139615
+ });
139583
139616
  } finally {
139584
139617
  setIsAlertOpen(false);
139585
139618
  setItemToDelete(null);
@@ -139588,7 +139621,11 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139588
139621
  };
139589
139622
  const handleSubmit = () => {
139590
139623
  if (!formState.name?.trim() || !formState.code?.trim()) {
139591
- toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
139624
+ toast2({
139625
+ title: "Validation Error",
139626
+ description: "Code and Name are required.",
139627
+ variant: "destructive"
139628
+ });
139592
139629
  return;
139593
139630
  }
139594
139631
  startTransition(async () => {
@@ -139597,28 +139634,291 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139597
139634
  if (isControlled && onUpdate) {
139598
139635
  await onUpdate({ ...currentItem, ...formState });
139599
139636
  } else {
139600
- MetadataService.updateLearningObjective(currentItem.id, formState);
139637
+ MetadataService.updateLearningObjective(
139638
+ currentItem.id,
139639
+ formState
139640
+ );
139601
139641
  refreshData();
139602
139642
  }
139603
- toast2({ title: "Success", description: "Learning Objective updated." });
139643
+ toast2({
139644
+ title: "Success",
139645
+ description: "Learning Objective updated."
139646
+ });
139604
139647
  } else {
139605
139648
  if (isControlled && onAdd) {
139606
139649
  await onAdd(formState);
139607
139650
  } else {
139608
- MetadataService.addLearningObjective(formState);
139651
+ MetadataService.addLearningObjective(
139652
+ formState
139653
+ );
139609
139654
  refreshData();
139610
139655
  }
139611
- toast2({ title: "Success", description: "Learning Objective added." });
139656
+ toast2({
139657
+ title: "Success",
139658
+ description: "Learning Objective added."
139659
+ });
139612
139660
  }
139613
139661
  setIsDialogOpen(false);
139614
139662
  } catch (error) {
139615
- toast2({ title: "Error", description: error.message, variant: "destructive" });
139663
+ toast2({
139664
+ title: "Error",
139665
+ description: error.message,
139666
+ variant: "destructive"
139667
+ });
139616
139668
  }
139617
139669
  });
139618
139670
  };
139619
139671
  const handleImport = async (records) => {
139672
+ console.log(
139673
+ `[LO Manager] handleImport called with ${records.length} raw records.`
139674
+ );
139675
+ if (!onBulkAdd) {
139676
+ console.error("[LO Manager] onBulkAdd handler is not provided.");
139677
+ return;
139678
+ }
139679
+ const parseStringToArray = (input) => {
139680
+ if (Array.isArray(input)) return input;
139681
+ if (typeof input === "string")
139682
+ return input.split(",").map((s4) => s4.trim()).filter(Boolean);
139683
+ return [];
139684
+ };
139685
+ const validationResult = records.reduce(
139686
+ (acc, rec) => {
139687
+ if (typeof rec["LO ID"] === "string" && rec["LO ID"].trim() && typeof rec["LO Description"] === "string" && rec["LO Description"].trim()) {
139688
+ acc.valid.push({
139689
+ code: rec["LO ID"],
139690
+ name: rec["LO ID"],
139691
+ description: rec["LO Description"],
139692
+ subject: rec["Subject"] || "",
139693
+ subjectCode: rec["Subject Code"] || rec["Subject"],
139694
+ category: rec["Category"] || "",
139695
+ categoryCode: rec["Category Code"] || rec["Category"],
139696
+ topic: rec["Topic"] || "",
139697
+ topicCode: rec["Topic Code"] || rec["Topic"],
139698
+ grade: rec["Grade"] || "",
139699
+ gradeCode: rec["Grade Code"] || rec["Grade"],
139700
+ keywords: parseStringToArray(rec["Keywords"]),
139701
+ stemElements: parseStringToArray(
139702
+ rec["STEM Element(s)"]
139703
+ ),
139704
+ bloomLevelsGuideline: parseStringToArray(
139705
+ rec["Bloom\u2019s Level(s) Guideline"]
139706
+ )
139707
+ });
139708
+ } else {
139709
+ acc.invalidCount++;
139710
+ }
139711
+ return acc;
139712
+ },
139713
+ { valid: [], invalidCount: 0 }
139714
+ );
139715
+ console.log(
139716
+ `[LO Manager] Validation complete. ${validationResult.valid.length} valid records found.`
139717
+ );
139718
+ if (validationResult.invalidCount > 0) {
139719
+ toast2({
139720
+ title: "Import Warning",
139721
+ description: `${validationResult.invalidCount} records had invalid or missing 'LO ID' or 'LO Description' fields and were ignored.`,
139722
+ variant: "destructive"
139723
+ });
139724
+ }
139725
+ if (validationResult.valid.length > 0) {
139726
+ console.log(
139727
+ "[LO Manager] Calling onBulkAdd prop with validated data..."
139728
+ );
139729
+ await onBulkAdd(validationResult.valid);
139730
+ } else {
139731
+ console.log("[LO Manager] No valid records to import.");
139732
+ }
139620
139733
  };
139621
- return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Learning Objectives"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__default.createElement(MetadataImportControls, { metadataName: "Learning Objectives", onImport: handleImport }), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e3) => handleFormChange("code", e3.target.value.toUpperCase()), disabled: !!currentItem })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React169__default.createElement(Input, { id: "name", value: formState.name || "", onChange: (e3) => handleFormChange("name", e3.target.value) }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "subject", value: formState.subject || "", onChange: (e3) => handleFormChange("subject", e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React169__default.createElement(EditableCombobox, { options: subjects.map((s4) => ({ value: s4.code, label: s4.name })), value: formState.subjectCode || "", onChange: (val) => handleFormChange("subjectCode", val), placeholder: "Select a subject..." }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "category", value: formState.category || "", onChange: (e3) => handleFormChange("category", e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "categoryCode", value: formState.categoryCode || "", onChange: (e3) => handleFormChange("categoryCode", e3.target.value) }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "topic", value: formState.topic || "", onChange: (e3) => handleFormChange("topic", e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "topicCode", value: formState.topicCode || "", onChange: (e3) => handleFormChange("topicCode", e3.target.value) }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "grade", value: formState.grade || "", onChange: (e3) => handleFormChange("grade", e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "gradeCode", value: formState.gradeCode || "", onChange: (e3) => handleFormChange("gradeCode", e3.target.value) }))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "keywords", value: formState.keywords?.join(", ") || "", onChange: (e3) => handleFormChange("keywords", e3.target.value.split(",").map((s4) => s4.trim())) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "stemElements", value: formState.stemElements?.join(", ") || "", onChange: (e3) => handleFormChange("stemElements", e3.target.value.split(",").map((s4) => s4.trim())) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "bloomLevelsGuideline", value: formState.bloomLevelsGuideline?.join(", ") || "", onChange: (e3) => handleFormChange("bloomLevelsGuideline", e3.target.value.split(",").map((s4) => s4.trim())) }))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !formState.name?.trim() || !formState.code?.trim() }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
139734
+ return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " ", "Manage Learning Objectives"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__default.createElement(
139735
+ MetadataImportControls,
139736
+ {
139737
+ metadataName: "Learning Objectives",
139738
+ onImport: handleImport
139739
+ }
139740
+ ), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(
139741
+ Button,
139742
+ {
139743
+ variant: "ghost",
139744
+ size: "icon",
139745
+ onClick: () => handleEditItem(item),
139746
+ className: "mr-2"
139747
+ },
139748
+ /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })
139749
+ ), /* @__PURE__ */ React169__default.createElement(
139750
+ Button,
139751
+ {
139752
+ variant: "ghost",
139753
+ size: "icon",
139754
+ onClick: () => handleDeleteItem(item),
139755
+ className: "text-destructive hover:text-destructive"
139756
+ },
139757
+ /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })
139758
+ ))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React169__default.createElement(
139759
+ Input,
139760
+ {
139761
+ id: "code",
139762
+ value: formState.code || "",
139763
+ onChange: (e3) => handleFormChange(
139764
+ "code",
139765
+ e3.target.value.toUpperCase()
139766
+ ),
139767
+ disabled: !!currentItem
139768
+ }
139769
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React169__default.createElement(
139770
+ Input,
139771
+ {
139772
+ id: "name",
139773
+ value: formState.name || "",
139774
+ onChange: (e3) => handleFormChange(
139775
+ "name",
139776
+ e3.target.value
139777
+ )
139778
+ }
139779
+ ))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React169__default.createElement(
139780
+ Input,
139781
+ {
139782
+ id: "subject",
139783
+ value: formState.subject || "",
139784
+ onChange: (e3) => handleFormChange(
139785
+ "subject",
139786
+ e3.target.value
139787
+ )
139788
+ }
139789
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React169__default.createElement(
139790
+ EditableCombobox,
139791
+ {
139792
+ options: subjects.map((s4) => ({
139793
+ value: s4.code,
139794
+ label: s4.name
139795
+ })),
139796
+ value: formState.subjectCode || "",
139797
+ onChange: (val) => handleFormChange("subjectCode", val),
139798
+ placeholder: "Select a subject..."
139799
+ }
139800
+ ))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React169__default.createElement(
139801
+ Input,
139802
+ {
139803
+ id: "category",
139804
+ value: formState.category || "",
139805
+ onChange: (e3) => handleFormChange(
139806
+ "category",
139807
+ e3.target.value
139808
+ )
139809
+ }
139810
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React169__default.createElement(
139811
+ Input,
139812
+ {
139813
+ id: "categoryCode",
139814
+ value: formState.categoryCode || "",
139815
+ onChange: (e3) => handleFormChange(
139816
+ "categoryCode",
139817
+ e3.target.value
139818
+ )
139819
+ }
139820
+ ))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React169__default.createElement(
139821
+ Input,
139822
+ {
139823
+ id: "topic",
139824
+ value: formState.topic || "",
139825
+ onChange: (e3) => handleFormChange(
139826
+ "topic",
139827
+ e3.target.value
139828
+ )
139829
+ }
139830
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React169__default.createElement(
139831
+ Input,
139832
+ {
139833
+ id: "topicCode",
139834
+ value: formState.topicCode || "",
139835
+ onChange: (e3) => handleFormChange(
139836
+ "topicCode",
139837
+ e3.target.value
139838
+ )
139839
+ }
139840
+ ))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React169__default.createElement(
139841
+ Input,
139842
+ {
139843
+ id: "grade",
139844
+ value: formState.grade || "",
139845
+ onChange: (e3) => handleFormChange(
139846
+ "grade",
139847
+ e3.target.value
139848
+ )
139849
+ }
139850
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React169__default.createElement(
139851
+ Input,
139852
+ {
139853
+ id: "gradeCode",
139854
+ value: formState.gradeCode || "",
139855
+ onChange: (e3) => handleFormChange(
139856
+ "gradeCode",
139857
+ e3.target.value
139858
+ )
139859
+ }
139860
+ ))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React169__default.createElement(
139861
+ Textarea,
139862
+ {
139863
+ id: "keywords",
139864
+ value: formState.keywords?.join(", ") || "",
139865
+ onChange: (e3) => handleFormChange(
139866
+ "keywords",
139867
+ e3.target.value.split(",").map((s4) => s4.trim())
139868
+ )
139869
+ }
139870
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React169__default.createElement(
139871
+ Textarea,
139872
+ {
139873
+ id: "stemElements",
139874
+ value: formState.stemElements?.join(", ") || "",
139875
+ onChange: (e3) => handleFormChange(
139876
+ "stemElements",
139877
+ e3.target.value.split(",").map((s4) => s4.trim())
139878
+ )
139879
+ }
139880
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React169__default.createElement(
139881
+ Textarea,
139882
+ {
139883
+ id: "bloomLevelsGuideline",
139884
+ value: formState.bloomLevelsGuideline?.join(
139885
+ ", "
139886
+ ) || "",
139887
+ onChange: (e3) => handleFormChange(
139888
+ "bloomLevelsGuideline",
139889
+ e3.target.value.split(",").map((s4) => s4.trim())
139890
+ )
139891
+ }
139892
+ ))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(
139893
+ Button,
139894
+ {
139895
+ type: "button",
139896
+ variant: "outline",
139897
+ onClick: () => setIsDialogOpen(false),
139898
+ disabled: isPending
139899
+ },
139900
+ "Cancel"
139901
+ ), /* @__PURE__ */ React169__default.createElement(
139902
+ Button,
139903
+ {
139904
+ type: "submit",
139905
+ onClick: handleSubmit,
139906
+ disabled: isPending || !formState.name?.trim() || !formState.code?.trim()
139907
+ },
139908
+ isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
139909
+ " ",
139910
+ "Save"
139911
+ )))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(
139912
+ AlertDialogAction2,
139913
+ {
139914
+ onClick: confirmDelete,
139915
+ disabled: isPending,
139916
+ className: "bg-destructive hover:bg-destructive/90"
139917
+ },
139918
+ isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
139919
+ " ",
139920
+ "Delete"
139921
+ ))))));
139622
139922
  }
139623
139923
 
139624
139924
  // src/react-ui/components/metadata/ContextManager.tsx
@@ -265,12 +265,12 @@ interface LearningObjectiveManagerProps {
265
265
  initialData?: LearningObjective[];
266
266
  subjects?: Subject[];
267
267
  isLoading?: boolean;
268
- onAdd?: (item: Omit<LearningObjective, 'id'>) => Promise<void>;
268
+ onAdd?: (item: Omit<LearningObjective, "id">) => Promise<void>;
269
269
  onUpdate?: (item: LearningObjective) => Promise<void>;
270
270
  onDelete?: (item: LearningObjective) => Promise<void>;
271
- onBulkAdd?: (items: Omit<LearningObjective, 'id'>[]) => Promise<void>;
271
+ onBulkAdd?: (items: Omit<LearningObjective, "id">[]) => Promise<void>;
272
272
  }
273
- declare function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }: LearningObjectiveManagerProps): React__default.JSX.Element;
273
+ declare function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd, }: LearningObjectiveManagerProps): React__default.JSX.Element;
274
274
 
275
275
  interface ContextManagerProps {
276
276
  initialData?: Context[];
@@ -265,12 +265,12 @@ interface LearningObjectiveManagerProps {
265
265
  initialData?: LearningObjective[];
266
266
  subjects?: Subject[];
267
267
  isLoading?: boolean;
268
- onAdd?: (item: Omit<LearningObjective, 'id'>) => Promise<void>;
268
+ onAdd?: (item: Omit<LearningObjective, "id">) => Promise<void>;
269
269
  onUpdate?: (item: LearningObjective) => Promise<void>;
270
270
  onDelete?: (item: LearningObjective) => Promise<void>;
271
- onBulkAdd?: (items: Omit<LearningObjective, 'id'>[]) => Promise<void>;
271
+ onBulkAdd?: (items: Omit<LearningObjective, "id">[]) => Promise<void>;
272
272
  }
273
- declare function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }: LearningObjectiveManagerProps): React__default.JSX.Element;
273
+ declare function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd, }: LearningObjectiveManagerProps): React__default.JSX.Element;
274
274
 
275
275
  interface ContextManagerProps {
276
276
  initialData?: Context[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thanh01.pmt/interactive-quiz-kit",
3
- "version": "1.0.70",
3
+ "version": "1.0.72",
4
4
  "description": "A comprehensive library for creating, managing, and playing interactive quizzes, with AI generation and SCORM support.",
5
5
  "keywords": [
6
6
  "react",