@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.
@@ -8767,12 +8767,10 @@ init_react_shim();
8767
8767
  // src/services/TopicDataService.ts
8768
8768
  init_react_shim();
8769
8769
  var TopicDataService = class {
8770
- // ... saveData, mergeData, getData, clearData methods remain the same ...
8771
8770
  static saveData(data) {
8772
8771
  try {
8773
8772
  if (typeof window === "undefined") return;
8774
- const serializedData = JSON.stringify(data);
8775
- localStorage.setItem(this.STORAGE_KEY, serializedData);
8773
+ localStorage.setItem(this.STORAGE_KEY, JSON.stringify(data));
8776
8774
  } catch (error) {
8777
8775
  console.error("Error saving learning objectives to Local Storage:", error);
8778
8776
  }
@@ -8783,8 +8781,7 @@ var TopicDataService = class {
8783
8781
  newData.forEach((newLo) => {
8784
8782
  loMap.set(newLo.code, newLo);
8785
8783
  });
8786
- const mergedData = Array.from(loMap.values());
8787
- this.saveData(mergedData);
8784
+ this.saveData(Array.from(loMap.values()));
8788
8785
  }
8789
8786
  static getData() {
8790
8787
  try {
@@ -8799,7 +8796,7 @@ var TopicDataService = class {
8799
8796
  }
8800
8797
  static clearData() {
8801
8798
  try {
8802
- if (typeof window === "undefined") return;
8799
+ if (typeof window !== "undefined") return;
8803
8800
  localStorage.removeItem(this.STORAGE_KEY);
8804
8801
  } catch (error) {
8805
8802
  console.error("Error clearing learning objectives from Local Storage:", error);
@@ -8813,6 +8810,12 @@ var TopicDataService = class {
8813
8810
  const headerLine = lines.shift();
8814
8811
  const headers = headerLine.split(" ").map((h2) => h2.trim());
8815
8812
  const headerMap = headers.map((h2) => this.HEADER_MAP[h2] || null);
8813
+ const requiredHeaders = ["LO ID", "LO Name", "Subject", "Subject Code", "Category", "Category Code", "Topic", "Topic Code", "Grade", "Grade Code"];
8814
+ const missingHeaders = requiredHeaders.filter((h2) => !headers.includes(h2));
8815
+ if (missingHeaders.length > 0) {
8816
+ const errorMsg = `Invalid TSV header. Missing required columns: ${missingHeaders.join(", ")}`;
8817
+ return { data: [], errors: [errorMsg] };
8818
+ }
8816
8819
  const data = [];
8817
8820
  const errors2 = [];
8818
8821
  lines.forEach((line, index3) => {
@@ -8821,29 +8824,30 @@ var TopicDataService = class {
8821
8824
  headerMap.forEach((propName, i) => {
8822
8825
  if (propName) {
8823
8826
  const value = values[i]?.trim() || "";
8824
- if (propName === "keywords" || propName === "stemElements" || propName === "bloomLevelsGuideline") {
8827
+ if (["keywords", "stemElements", "bloomLevelsGuideline"].includes(propName)) {
8825
8828
  rowObject[propName] = value.split(",").map((s2) => s2.trim()).filter(Boolean);
8826
8829
  } else {
8827
8830
  rowObject[propName] = value;
8828
8831
  }
8829
8832
  }
8830
8833
  });
8831
- if (!rowObject.code) {
8832
- errors2.push(`Line ${index3 + 2}: Missing required value for 'LO ID'.`);
8834
+ if (!rowObject.code || !rowObject.name) {
8835
+ errors2.push(`Line ${index3 + 2}: Missing required values for 'LO ID' or 'LO Name'.`);
8833
8836
  return;
8834
8837
  }
8835
- if (!rowObject.name) {
8836
- rowObject.name = rowObject.code;
8837
- }
8838
8838
  const learningObjective = {
8839
8839
  id: generateUniqueId("lo_"),
8840
8840
  code: rowObject.code,
8841
8841
  name: rowObject.name,
8842
8842
  description: rowObject.description,
8843
8843
  subject: rowObject.subject || "",
8844
+ subjectCode: rowObject.subjectCode,
8844
8845
  category: rowObject.category || "",
8846
+ categoryCode: rowObject.categoryCode,
8845
8847
  topic: rowObject.topic || "",
8848
+ topicCode: rowObject.topicCode,
8846
8849
  grade: rowObject.grade || "",
8850
+ gradeCode: rowObject.gradeCode,
8847
8851
  keywords: rowObject.keywords || [],
8848
8852
  stemElements: rowObject.stemElements || [],
8849
8853
  bloomLevelsGuideline: rowObject.bloomLevelsGuideline || []
@@ -8874,17 +8878,23 @@ var TopicDataService = class {
8874
8878
  }
8875
8879
  };
8876
8880
  TopicDataService.STORAGE_KEY = "interactive_quiz_kit_learning_objectives";
8877
- // Define a map for flexible header mapping
8878
8881
  TopicDataService.HEADER_MAP = {
8879
8882
  "LO ID": "code",
8880
8883
  "LO Name": "name",
8881
- // Ready for future addition
8882
8884
  "LO Description": "description",
8883
8885
  "Subject": "subject",
8886
+ "Subject Code": "subjectCode",
8887
+ // New
8884
8888
  "Category": "category",
8889
+ "Category Code": "categoryCode",
8890
+ // New
8885
8891
  "Topic": "topic",
8892
+ "Topic Code": "topicCode",
8893
+ // New
8886
8894
  "Keywords": "keywords",
8887
8895
  "Grade": "grade",
8896
+ "Grade Code": "gradeCode",
8897
+ // New
8888
8898
  "STEM Element(s)": "stemElements",
8889
8899
  "Bloom\u2019s Level(s) Guideline": "bloomLevelsGuideline"
8890
8900
  };
@@ -77229,15 +77239,27 @@ function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onU
77229
77239
 
77230
77240
  // src/react-ui/components/metadata/LearningObjectiveManager.tsx
77231
77241
  init_react_shim();
77232
- function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
77242
+ function LearningObjectiveManager({
77243
+ initialData,
77244
+ subjects: subjectsProp,
77245
+ isLoading: isLoadingProp,
77246
+ onAdd,
77247
+ onUpdate,
77248
+ onDelete,
77249
+ onBulkAdd
77250
+ }) {
77233
77251
  const [items, setItems] = useState([]);
77234
77252
  const [subjects, setSubjects] = useState([]);
77235
77253
  const [isLoading, setIsLoading] = useState(true);
77236
77254
  const [isDialogOpen, setIsDialogOpen] = useState(false);
77237
77255
  const [isAlertOpen, setIsAlertOpen] = useState(false);
77238
- const [currentItem, setCurrentItem] = useState(null);
77256
+ const [currentItem, setCurrentItem] = useState(
77257
+ null
77258
+ );
77239
77259
  const [formState, setFormState] = useState({});
77240
- const [itemToDelete, setItemToDelete] = useState(null);
77260
+ const [itemToDelete, setItemToDelete] = useState(
77261
+ null
77262
+ );
77241
77263
  const [isPending, startTransition] = useTransition();
77242
77264
  const { toast: toast2 } = useToast();
77243
77265
  const isControlled = initialData !== void 0;
@@ -77248,7 +77270,11 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
77248
77270
  setItems(MetadataService.getLearningObjectives());
77249
77271
  setSubjects(MetadataService.getSubjects());
77250
77272
  } catch (error) {
77251
- toast2({ title: "Error", description: "Failed to refresh data.", variant: "destructive" });
77273
+ toast2({
77274
+ title: "Error",
77275
+ description: "Failed to refresh data.",
77276
+ variant: "destructive"
77277
+ });
77252
77278
  } finally {
77253
77279
  setIsLoading(false);
77254
77280
  }
@@ -77268,7 +77294,9 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
77268
77294
  };
77269
77295
  const handleAddItem = () => {
77270
77296
  setCurrentItem(null);
77271
- setFormState({ subjectCode: subjects.length > 0 ? subjects[0].code : "" });
77297
+ setFormState({
77298
+ subjectCode: subjects.length > 0 ? subjects[0].code : ""
77299
+ });
77272
77300
  setIsDialogOpen(true);
77273
77301
  };
77274
77302
  const handleEditItem = (item) => {
@@ -77290,9 +77318,16 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
77290
77318
  MetadataService.deleteLearningObjective(itemToDelete.code);
77291
77319
  refreshData();
77292
77320
  }
77293
- toast2({ title: "Success", description: `Learning Objective "${itemToDelete.name}" deleted.` });
77321
+ toast2({
77322
+ title: "Success",
77323
+ description: `Learning Objective "${itemToDelete.name}" deleted.`
77324
+ });
77294
77325
  } catch (error) {
77295
- toast2({ title: "Error", description: error.message, variant: "destructive" });
77326
+ toast2({
77327
+ title: "Error",
77328
+ description: error.message,
77329
+ variant: "destructive"
77330
+ });
77296
77331
  } finally {
77297
77332
  setIsAlertOpen(false);
77298
77333
  setItemToDelete(null);
@@ -77301,7 +77336,11 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
77301
77336
  };
77302
77337
  const handleSubmit = () => {
77303
77338
  if (!formState.name?.trim() || !formState.code?.trim()) {
77304
- toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
77339
+ toast2({
77340
+ title: "Validation Error",
77341
+ description: "Code and Name are required.",
77342
+ variant: "destructive"
77343
+ });
77305
77344
  return;
77306
77345
  }
77307
77346
  startTransition(async () => {
@@ -77310,75 +77349,291 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
77310
77349
  if (isControlled && onUpdate) {
77311
77350
  await onUpdate({ ...currentItem, ...formState });
77312
77351
  } else {
77313
- MetadataService.updateLearningObjective(currentItem.id, formState);
77352
+ MetadataService.updateLearningObjective(
77353
+ currentItem.id,
77354
+ formState
77355
+ );
77314
77356
  refreshData();
77315
77357
  }
77316
- toast2({ title: "Success", description: "Learning Objective updated." });
77358
+ toast2({
77359
+ title: "Success",
77360
+ description: "Learning Objective updated."
77361
+ });
77317
77362
  } else {
77318
77363
  if (isControlled && onAdd) {
77319
77364
  await onAdd(formState);
77320
77365
  } else {
77321
- MetadataService.addLearningObjective(formState);
77366
+ MetadataService.addLearningObjective(
77367
+ formState
77368
+ );
77322
77369
  refreshData();
77323
77370
  }
77324
- toast2({ title: "Success", description: "Learning Objective added." });
77371
+ toast2({
77372
+ title: "Success",
77373
+ description: "Learning Objective added."
77374
+ });
77325
77375
  }
77326
77376
  setIsDialogOpen(false);
77327
77377
  } catch (error) {
77328
- toast2({ title: "Error", description: error.message, variant: "destructive" });
77378
+ toast2({
77379
+ title: "Error",
77380
+ description: error.message,
77381
+ variant: "destructive"
77382
+ });
77329
77383
  }
77330
77384
  });
77331
77385
  };
77332
77386
  const handleImport = async (records) => {
77333
- console.log(`[LO Manager] handleImport called with ${records.length} raw records.`);
77387
+ console.log(
77388
+ `[LO Manager] handleImport called with ${records.length} raw records.`
77389
+ );
77334
77390
  if (!onBulkAdd) {
77335
77391
  console.error("[LO Manager] onBulkAdd handler is not provided.");
77336
77392
  return;
77337
77393
  }
77338
77394
  const parseStringToArray = (input) => {
77339
77395
  if (Array.isArray(input)) return input;
77340
- if (typeof input === "string") return input.split(",").map((s2) => s2.trim()).filter(Boolean);
77396
+ if (typeof input === "string")
77397
+ return input.split(",").map((s2) => s2.trim()).filter(Boolean);
77341
77398
  return [];
77342
77399
  };
77343
- const validationResult = records.reduce((acc, rec) => {
77344
- if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
77345
- acc.valid.push({
77346
- code: rec.code,
77347
- name: rec.name,
77348
- description: rec.description || rec.name,
77349
- subject: rec.subject || "",
77350
- subjectCode: rec.subjectCode,
77351
- category: rec.category || "",
77352
- categoryCode: rec.categoryCode,
77353
- topic: rec.topic || "",
77354
- topicCode: rec.topicCode,
77355
- grade: rec.grade || "",
77356
- gradeCode: rec.gradeCode,
77357
- keywords: parseStringToArray(rec.keywords),
77358
- stemElements: parseStringToArray(rec.stemElements),
77359
- bloomLevelsGuideline: parseStringToArray(rec.bloomLevelsGuideline)
77360
- });
77361
- } else {
77362
- acc.invalidCount++;
77363
- }
77364
- return acc;
77365
- }, { valid: [], invalidCount: 0 });
77366
- console.log(`[LO Manager] Validation complete. ${validationResult.valid.length} valid records found.`);
77400
+ const validationResult = records.reduce(
77401
+ (acc, rec) => {
77402
+ if (typeof rec["LO ID"] === "string" && rec["LO ID"].trim() && typeof rec["LO Description"] === "string" && rec["LO Description"].trim()) {
77403
+ acc.valid.push({
77404
+ code: rec["LO ID"],
77405
+ name: rec["LO ID"],
77406
+ description: rec["LO Description"],
77407
+ subject: rec["Subject"] || "",
77408
+ subjectCode: rec["Subject Code"] || rec["Subject"],
77409
+ category: rec["Category"] || "",
77410
+ categoryCode: rec["Category Code"] || rec["Category"],
77411
+ topic: rec["Topic"] || "",
77412
+ topicCode: rec["Topic Code"] || rec["Topic"],
77413
+ grade: rec["Grade"] || "",
77414
+ gradeCode: rec["Grade Code"] || rec["Grade"],
77415
+ keywords: parseStringToArray(rec["Keywords"]),
77416
+ stemElements: parseStringToArray(
77417
+ rec["STEM Element(s)"]
77418
+ ),
77419
+ bloomLevelsGuideline: parseStringToArray(
77420
+ rec["Bloom\u2019s Level(s) Guideline"]
77421
+ )
77422
+ });
77423
+ } else {
77424
+ acc.invalidCount++;
77425
+ }
77426
+ return acc;
77427
+ },
77428
+ { valid: [], invalidCount: 0 }
77429
+ );
77430
+ console.log(
77431
+ `[LO Manager] Validation complete. ${validationResult.valid.length} valid records found.`
77432
+ );
77367
77433
  if (validationResult.invalidCount > 0) {
77368
77434
  toast2({
77369
77435
  title: "Import Warning",
77370
- description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
77436
+ description: `${validationResult.invalidCount} records had invalid or missing 'LO ID' or 'LO Description' fields and were ignored.`,
77371
77437
  variant: "destructive"
77372
77438
  });
77373
77439
  }
77374
77440
  if (validationResult.valid.length > 0) {
77375
- console.log("[LO Manager] Calling onBulkAdd prop with validated data...");
77441
+ console.log(
77442
+ "[LO Manager] Calling onBulkAdd prop with validated data..."
77443
+ );
77376
77444
  await onBulkAdd(validationResult.valid);
77377
77445
  } else {
77378
77446
  console.log("[LO Manager] No valid records to import.");
77379
77447
  }
77380
77448
  };
77381
- return /* @__PURE__ */ React119__default.createElement(Card, null, /* @__PURE__ */ React119__default.createElement(CardHeader, null, /* @__PURE__ */ React119__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React119__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React119__default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Learning Objectives"), /* @__PURE__ */ React119__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React119__default.createElement(MetadataImportControls, { metadataName: "Learning Objectives", onImport: handleImport }), /* @__PURE__ */ React119__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React119__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React119__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React119__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React119__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React119__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React119__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React119__default.createElement(Table2, null, /* @__PURE__ */ React119__default.createElement(TableHeader, null, /* @__PURE__ */ React119__default.createElement(TableRow, null, /* @__PURE__ */ React119__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React119__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React119__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React119__default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React119__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React119__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React119__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React119__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React119__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React119__default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React119__default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React119__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React119__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React119__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React119__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React119__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React119__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React119__default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React119__default.createElement(DialogHeader, null, /* @__PURE__ */ React119__default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React119__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React119__default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e2) => handleFormChange("code", e2.target.value.toUpperCase()), disabled: !!currentItem })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React119__default.createElement(Input, { id: "name", value: formState.name || "", onChange: (e2) => handleFormChange("name", e2.target.value) }))), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React119__default.createElement(Input, { id: "subject", value: formState.subject || "", onChange: (e2) => handleFormChange("subject", e2.target.value) })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React119__default.createElement(EditableCombobox, { options: subjects.map((s2) => ({ value: s2.code, label: s2.name })), value: formState.subjectCode || "", onChange: (val) => handleFormChange("subjectCode", val), placeholder: "Select a subject..." }))), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React119__default.createElement(Input, { id: "category", value: formState.category || "", onChange: (e2) => handleFormChange("category", e2.target.value) })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React119__default.createElement(Input, { id: "categoryCode", value: formState.categoryCode || "", onChange: (e2) => handleFormChange("categoryCode", e2.target.value) }))), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React119__default.createElement(Input, { id: "topic", value: formState.topic || "", onChange: (e2) => handleFormChange("topic", e2.target.value) })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React119__default.createElement(Input, { id: "topicCode", value: formState.topicCode || "", onChange: (e2) => handleFormChange("topicCode", e2.target.value) }))), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React119__default.createElement(Input, { id: "grade", value: formState.grade || "", onChange: (e2) => handleFormChange("grade", e2.target.value) })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React119__default.createElement(Input, { id: "gradeCode", value: formState.gradeCode || "", onChange: (e2) => handleFormChange("gradeCode", e2.target.value) }))), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React119__default.createElement(Textarea, { id: "keywords", value: formState.keywords?.join(", ") || "", onChange: (e2) => handleFormChange("keywords", e2.target.value.split(",").map((s2) => s2.trim())) })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React119__default.createElement(Textarea, { id: "stemElements", value: formState.stemElements?.join(", ") || "", onChange: (e2) => handleFormChange("stemElements", e2.target.value.split(",").map((s2) => s2.trim())) })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React119__default.createElement(Textarea, { id: "bloomLevelsGuideline", value: formState.bloomLevelsGuideline?.join(", ") || "", onChange: (e2) => handleFormChange("bloomLevelsGuideline", e2.target.value.split(",").map((s2) => s2.trim())) }))), /* @__PURE__ */ React119__default.createElement(DialogFooter, null, /* @__PURE__ */ React119__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React119__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !formState.name?.trim() || !formState.code?.trim() }, isPending && /* @__PURE__ */ React119__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React119__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React119__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React119__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React119__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React119__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React119__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React119__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React119__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React119__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
77449
+ return /* @__PURE__ */ React119__default.createElement(Card, null, /* @__PURE__ */ React119__default.createElement(CardHeader, null, /* @__PURE__ */ React119__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React119__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React119__default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " ", "Manage Learning Objectives"), /* @__PURE__ */ React119__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React119__default.createElement(
77450
+ MetadataImportControls,
77451
+ {
77452
+ metadataName: "Learning Objectives",
77453
+ onImport: handleImport
77454
+ }
77455
+ ), /* @__PURE__ */ React119__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React119__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React119__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React119__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React119__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React119__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React119__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React119__default.createElement(Table2, null, /* @__PURE__ */ React119__default.createElement(TableHeader, null, /* @__PURE__ */ React119__default.createElement(TableRow, null, /* @__PURE__ */ React119__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React119__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React119__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React119__default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React119__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React119__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React119__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React119__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React119__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React119__default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React119__default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React119__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React119__default.createElement(
77456
+ Button,
77457
+ {
77458
+ variant: "ghost",
77459
+ size: "icon",
77460
+ onClick: () => handleEditItem(item),
77461
+ className: "mr-2"
77462
+ },
77463
+ /* @__PURE__ */ React119__default.createElement(PenLine, { className: "h-4 w-4" })
77464
+ ), /* @__PURE__ */ React119__default.createElement(
77465
+ Button,
77466
+ {
77467
+ variant: "ghost",
77468
+ size: "icon",
77469
+ onClick: () => handleDeleteItem(item),
77470
+ className: "text-destructive hover:text-destructive"
77471
+ },
77472
+ /* @__PURE__ */ React119__default.createElement(Trash2, { className: "h-4 w-4" })
77473
+ ))))))), /* @__PURE__ */ React119__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React119__default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React119__default.createElement(DialogHeader, null, /* @__PURE__ */ React119__default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React119__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React119__default.createElement(
77474
+ Input,
77475
+ {
77476
+ id: "code",
77477
+ value: formState.code || "",
77478
+ onChange: (e2) => handleFormChange(
77479
+ "code",
77480
+ e2.target.value.toUpperCase()
77481
+ ),
77482
+ disabled: !!currentItem
77483
+ }
77484
+ )), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React119__default.createElement(
77485
+ Input,
77486
+ {
77487
+ id: "name",
77488
+ value: formState.name || "",
77489
+ onChange: (e2) => handleFormChange(
77490
+ "name",
77491
+ e2.target.value
77492
+ )
77493
+ }
77494
+ ))), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React119__default.createElement(
77495
+ Input,
77496
+ {
77497
+ id: "subject",
77498
+ value: formState.subject || "",
77499
+ onChange: (e2) => handleFormChange(
77500
+ "subject",
77501
+ e2.target.value
77502
+ )
77503
+ }
77504
+ )), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React119__default.createElement(
77505
+ EditableCombobox,
77506
+ {
77507
+ options: subjects.map((s2) => ({
77508
+ value: s2.code,
77509
+ label: s2.name
77510
+ })),
77511
+ value: formState.subjectCode || "",
77512
+ onChange: (val) => handleFormChange("subjectCode", val),
77513
+ placeholder: "Select a subject..."
77514
+ }
77515
+ ))), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React119__default.createElement(
77516
+ Input,
77517
+ {
77518
+ id: "category",
77519
+ value: formState.category || "",
77520
+ onChange: (e2) => handleFormChange(
77521
+ "category",
77522
+ e2.target.value
77523
+ )
77524
+ }
77525
+ )), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React119__default.createElement(
77526
+ Input,
77527
+ {
77528
+ id: "categoryCode",
77529
+ value: formState.categoryCode || "",
77530
+ onChange: (e2) => handleFormChange(
77531
+ "categoryCode",
77532
+ e2.target.value
77533
+ )
77534
+ }
77535
+ ))), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React119__default.createElement(
77536
+ Input,
77537
+ {
77538
+ id: "topic",
77539
+ value: formState.topic || "",
77540
+ onChange: (e2) => handleFormChange(
77541
+ "topic",
77542
+ e2.target.value
77543
+ )
77544
+ }
77545
+ )), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React119__default.createElement(
77546
+ Input,
77547
+ {
77548
+ id: "topicCode",
77549
+ value: formState.topicCode || "",
77550
+ onChange: (e2) => handleFormChange(
77551
+ "topicCode",
77552
+ e2.target.value
77553
+ )
77554
+ }
77555
+ ))), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React119__default.createElement(
77556
+ Input,
77557
+ {
77558
+ id: "grade",
77559
+ value: formState.grade || "",
77560
+ onChange: (e2) => handleFormChange(
77561
+ "grade",
77562
+ e2.target.value
77563
+ )
77564
+ }
77565
+ )), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React119__default.createElement(
77566
+ Input,
77567
+ {
77568
+ id: "gradeCode",
77569
+ value: formState.gradeCode || "",
77570
+ onChange: (e2) => handleFormChange(
77571
+ "gradeCode",
77572
+ e2.target.value
77573
+ )
77574
+ }
77575
+ ))), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React119__default.createElement(
77576
+ Textarea,
77577
+ {
77578
+ id: "keywords",
77579
+ value: formState.keywords?.join(", ") || "",
77580
+ onChange: (e2) => handleFormChange(
77581
+ "keywords",
77582
+ e2.target.value.split(",").map((s2) => s2.trim())
77583
+ )
77584
+ }
77585
+ )), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React119__default.createElement(
77586
+ Textarea,
77587
+ {
77588
+ id: "stemElements",
77589
+ value: formState.stemElements?.join(", ") || "",
77590
+ onChange: (e2) => handleFormChange(
77591
+ "stemElements",
77592
+ e2.target.value.split(",").map((s2) => s2.trim())
77593
+ )
77594
+ }
77595
+ )), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React119__default.createElement(
77596
+ Textarea,
77597
+ {
77598
+ id: "bloomLevelsGuideline",
77599
+ value: formState.bloomLevelsGuideline?.join(
77600
+ ", "
77601
+ ) || "",
77602
+ onChange: (e2) => handleFormChange(
77603
+ "bloomLevelsGuideline",
77604
+ e2.target.value.split(",").map((s2) => s2.trim())
77605
+ )
77606
+ }
77607
+ ))), /* @__PURE__ */ React119__default.createElement(DialogFooter, null, /* @__PURE__ */ React119__default.createElement(
77608
+ Button,
77609
+ {
77610
+ type: "button",
77611
+ variant: "outline",
77612
+ onClick: () => setIsDialogOpen(false),
77613
+ disabled: isPending
77614
+ },
77615
+ "Cancel"
77616
+ ), /* @__PURE__ */ React119__default.createElement(
77617
+ Button,
77618
+ {
77619
+ type: "submit",
77620
+ onClick: handleSubmit,
77621
+ disabled: isPending || !formState.name?.trim() || !formState.code?.trim()
77622
+ },
77623
+ isPending && /* @__PURE__ */ React119__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
77624
+ " ",
77625
+ "Save"
77626
+ )))), /* @__PURE__ */ React119__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React119__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React119__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React119__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React119__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React119__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React119__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React119__default.createElement(
77627
+ AlertDialogAction2,
77628
+ {
77629
+ onClick: confirmDelete,
77630
+ disabled: isPending,
77631
+ className: "bg-destructive hover:bg-destructive/90"
77632
+ },
77633
+ isPending && /* @__PURE__ */ React119__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
77634
+ " ",
77635
+ "Delete"
77636
+ ))))));
77382
77637
  }
77383
77638
 
77384
77639
  // src/react-ui/components/metadata/ContextManager.tsx