@thanh01.pmt/interactive-quiz-kit 1.0.71 → 1.0.73

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
@@ -101851,12 +101851,10 @@ init_react_shim();
101851
101851
  // src/services/TopicDataService.ts
101852
101852
  init_react_shim();
101853
101853
  var TopicDataService = class {
101854
- // ... saveData, mergeData, getData, clearData methods remain the same ...
101855
101854
  static saveData(data) {
101856
101855
  try {
101857
101856
  if (typeof window === "undefined") return;
101858
- const serializedData = JSON.stringify(data);
101859
- localStorage.setItem(this.STORAGE_KEY, serializedData);
101857
+ localStorage.setItem(this.STORAGE_KEY, JSON.stringify(data));
101860
101858
  } catch (error) {
101861
101859
  console.error("Error saving learning objectives to Local Storage:", error);
101862
101860
  }
@@ -101867,8 +101865,7 @@ var TopicDataService = class {
101867
101865
  newData.forEach((newLo) => {
101868
101866
  loMap.set(newLo.code, newLo);
101869
101867
  });
101870
- const mergedData = Array.from(loMap.values());
101871
- this.saveData(mergedData);
101868
+ this.saveData(Array.from(loMap.values()));
101872
101869
  }
101873
101870
  static getData() {
101874
101871
  try {
@@ -101883,7 +101880,7 @@ var TopicDataService = class {
101883
101880
  }
101884
101881
  static clearData() {
101885
101882
  try {
101886
- if (typeof window === "undefined") return;
101883
+ if (typeof window !== "undefined") return;
101887
101884
  localStorage.removeItem(this.STORAGE_KEY);
101888
101885
  } catch (error) {
101889
101886
  console.error("Error clearing learning objectives from Local Storage:", error);
@@ -101897,6 +101894,12 @@ var TopicDataService = class {
101897
101894
  const headerLine = lines.shift();
101898
101895
  const headers = headerLine.split(" ").map((h3) => h3.trim());
101899
101896
  const headerMap = headers.map((h3) => this.HEADER_MAP[h3] || null);
101897
+ const requiredHeaders = ["LO ID", "LO Name", "Subject", "Subject Code", "Category", "Category Code", "Topic", "Topic Code", "Grade", "Grade Code"];
101898
+ const missingHeaders = requiredHeaders.filter((h3) => !headers.includes(h3));
101899
+ if (missingHeaders.length > 0) {
101900
+ const errorMsg = `Invalid TSV header. Missing required columns: ${missingHeaders.join(", ")}`;
101901
+ return { data: [], errors: [errorMsg] };
101902
+ }
101900
101903
  const data = [];
101901
101904
  const errors2 = [];
101902
101905
  lines.forEach((line, index3) => {
@@ -101905,29 +101908,30 @@ var TopicDataService = class {
101905
101908
  headerMap.forEach((propName, i2) => {
101906
101909
  if (propName) {
101907
101910
  const value = values[i2]?.trim() || "";
101908
- if (propName === "keywords" || propName === "stemElements" || propName === "bloomLevelsGuideline") {
101911
+ if (["keywords", "stemElements", "bloomLevelsGuideline"].includes(propName)) {
101909
101912
  rowObject[propName] = value.split(",").map((s4) => s4.trim()).filter(Boolean);
101910
101913
  } else {
101911
101914
  rowObject[propName] = value;
101912
101915
  }
101913
101916
  }
101914
101917
  });
101915
- if (!rowObject.code) {
101916
- errors2.push(`Line ${index3 + 2}: Missing required value for 'LO ID'.`);
101918
+ if (!rowObject.code || !rowObject.name) {
101919
+ errors2.push(`Line ${index3 + 2}: Missing required values for 'LO ID' or 'LO Name'.`);
101917
101920
  return;
101918
101921
  }
101919
- if (!rowObject.name) {
101920
- rowObject.name = rowObject.code;
101921
- }
101922
101922
  const learningObjective = {
101923
101923
  id: generateUniqueId("lo_"),
101924
101924
  code: rowObject.code,
101925
101925
  name: rowObject.name,
101926
101926
  description: rowObject.description,
101927
101927
  subject: rowObject.subject || "",
101928
+ subjectCode: rowObject.subjectCode,
101928
101929
  category: rowObject.category || "",
101930
+ categoryCode: rowObject.categoryCode,
101929
101931
  topic: rowObject.topic || "",
101932
+ topicCode: rowObject.topicCode,
101930
101933
  grade: rowObject.grade || "",
101934
+ gradeCode: rowObject.gradeCode,
101931
101935
  keywords: rowObject.keywords || [],
101932
101936
  stemElements: rowObject.stemElements || [],
101933
101937
  bloomLevelsGuideline: rowObject.bloomLevelsGuideline || []
@@ -101958,17 +101962,23 @@ var TopicDataService = class {
101958
101962
  }
101959
101963
  };
101960
101964
  TopicDataService.STORAGE_KEY = "interactive_quiz_kit_learning_objectives";
101961
- // Define a map for flexible header mapping
101962
101965
  TopicDataService.HEADER_MAP = {
101963
101966
  "LO ID": "code",
101964
101967
  "LO Name": "name",
101965
- // Ready for future addition
101966
101968
  "LO Description": "description",
101967
101969
  "Subject": "subject",
101970
+ "Subject Code": "subjectCode",
101971
+ // New
101968
101972
  "Category": "category",
101973
+ "Category Code": "categoryCode",
101974
+ // New
101969
101975
  "Topic": "topic",
101976
+ "Topic Code": "topicCode",
101977
+ // New
101970
101978
  "Keywords": "keywords",
101971
101979
  "Grade": "grade",
101980
+ "Grade Code": "gradeCode",
101981
+ // New
101972
101982
  "STEM Element(s)": "stemElements",
101973
101983
  "Bloom\u2019s Level(s) Guideline": "bloomLevelsGuideline"
101974
101984
  };
@@ -139524,15 +139534,27 @@ function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onU
139524
139534
 
139525
139535
  // src/react-ui/components/metadata/LearningObjectiveManager.tsx
139526
139536
  init_react_shim();
139527
- function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
139537
+ function LearningObjectiveManager({
139538
+ initialData,
139539
+ subjects: subjectsProp,
139540
+ isLoading: isLoadingProp,
139541
+ onAdd,
139542
+ onUpdate,
139543
+ onDelete,
139544
+ onBulkAdd
139545
+ }) {
139528
139546
  const [items, setItems] = useState([]);
139529
139547
  const [subjects, setSubjects] = useState([]);
139530
139548
  const [isLoading, setIsLoading] = useState(true);
139531
139549
  const [isDialogOpen, setIsDialogOpen] = useState(false);
139532
139550
  const [isAlertOpen, setIsAlertOpen] = useState(false);
139533
- const [currentItem, setCurrentItem] = useState(null);
139551
+ const [currentItem, setCurrentItem] = useState(
139552
+ null
139553
+ );
139534
139554
  const [formState, setFormState] = useState({});
139535
- const [itemToDelete, setItemToDelete] = useState(null);
139555
+ const [itemToDelete, setItemToDelete] = useState(
139556
+ null
139557
+ );
139536
139558
  const [isPending, startTransition] = useTransition();
139537
139559
  const { toast: toast2 } = useToast();
139538
139560
  const isControlled = initialData !== void 0;
@@ -139543,7 +139565,11 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139543
139565
  setItems(MetadataService.getLearningObjectives());
139544
139566
  setSubjects(MetadataService.getSubjects());
139545
139567
  } catch (error) {
139546
- toast2({ title: "Error", description: "Failed to refresh data.", variant: "destructive" });
139568
+ toast2({
139569
+ title: "Error",
139570
+ description: "Failed to refresh data.",
139571
+ variant: "destructive"
139572
+ });
139547
139573
  } finally {
139548
139574
  setIsLoading(false);
139549
139575
  }
@@ -139563,7 +139589,9 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139563
139589
  };
139564
139590
  const handleAddItem = () => {
139565
139591
  setCurrentItem(null);
139566
- setFormState({ subjectCode: subjects.length > 0 ? subjects[0].code : "" });
139592
+ setFormState({
139593
+ subjectCode: subjects.length > 0 ? subjects[0].code : ""
139594
+ });
139567
139595
  setIsDialogOpen(true);
139568
139596
  };
139569
139597
  const handleEditItem = (item) => {
@@ -139585,9 +139613,16 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139585
139613
  MetadataService.deleteLearningObjective(itemToDelete.code);
139586
139614
  refreshData();
139587
139615
  }
139588
- toast2({ title: "Success", description: `Learning Objective "${itemToDelete.name}" deleted.` });
139616
+ toast2({
139617
+ title: "Success",
139618
+ description: `Learning Objective "${itemToDelete.name}" deleted.`
139619
+ });
139589
139620
  } catch (error) {
139590
- toast2({ title: "Error", description: error.message, variant: "destructive" });
139621
+ toast2({
139622
+ title: "Error",
139623
+ description: error.message,
139624
+ variant: "destructive"
139625
+ });
139591
139626
  } finally {
139592
139627
  setIsAlertOpen(false);
139593
139628
  setItemToDelete(null);
@@ -139596,7 +139631,11 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139596
139631
  };
139597
139632
  const handleSubmit = () => {
139598
139633
  if (!formState.name?.trim() || !formState.code?.trim()) {
139599
- toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
139634
+ toast2({
139635
+ title: "Validation Error",
139636
+ description: "Code and Name are required.",
139637
+ variant: "destructive"
139638
+ });
139600
139639
  return;
139601
139640
  }
139602
139641
  startTransition(async () => {
@@ -139605,75 +139644,291 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139605
139644
  if (isControlled && onUpdate) {
139606
139645
  await onUpdate({ ...currentItem, ...formState });
139607
139646
  } else {
139608
- MetadataService.updateLearningObjective(currentItem.id, formState);
139647
+ MetadataService.updateLearningObjective(
139648
+ currentItem.id,
139649
+ formState
139650
+ );
139609
139651
  refreshData();
139610
139652
  }
139611
- toast2({ title: "Success", description: "Learning Objective updated." });
139653
+ toast2({
139654
+ title: "Success",
139655
+ description: "Learning Objective updated."
139656
+ });
139612
139657
  } else {
139613
139658
  if (isControlled && onAdd) {
139614
139659
  await onAdd(formState);
139615
139660
  } else {
139616
- MetadataService.addLearningObjective(formState);
139661
+ MetadataService.addLearningObjective(
139662
+ formState
139663
+ );
139617
139664
  refreshData();
139618
139665
  }
139619
- toast2({ title: "Success", description: "Learning Objective added." });
139666
+ toast2({
139667
+ title: "Success",
139668
+ description: "Learning Objective added."
139669
+ });
139620
139670
  }
139621
139671
  setIsDialogOpen(false);
139622
139672
  } catch (error) {
139623
- toast2({ title: "Error", description: error.message, variant: "destructive" });
139673
+ toast2({
139674
+ title: "Error",
139675
+ description: error.message,
139676
+ variant: "destructive"
139677
+ });
139624
139678
  }
139625
139679
  });
139626
139680
  };
139627
139681
  const handleImport = async (records) => {
139628
- console.log(`[LO Manager] handleImport called with ${records.length} raw records.`);
139682
+ console.log(
139683
+ `[LO Manager] handleImport called with ${records.length} raw records.`
139684
+ );
139629
139685
  if (!onBulkAdd) {
139630
139686
  console.error("[LO Manager] onBulkAdd handler is not provided.");
139631
139687
  return;
139632
139688
  }
139633
139689
  const parseStringToArray = (input) => {
139634
139690
  if (Array.isArray(input)) return input;
139635
- if (typeof input === "string") return input.split(",").map((s4) => s4.trim()).filter(Boolean);
139691
+ if (typeof input === "string")
139692
+ return input.split(",").map((s4) => s4.trim()).filter(Boolean);
139636
139693
  return [];
139637
139694
  };
139638
- const validationResult = records.reduce((acc, rec) => {
139639
- if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
139640
- acc.valid.push({
139641
- code: rec.code,
139642
- name: rec.name,
139643
- description: rec.description || rec.name,
139644
- subject: rec.subject || "",
139645
- subjectCode: rec.subjectCode,
139646
- category: rec.category || "",
139647
- categoryCode: rec.categoryCode,
139648
- topic: rec.topic || "",
139649
- topicCode: rec.topicCode,
139650
- grade: rec.grade || "",
139651
- gradeCode: rec.gradeCode,
139652
- keywords: parseStringToArray(rec.keywords),
139653
- stemElements: parseStringToArray(rec.stemElements),
139654
- bloomLevelsGuideline: parseStringToArray(rec.bloomLevelsGuideline)
139655
- });
139656
- } else {
139657
- acc.invalidCount++;
139658
- }
139659
- return acc;
139660
- }, { valid: [], invalidCount: 0 });
139661
- console.log(`[LO Manager] Validation complete. ${validationResult.valid.length} valid records found.`);
139695
+ const validationResult = records.reduce(
139696
+ (acc, rec) => {
139697
+ if (typeof rec["LO ID"] === "string" && rec["LO ID"].trim() && typeof rec["LO Description"] === "string" && rec["LO Description"].trim()) {
139698
+ acc.valid.push({
139699
+ code: rec["LO ID"],
139700
+ name: rec["LO ID"],
139701
+ description: rec["LO Description"],
139702
+ subject: rec["Subject"] || "",
139703
+ subjectCode: rec["Subject Code"] || rec["Subject"],
139704
+ category: rec["Category"] || "",
139705
+ categoryCode: rec["Category Code"] || rec["Category"],
139706
+ topic: rec["Topic"] || "",
139707
+ topicCode: rec["Topic Code"] || rec["Topic"],
139708
+ grade: rec["Grade"] || "",
139709
+ gradeCode: rec["Grade Code"] || rec["Grade"],
139710
+ keywords: parseStringToArray(rec["Keywords"]),
139711
+ stemElements: parseStringToArray(
139712
+ rec["STEM Element(s)"]
139713
+ ),
139714
+ bloomLevelsGuideline: parseStringToArray(
139715
+ rec["Bloom\u2019s Level(s) Guideline"]
139716
+ )
139717
+ });
139718
+ } else {
139719
+ acc.invalidCount++;
139720
+ }
139721
+ return acc;
139722
+ },
139723
+ { valid: [], invalidCount: 0 }
139724
+ );
139725
+ console.log(
139726
+ `[LO Manager] Validation complete. ${validationResult.valid.length} valid records found.`
139727
+ );
139662
139728
  if (validationResult.invalidCount > 0) {
139663
139729
  toast2({
139664
139730
  title: "Import Warning",
139665
- description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
139731
+ description: `${validationResult.invalidCount} records had invalid or missing 'LO ID' or 'LO Description' fields and were ignored.`,
139666
139732
  variant: "destructive"
139667
139733
  });
139668
139734
  }
139669
139735
  if (validationResult.valid.length > 0) {
139670
- console.log("[LO Manager] Calling onBulkAdd prop with validated data...");
139736
+ console.log(
139737
+ "[LO Manager] Calling onBulkAdd prop with validated data..."
139738
+ );
139671
139739
  await onBulkAdd(validationResult.valid);
139672
139740
  } else {
139673
139741
  console.log("[LO Manager] No valid records to import.");
139674
139742
  }
139675
139743
  };
139676
- 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"))))));
139744
+ 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(
139745
+ MetadataImportControls,
139746
+ {
139747
+ metadataName: "Learning Objectives",
139748
+ onImport: handleImport
139749
+ }
139750
+ ), /* @__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(
139751
+ Button,
139752
+ {
139753
+ variant: "ghost",
139754
+ size: "icon",
139755
+ onClick: () => handleEditItem(item),
139756
+ className: "mr-2"
139757
+ },
139758
+ /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })
139759
+ ), /* @__PURE__ */ React169__default.createElement(
139760
+ Button,
139761
+ {
139762
+ variant: "ghost",
139763
+ size: "icon",
139764
+ onClick: () => handleDeleteItem(item),
139765
+ className: "text-destructive hover:text-destructive"
139766
+ },
139767
+ /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })
139768
+ ))))))), /* @__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(
139769
+ Input,
139770
+ {
139771
+ id: "code",
139772
+ value: formState.code || "",
139773
+ onChange: (e3) => handleFormChange(
139774
+ "code",
139775
+ e3.target.value.toUpperCase()
139776
+ ),
139777
+ disabled: !!currentItem
139778
+ }
139779
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React169__default.createElement(
139780
+ Input,
139781
+ {
139782
+ id: "name",
139783
+ value: formState.name || "",
139784
+ onChange: (e3) => handleFormChange(
139785
+ "name",
139786
+ e3.target.value
139787
+ )
139788
+ }
139789
+ ))), /* @__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(
139790
+ Input,
139791
+ {
139792
+ id: "subject",
139793
+ value: formState.subject || "",
139794
+ onChange: (e3) => handleFormChange(
139795
+ "subject",
139796
+ e3.target.value
139797
+ )
139798
+ }
139799
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React169__default.createElement(
139800
+ EditableCombobox,
139801
+ {
139802
+ options: subjects.map((s4) => ({
139803
+ value: s4.code,
139804
+ label: s4.name
139805
+ })),
139806
+ value: formState.subjectCode || "",
139807
+ onChange: (val) => handleFormChange("subjectCode", val),
139808
+ placeholder: "Select a subject..."
139809
+ }
139810
+ ))), /* @__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(
139811
+ Input,
139812
+ {
139813
+ id: "category",
139814
+ value: formState.category || "",
139815
+ onChange: (e3) => handleFormChange(
139816
+ "category",
139817
+ e3.target.value
139818
+ )
139819
+ }
139820
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React169__default.createElement(
139821
+ Input,
139822
+ {
139823
+ id: "categoryCode",
139824
+ value: formState.categoryCode || "",
139825
+ onChange: (e3) => handleFormChange(
139826
+ "categoryCode",
139827
+ e3.target.value
139828
+ )
139829
+ }
139830
+ ))), /* @__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(
139831
+ Input,
139832
+ {
139833
+ id: "topic",
139834
+ value: formState.topic || "",
139835
+ onChange: (e3) => handleFormChange(
139836
+ "topic",
139837
+ e3.target.value
139838
+ )
139839
+ }
139840
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React169__default.createElement(
139841
+ Input,
139842
+ {
139843
+ id: "topicCode",
139844
+ value: formState.topicCode || "",
139845
+ onChange: (e3) => handleFormChange(
139846
+ "topicCode",
139847
+ e3.target.value
139848
+ )
139849
+ }
139850
+ ))), /* @__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(
139851
+ Input,
139852
+ {
139853
+ id: "grade",
139854
+ value: formState.grade || "",
139855
+ onChange: (e3) => handleFormChange(
139856
+ "grade",
139857
+ e3.target.value
139858
+ )
139859
+ }
139860
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React169__default.createElement(
139861
+ Input,
139862
+ {
139863
+ id: "gradeCode",
139864
+ value: formState.gradeCode || "",
139865
+ onChange: (e3) => handleFormChange(
139866
+ "gradeCode",
139867
+ e3.target.value
139868
+ )
139869
+ }
139870
+ ))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React169__default.createElement(
139871
+ Textarea,
139872
+ {
139873
+ id: "keywords",
139874
+ value: formState.keywords?.join(", ") || "",
139875
+ onChange: (e3) => handleFormChange(
139876
+ "keywords",
139877
+ e3.target.value.split(",").map((s4) => s4.trim())
139878
+ )
139879
+ }
139880
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React169__default.createElement(
139881
+ Textarea,
139882
+ {
139883
+ id: "stemElements",
139884
+ value: formState.stemElements?.join(", ") || "",
139885
+ onChange: (e3) => handleFormChange(
139886
+ "stemElements",
139887
+ e3.target.value.split(",").map((s4) => s4.trim())
139888
+ )
139889
+ }
139890
+ )), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React169__default.createElement(
139891
+ Textarea,
139892
+ {
139893
+ id: "bloomLevelsGuideline",
139894
+ value: formState.bloomLevelsGuideline?.join(
139895
+ ", "
139896
+ ) || "",
139897
+ onChange: (e3) => handleFormChange(
139898
+ "bloomLevelsGuideline",
139899
+ e3.target.value.split(",").map((s4) => s4.trim())
139900
+ )
139901
+ }
139902
+ ))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(
139903
+ Button,
139904
+ {
139905
+ type: "button",
139906
+ variant: "outline",
139907
+ onClick: () => setIsDialogOpen(false),
139908
+ disabled: isPending
139909
+ },
139910
+ "Cancel"
139911
+ ), /* @__PURE__ */ React169__default.createElement(
139912
+ Button,
139913
+ {
139914
+ type: "submit",
139915
+ onClick: handleSubmit,
139916
+ disabled: isPending || !formState.name?.trim() || !formState.code?.trim()
139917
+ },
139918
+ isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
139919
+ " ",
139920
+ "Save"
139921
+ )))), /* @__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(
139922
+ AlertDialogAction2,
139923
+ {
139924
+ onClick: confirmDelete,
139925
+ disabled: isPending,
139926
+ className: "bg-destructive hover:bg-destructive/90"
139927
+ },
139928
+ isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
139929
+ " ",
139930
+ "Delete"
139931
+ ))))));
139677
139932
  }
139678
139933
 
139679
139934
  // 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.71",
3
+ "version": "1.0.73",
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",