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