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

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