@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.cjs CHANGED
@@ -101917,12 +101917,10 @@ init_react_shim();
101917
101917
  // src/services/TopicDataService.ts
101918
101918
  init_react_shim();
101919
101919
  var TopicDataService = class {
101920
- // ... saveData, mergeData, getData, clearData methods remain the same ...
101921
101920
  static saveData(data) {
101922
101921
  try {
101923
101922
  if (typeof window === "undefined") return;
101924
- const serializedData = JSON.stringify(data);
101925
- localStorage.setItem(this.STORAGE_KEY, serializedData);
101923
+ localStorage.setItem(this.STORAGE_KEY, JSON.stringify(data));
101926
101924
  } catch (error) {
101927
101925
  console.error("Error saving learning objectives to Local Storage:", error);
101928
101926
  }
@@ -101933,8 +101931,7 @@ var TopicDataService = class {
101933
101931
  newData.forEach((newLo) => {
101934
101932
  loMap.set(newLo.code, newLo);
101935
101933
  });
101936
- const mergedData = Array.from(loMap.values());
101937
- this.saveData(mergedData);
101934
+ this.saveData(Array.from(loMap.values()));
101938
101935
  }
101939
101936
  static getData() {
101940
101937
  try {
@@ -101949,7 +101946,7 @@ var TopicDataService = class {
101949
101946
  }
101950
101947
  static clearData() {
101951
101948
  try {
101952
- if (typeof window === "undefined") return;
101949
+ if (typeof window !== "undefined") return;
101953
101950
  localStorage.removeItem(this.STORAGE_KEY);
101954
101951
  } catch (error) {
101955
101952
  console.error("Error clearing learning objectives from Local Storage:", error);
@@ -101963,6 +101960,12 @@ var TopicDataService = class {
101963
101960
  const headerLine = lines.shift();
101964
101961
  const headers = headerLine.split(" ").map((h3) => h3.trim());
101965
101962
  const headerMap = headers.map((h3) => this.HEADER_MAP[h3] || null);
101963
+ const requiredHeaders = ["LO ID", "LO Name", "Subject", "Subject Code", "Category", "Category Code", "Topic", "Topic Code", "Grade", "Grade Code"];
101964
+ const missingHeaders = requiredHeaders.filter((h3) => !headers.includes(h3));
101965
+ if (missingHeaders.length > 0) {
101966
+ const errorMsg = `Invalid TSV header. Missing required columns: ${missingHeaders.join(", ")}`;
101967
+ return { data: [], errors: [errorMsg] };
101968
+ }
101966
101969
  const data = [];
101967
101970
  const errors2 = [];
101968
101971
  lines.forEach((line, index3) => {
@@ -101971,29 +101974,30 @@ var TopicDataService = class {
101971
101974
  headerMap.forEach((propName, i2) => {
101972
101975
  if (propName) {
101973
101976
  const value = values[i2]?.trim() || "";
101974
- if (propName === "keywords" || propName === "stemElements" || propName === "bloomLevelsGuideline") {
101977
+ if (["keywords", "stemElements", "bloomLevelsGuideline"].includes(propName)) {
101975
101978
  rowObject[propName] = value.split(",").map((s4) => s4.trim()).filter(Boolean);
101976
101979
  } else {
101977
101980
  rowObject[propName] = value;
101978
101981
  }
101979
101982
  }
101980
101983
  });
101981
- if (!rowObject.code) {
101982
- errors2.push(`Line ${index3 + 2}: Missing required value for 'LO ID'.`);
101984
+ if (!rowObject.code || !rowObject.name) {
101985
+ errors2.push(`Line ${index3 + 2}: Missing required values for 'LO ID' or 'LO Name'.`);
101983
101986
  return;
101984
101987
  }
101985
- if (!rowObject.name) {
101986
- rowObject.name = rowObject.code;
101987
- }
101988
101988
  const learningObjective = {
101989
101989
  id: generateUniqueId("lo_"),
101990
101990
  code: rowObject.code,
101991
101991
  name: rowObject.name,
101992
101992
  description: rowObject.description,
101993
101993
  subject: rowObject.subject || "",
101994
+ subjectCode: rowObject.subjectCode,
101994
101995
  category: rowObject.category || "",
101996
+ categoryCode: rowObject.categoryCode,
101995
101997
  topic: rowObject.topic || "",
101998
+ topicCode: rowObject.topicCode,
101996
101999
  grade: rowObject.grade || "",
102000
+ gradeCode: rowObject.gradeCode,
101997
102001
  keywords: rowObject.keywords || [],
101998
102002
  stemElements: rowObject.stemElements || [],
101999
102003
  bloomLevelsGuideline: rowObject.bloomLevelsGuideline || []
@@ -102024,17 +102028,23 @@ var TopicDataService = class {
102024
102028
  }
102025
102029
  };
102026
102030
  TopicDataService.STORAGE_KEY = "interactive_quiz_kit_learning_objectives";
102027
- // Define a map for flexible header mapping
102028
102031
  TopicDataService.HEADER_MAP = {
102029
102032
  "LO ID": "code",
102030
102033
  "LO Name": "name",
102031
- // Ready for future addition
102032
102034
  "LO Description": "description",
102033
102035
  "Subject": "subject",
102036
+ "Subject Code": "subjectCode",
102037
+ // New
102034
102038
  "Category": "category",
102039
+ "Category Code": "categoryCode",
102040
+ // New
102035
102041
  "Topic": "topic",
102042
+ "Topic Code": "topicCode",
102043
+ // New
102036
102044
  "Keywords": "keywords",
102037
102045
  "Grade": "grade",
102046
+ "Grade Code": "gradeCode",
102047
+ // New
102038
102048
  "STEM Element(s)": "stemElements",
102039
102049
  "Bloom\u2019s Level(s) Guideline": "bloomLevelsGuideline"
102040
102050
  };
@@ -139590,15 +139600,27 @@ function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onU
139590
139600
 
139591
139601
  // src/react-ui/components/metadata/LearningObjectiveManager.tsx
139592
139602
  init_react_shim();
139593
- function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
139603
+ function LearningObjectiveManager({
139604
+ initialData,
139605
+ subjects: subjectsProp,
139606
+ isLoading: isLoadingProp,
139607
+ onAdd,
139608
+ onUpdate,
139609
+ onDelete,
139610
+ onBulkAdd
139611
+ }) {
139594
139612
  const [items, setItems] = React169.useState([]);
139595
139613
  const [subjects, setSubjects] = React169.useState([]);
139596
139614
  const [isLoading, setIsLoading] = React169.useState(true);
139597
139615
  const [isDialogOpen, setIsDialogOpen] = React169.useState(false);
139598
139616
  const [isAlertOpen, setIsAlertOpen] = React169.useState(false);
139599
- const [currentItem, setCurrentItem] = React169.useState(null);
139617
+ const [currentItem, setCurrentItem] = React169.useState(
139618
+ null
139619
+ );
139600
139620
  const [formState, setFormState] = React169.useState({});
139601
- const [itemToDelete, setItemToDelete] = React169.useState(null);
139621
+ const [itemToDelete, setItemToDelete] = React169.useState(
139622
+ null
139623
+ );
139602
139624
  const [isPending, startTransition] = React169.useTransition();
139603
139625
  const { toast: toast2 } = useToast();
139604
139626
  const isControlled = initialData !== void 0;
@@ -139609,7 +139631,11 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139609
139631
  setItems(MetadataService.getLearningObjectives());
139610
139632
  setSubjects(MetadataService.getSubjects());
139611
139633
  } catch (error) {
139612
- toast2({ title: "Error", description: "Failed to refresh data.", variant: "destructive" });
139634
+ toast2({
139635
+ title: "Error",
139636
+ description: "Failed to refresh data.",
139637
+ variant: "destructive"
139638
+ });
139613
139639
  } finally {
139614
139640
  setIsLoading(false);
139615
139641
  }
@@ -139629,7 +139655,9 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139629
139655
  };
139630
139656
  const handleAddItem = () => {
139631
139657
  setCurrentItem(null);
139632
- setFormState({ subjectCode: subjects.length > 0 ? subjects[0].code : "" });
139658
+ setFormState({
139659
+ subjectCode: subjects.length > 0 ? subjects[0].code : ""
139660
+ });
139633
139661
  setIsDialogOpen(true);
139634
139662
  };
139635
139663
  const handleEditItem = (item) => {
@@ -139651,9 +139679,16 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139651
139679
  MetadataService.deleteLearningObjective(itemToDelete.code);
139652
139680
  refreshData();
139653
139681
  }
139654
- toast2({ title: "Success", description: `Learning Objective "${itemToDelete.name}" deleted.` });
139682
+ toast2({
139683
+ title: "Success",
139684
+ description: `Learning Objective "${itemToDelete.name}" deleted.`
139685
+ });
139655
139686
  } catch (error) {
139656
- toast2({ title: "Error", description: error.message, variant: "destructive" });
139687
+ toast2({
139688
+ title: "Error",
139689
+ description: error.message,
139690
+ variant: "destructive"
139691
+ });
139657
139692
  } finally {
139658
139693
  setIsAlertOpen(false);
139659
139694
  setItemToDelete(null);
@@ -139662,7 +139697,11 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139662
139697
  };
139663
139698
  const handleSubmit = () => {
139664
139699
  if (!formState.name?.trim() || !formState.code?.trim()) {
139665
- toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
139700
+ toast2({
139701
+ title: "Validation Error",
139702
+ description: "Code and Name are required.",
139703
+ variant: "destructive"
139704
+ });
139666
139705
  return;
139667
139706
  }
139668
139707
  startTransition(async () => {
@@ -139671,75 +139710,291 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
139671
139710
  if (isControlled && onUpdate) {
139672
139711
  await onUpdate({ ...currentItem, ...formState });
139673
139712
  } else {
139674
- MetadataService.updateLearningObjective(currentItem.id, formState);
139713
+ MetadataService.updateLearningObjective(
139714
+ currentItem.id,
139715
+ formState
139716
+ );
139675
139717
  refreshData();
139676
139718
  }
139677
- toast2({ title: "Success", description: "Learning Objective updated." });
139719
+ toast2({
139720
+ title: "Success",
139721
+ description: "Learning Objective updated."
139722
+ });
139678
139723
  } else {
139679
139724
  if (isControlled && onAdd) {
139680
139725
  await onAdd(formState);
139681
139726
  } else {
139682
- MetadataService.addLearningObjective(formState);
139727
+ MetadataService.addLearningObjective(
139728
+ formState
139729
+ );
139683
139730
  refreshData();
139684
139731
  }
139685
- toast2({ title: "Success", description: "Learning Objective added." });
139732
+ toast2({
139733
+ title: "Success",
139734
+ description: "Learning Objective added."
139735
+ });
139686
139736
  }
139687
139737
  setIsDialogOpen(false);
139688
139738
  } catch (error) {
139689
- toast2({ title: "Error", description: error.message, variant: "destructive" });
139739
+ toast2({
139740
+ title: "Error",
139741
+ description: error.message,
139742
+ variant: "destructive"
139743
+ });
139690
139744
  }
139691
139745
  });
139692
139746
  };
139693
139747
  const handleImport = async (records) => {
139694
- console.log(`[LO Manager] handleImport called with ${records.length} raw records.`);
139748
+ console.log(
139749
+ `[LO Manager] handleImport called with ${records.length} raw records.`
139750
+ );
139695
139751
  if (!onBulkAdd) {
139696
139752
  console.error("[LO Manager] onBulkAdd handler is not provided.");
139697
139753
  return;
139698
139754
  }
139699
139755
  const parseStringToArray = (input) => {
139700
139756
  if (Array.isArray(input)) return input;
139701
- if (typeof input === "string") return input.split(",").map((s4) => s4.trim()).filter(Boolean);
139757
+ if (typeof input === "string")
139758
+ return input.split(",").map((s4) => s4.trim()).filter(Boolean);
139702
139759
  return [];
139703
139760
  };
139704
- const validationResult = records.reduce((acc, rec) => {
139705
- if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
139706
- acc.valid.push({
139707
- code: rec.code,
139708
- name: rec.name,
139709
- description: rec.description || rec.name,
139710
- subject: rec.subject || "",
139711
- subjectCode: rec.subjectCode,
139712
- category: rec.category || "",
139713
- categoryCode: rec.categoryCode,
139714
- topic: rec.topic || "",
139715
- topicCode: rec.topicCode,
139716
- grade: rec.grade || "",
139717
- gradeCode: rec.gradeCode,
139718
- keywords: parseStringToArray(rec.keywords),
139719
- stemElements: parseStringToArray(rec.stemElements),
139720
- bloomLevelsGuideline: parseStringToArray(rec.bloomLevelsGuideline)
139721
- });
139722
- } else {
139723
- acc.invalidCount++;
139724
- }
139725
- return acc;
139726
- }, { valid: [], invalidCount: 0 });
139727
- console.log(`[LO Manager] Validation complete. ${validationResult.valid.length} valid records found.`);
139761
+ const validationResult = records.reduce(
139762
+ (acc, rec) => {
139763
+ if (typeof rec["LO ID"] === "string" && rec["LO ID"].trim() && typeof rec["LO Description"] === "string" && rec["LO Description"].trim()) {
139764
+ acc.valid.push({
139765
+ code: rec["LO ID"],
139766
+ name: rec["LO ID"],
139767
+ description: rec["LO Description"],
139768
+ subject: rec["Subject"] || "",
139769
+ subjectCode: rec["Subject Code"] || rec["Subject"],
139770
+ category: rec["Category"] || "",
139771
+ categoryCode: rec["Category Code"] || rec["Category"],
139772
+ topic: rec["Topic"] || "",
139773
+ topicCode: rec["Topic Code"] || rec["Topic"],
139774
+ grade: rec["Grade"] || "",
139775
+ gradeCode: rec["Grade Code"] || rec["Grade"],
139776
+ keywords: parseStringToArray(rec["Keywords"]),
139777
+ stemElements: parseStringToArray(
139778
+ rec["STEM Element(s)"]
139779
+ ),
139780
+ bloomLevelsGuideline: parseStringToArray(
139781
+ rec["Bloom\u2019s Level(s) Guideline"]
139782
+ )
139783
+ });
139784
+ } else {
139785
+ acc.invalidCount++;
139786
+ }
139787
+ return acc;
139788
+ },
139789
+ { valid: [], invalidCount: 0 }
139790
+ );
139791
+ console.log(
139792
+ `[LO Manager] Validation complete. ${validationResult.valid.length} valid records found.`
139793
+ );
139728
139794
  if (validationResult.invalidCount > 0) {
139729
139795
  toast2({
139730
139796
  title: "Import Warning",
139731
- description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
139797
+ description: `${validationResult.invalidCount} records had invalid or missing 'LO ID' or 'LO Description' fields and were ignored.`,
139732
139798
  variant: "destructive"
139733
139799
  });
139734
139800
  }
139735
139801
  if (validationResult.valid.length > 0) {
139736
- console.log("[LO Manager] Calling onBulkAdd prop with validated data...");
139802
+ console.log(
139803
+ "[LO Manager] Calling onBulkAdd prop with validated data..."
139804
+ );
139737
139805
  await onBulkAdd(validationResult.valid);
139738
139806
  } else {
139739
139807
  console.log("[LO Manager] No valid records to import.");
139740
139808
  }
139741
139809
  };
139742
- return /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Learning Objectives"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__namespace.default.createElement(MetadataImportControls, { metadataName: "Learning Objectives", onImport: handleImport }), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__namespace.default.createElement(Table3, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__namespace.default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__namespace.default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e3) => handleFormChange("code", e3.target.value.toUpperCase()), disabled: !!currentItem })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "name", value: formState.name || "", onChange: (e3) => handleFormChange("name", e3.target.value) }))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "subject", value: formState.subject || "", onChange: (e3) => handleFormChange("subject", e3.target.value) })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React169__namespace.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__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "category", value: formState.category || "", onChange: (e3) => handleFormChange("category", e3.target.value) })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "categoryCode", value: formState.categoryCode || "", onChange: (e3) => handleFormChange("categoryCode", e3.target.value) }))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "topic", value: formState.topic || "", onChange: (e3) => handleFormChange("topic", e3.target.value) })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "topicCode", value: formState.topicCode || "", onChange: (e3) => handleFormChange("topicCode", e3.target.value) }))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "grade", value: formState.grade || "", onChange: (e3) => handleFormChange("grade", e3.target.value) })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "gradeCode", value: formState.gradeCode || "", onChange: (e3) => handleFormChange("gradeCode", e3.target.value) }))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "keywords", value: formState.keywords?.join(", ") || "", onChange: (e3) => handleFormChange("keywords", e3.target.value.split(",").map((s4) => s4.trim())) })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "stemElements", value: formState.stemElements?.join(", ") || "", onChange: (e3) => handleFormChange("stemElements", e3.target.value.split(",").map((s4) => s4.trim())) })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "bloomLevelsGuideline", value: formState.bloomLevelsGuideline?.join(", ") || "", onChange: (e3) => handleFormChange("bloomLevelsGuideline", e3.target.value.split(",").map((s4) => s4.trim())) }))), /* @__PURE__ */ React169__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !formState.name?.trim() || !formState.code?.trim() }, isPending && /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
139810
+ return /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " ", "Manage Learning Objectives"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__namespace.default.createElement(
139811
+ MetadataImportControls,
139812
+ {
139813
+ metadataName: "Learning Objectives",
139814
+ onImport: handleImport
139815
+ }
139816
+ ), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__namespace.default.createElement(Table3, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__namespace.default.createElement(
139817
+ Button,
139818
+ {
139819
+ variant: "ghost",
139820
+ size: "icon",
139821
+ onClick: () => handleEditItem(item),
139822
+ className: "mr-2"
139823
+ },
139824
+ /* @__PURE__ */ React169__namespace.default.createElement(PenLine, { className: "h-4 w-4" })
139825
+ ), /* @__PURE__ */ React169__namespace.default.createElement(
139826
+ Button,
139827
+ {
139828
+ variant: "ghost",
139829
+ size: "icon",
139830
+ onClick: () => handleDeleteItem(item),
139831
+ className: "text-destructive hover:text-destructive"
139832
+ },
139833
+ /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "h-4 w-4" })
139834
+ ))))))), /* @__PURE__ */ React169__namespace.default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(
139835
+ Input,
139836
+ {
139837
+ id: "code",
139838
+ value: formState.code || "",
139839
+ onChange: (e3) => handleFormChange(
139840
+ "code",
139841
+ e3.target.value.toUpperCase()
139842
+ ),
139843
+ disabled: !!currentItem
139844
+ }
139845
+ )), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React169__namespace.default.createElement(
139846
+ Input,
139847
+ {
139848
+ id: "name",
139849
+ value: formState.name || "",
139850
+ onChange: (e3) => handleFormChange(
139851
+ "name",
139852
+ e3.target.value
139853
+ )
139854
+ }
139855
+ ))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React169__namespace.default.createElement(
139856
+ Input,
139857
+ {
139858
+ id: "subject",
139859
+ value: formState.subject || "",
139860
+ onChange: (e3) => handleFormChange(
139861
+ "subject",
139862
+ e3.target.value
139863
+ )
139864
+ }
139865
+ )), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React169__namespace.default.createElement(
139866
+ EditableCombobox,
139867
+ {
139868
+ options: subjects.map((s4) => ({
139869
+ value: s4.code,
139870
+ label: s4.name
139871
+ })),
139872
+ value: formState.subjectCode || "",
139873
+ onChange: (val) => handleFormChange("subjectCode", val),
139874
+ placeholder: "Select a subject..."
139875
+ }
139876
+ ))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React169__namespace.default.createElement(
139877
+ Input,
139878
+ {
139879
+ id: "category",
139880
+ value: formState.category || "",
139881
+ onChange: (e3) => handleFormChange(
139882
+ "category",
139883
+ e3.target.value
139884
+ )
139885
+ }
139886
+ )), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React169__namespace.default.createElement(
139887
+ Input,
139888
+ {
139889
+ id: "categoryCode",
139890
+ value: formState.categoryCode || "",
139891
+ onChange: (e3) => handleFormChange(
139892
+ "categoryCode",
139893
+ e3.target.value
139894
+ )
139895
+ }
139896
+ ))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React169__namespace.default.createElement(
139897
+ Input,
139898
+ {
139899
+ id: "topic",
139900
+ value: formState.topic || "",
139901
+ onChange: (e3) => handleFormChange(
139902
+ "topic",
139903
+ e3.target.value
139904
+ )
139905
+ }
139906
+ )), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React169__namespace.default.createElement(
139907
+ Input,
139908
+ {
139909
+ id: "topicCode",
139910
+ value: formState.topicCode || "",
139911
+ onChange: (e3) => handleFormChange(
139912
+ "topicCode",
139913
+ e3.target.value
139914
+ )
139915
+ }
139916
+ ))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React169__namespace.default.createElement(
139917
+ Input,
139918
+ {
139919
+ id: "grade",
139920
+ value: formState.grade || "",
139921
+ onChange: (e3) => handleFormChange(
139922
+ "grade",
139923
+ e3.target.value
139924
+ )
139925
+ }
139926
+ )), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React169__namespace.default.createElement(
139927
+ Input,
139928
+ {
139929
+ id: "gradeCode",
139930
+ value: formState.gradeCode || "",
139931
+ onChange: (e3) => handleFormChange(
139932
+ "gradeCode",
139933
+ e3.target.value
139934
+ )
139935
+ }
139936
+ ))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React169__namespace.default.createElement(
139937
+ Textarea,
139938
+ {
139939
+ id: "keywords",
139940
+ value: formState.keywords?.join(", ") || "",
139941
+ onChange: (e3) => handleFormChange(
139942
+ "keywords",
139943
+ e3.target.value.split(",").map((s4) => s4.trim())
139944
+ )
139945
+ }
139946
+ )), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React169__namespace.default.createElement(
139947
+ Textarea,
139948
+ {
139949
+ id: "stemElements",
139950
+ value: formState.stemElements?.join(", ") || "",
139951
+ onChange: (e3) => handleFormChange(
139952
+ "stemElements",
139953
+ e3.target.value.split(",").map((s4) => s4.trim())
139954
+ )
139955
+ }
139956
+ )), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React169__namespace.default.createElement(
139957
+ Textarea,
139958
+ {
139959
+ id: "bloomLevelsGuideline",
139960
+ value: formState.bloomLevelsGuideline?.join(
139961
+ ", "
139962
+ ) || "",
139963
+ onChange: (e3) => handleFormChange(
139964
+ "bloomLevelsGuideline",
139965
+ e3.target.value.split(",").map((s4) => s4.trim())
139966
+ )
139967
+ }
139968
+ ))), /* @__PURE__ */ React169__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(
139969
+ Button,
139970
+ {
139971
+ type: "button",
139972
+ variant: "outline",
139973
+ onClick: () => setIsDialogOpen(false),
139974
+ disabled: isPending
139975
+ },
139976
+ "Cancel"
139977
+ ), /* @__PURE__ */ React169__namespace.default.createElement(
139978
+ Button,
139979
+ {
139980
+ type: "submit",
139981
+ onClick: handleSubmit,
139982
+ disabled: isPending || !formState.name?.trim() || !formState.code?.trim()
139983
+ },
139984
+ isPending && /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
139985
+ " ",
139986
+ "Save"
139987
+ )))), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__namespace.default.createElement(
139988
+ AlertDialogAction2,
139989
+ {
139990
+ onClick: confirmDelete,
139991
+ disabled: isPending,
139992
+ className: "bg-destructive hover:bg-destructive/90"
139993
+ },
139994
+ isPending && /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
139995
+ " ",
139996
+ "Delete"
139997
+ ))))));
139743
139998
  }
139744
139999
 
139745
140000
  // src/react-ui/components/metadata/ContextManager.tsx
@@ -5,7 +5,7 @@ import { Q as QuizResultType, U as UserAnswerType, n as PracticeSession, o as Pr
5
5
  export { 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, q as PracticeTopicSummary, g as QuestionReview, R as RoadmapItem, T as TestCaseResult, a as UserAnswers, W as WeeklyRoadmap } from './ai-ecosystem-DyQYZbyX.cjs';
6
6
  import * as React$1 from 'react';
7
7
  import React__default, { ReactNode } from 'react';
8
- 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';
8
+ 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';
9
9
  import * as class_variance_authority_types from 'class-variance-authority/types';
10
10
  import { VariantProps } from 'class-variance-authority';
11
11
  import * as LabelPrimitive from '@radix-ui/react-label';
@@ -5,7 +5,7 @@ import { Q as QuizResultType, U as UserAnswerType, n as PracticeSession, o as Pr
5
5
  export { 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, q as PracticeTopicSummary, g as QuestionReview, R as RoadmapItem, T as TestCaseResult, a as UserAnswers, W as WeeklyRoadmap } from './ai-ecosystem-Qa_SdE2T.js';
6
6
  import * as React$1 from 'react';
7
7
  import React__default, { ReactNode } from 'react';
8
- 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';
8
+ 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';
9
9
  import * as class_variance_authority_types from 'class-variance-authority/types';
10
10
  import { VariantProps } from 'class-variance-authority';
11
11
  import * as LabelPrimitive from '@radix-ui/react-label';