@thanh01.pmt/interactive-quiz-kit 1.0.51 → 1.0.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react-ui.mjs CHANGED
@@ -168220,7 +168220,7 @@ function SubjectManager({
168220
168220
 
168221
168221
  // src/react-ui/components/metadata/GradeLevelManager.tsx
168222
168222
  init_react_shim();
168223
- function GradeLevelManager() {
168223
+ function GradeLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
168224
168224
  const [items, setItems] = useState([]);
168225
168225
  const [isLoading, setIsLoading] = useState(true);
168226
168226
  const [isDialogOpen, setIsDialogOpen] = useState(false);
@@ -168231,19 +168231,27 @@ function GradeLevelManager() {
168231
168231
  const [itemToDelete, setItemToDelete] = useState(null);
168232
168232
  const [isPending, startTransition] = useTransition();
168233
168233
  const { toast: toast2 } = useToast();
168234
- useEffect(() => {
168235
- fetchItems();
168236
- }, []);
168237
- const fetchItems = () => {
168238
- setIsLoading(true);
168239
- try {
168240
- setItems(MetadataService.getGradeLevels());
168241
- } catch (error) {
168242
- toast2({ title: "Error", description: "Failed to fetch grade levels.", variant: "destructive" });
168243
- } finally {
168244
- setIsLoading(false);
168234
+ const isControlled = initialData !== void 0;
168235
+ const refreshData = () => {
168236
+ if (!isControlled) {
168237
+ setIsLoading(true);
168238
+ try {
168239
+ setItems(MetadataService.getGradeLevels());
168240
+ } catch (error) {
168241
+ toast2({ title: "Error", description: "Failed to refresh grade levels.", variant: "destructive" });
168242
+ } finally {
168243
+ setIsLoading(false);
168244
+ }
168245
168245
  }
168246
168246
  };
168247
+ useEffect(() => {
168248
+ if (isControlled) {
168249
+ setItems(initialData || []);
168250
+ setIsLoading(isLoadingProp || false);
168251
+ } else {
168252
+ refreshData();
168253
+ }
168254
+ }, [isControlled, initialData, isLoadingProp]);
168247
168255
  const handleAddItem = () => {
168248
168256
  setCurrentItem(null);
168249
168257
  setItemName("");
@@ -168262,13 +168270,17 @@ function GradeLevelManager() {
168262
168270
  };
168263
168271
  const confirmDelete = () => {
168264
168272
  if (!itemToDelete) return;
168265
- startTransition(() => {
168273
+ startTransition(async () => {
168266
168274
  try {
168267
- MetadataService.deleteGradeLevel(itemToDelete.code);
168275
+ if (isControlled && onDelete) {
168276
+ await onDelete(itemToDelete);
168277
+ } else {
168278
+ MetadataService.deleteGradeLevel(itemToDelete.code);
168279
+ refreshData();
168280
+ }
168268
168281
  toast2({ title: "Success", description: `Grade Level "${itemToDelete.name}" deleted.` });
168269
- fetchItems();
168270
168282
  } catch (error) {
168271
- toast2({ title: "Error", description: "Failed to delete grade level.", variant: "destructive" });
168283
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
168272
168284
  } finally {
168273
168285
  setIsAlertOpen(false);
168274
168286
  setItemToDelete(null);
@@ -168280,27 +168292,44 @@ function GradeLevelManager() {
168280
168292
  toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
168281
168293
  return;
168282
168294
  }
168283
- startTransition(() => {
168295
+ startTransition(async () => {
168284
168296
  try {
168285
168297
  if (currentItem) {
168286
- MetadataService.updateGradeLevel(currentItem.id, itemName, itemCode);
168298
+ if (isControlled && onUpdate) {
168299
+ await onUpdate({ id: currentItem.id, name: itemName, code: itemCode });
168300
+ } else {
168301
+ MetadataService.updateGradeLevel(currentItem.id, itemName, itemCode);
168302
+ refreshData();
168303
+ }
168304
+ toast2({ title: "Success", description: "Grade Level updated." });
168287
168305
  } else {
168288
- MetadataService.addGradeLevel(itemName, itemCode);
168306
+ if (isControlled && onAdd) {
168307
+ await onAdd({ name: itemName, code: itemCode });
168308
+ } else {
168309
+ MetadataService.addGradeLevel(itemName, itemCode);
168310
+ refreshData();
168311
+ }
168312
+ toast2({ title: "Success", description: "Grade Level added." });
168289
168313
  }
168290
- toast2({ title: "Success", description: `Grade Level saved.` });
168291
- fetchItems();
168292
168314
  setIsDialogOpen(false);
168293
168315
  } catch (error) {
168294
- toast2({ title: "Error", description: "Failed to save grade level.", variant: "destructive" });
168316
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
168295
168317
  }
168296
168318
  });
168297
168319
  };
168298
- return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(Award, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Grade Levels"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Grade Level"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No grade levels found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Grade Level" : "Add New Grade Level")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., G9", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Grade 9" }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemName.trim() || !itemCode.trim() }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), "Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), "Delete"))))));
168320
+ return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(Award, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Grade Levels"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Grade Level"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No grade levels found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Grade Level" : "Add New Grade Level")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., G9", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Grade 9" }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemName.trim() || !itemCode.trim() }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
168299
168321
  }
168300
168322
 
168301
168323
  // src/react-ui/components/metadata/TopicManager.tsx
168302
168324
  init_react_shim();
168303
- function TopicManager() {
168325
+ function TopicManager({
168326
+ initialData,
168327
+ subjects: subjectsProp,
168328
+ isLoading: isLoadingProp,
168329
+ onAdd,
168330
+ onUpdate,
168331
+ onDelete
168332
+ }) {
168304
168333
  const [topics, setTopics] = useState([]);
168305
168334
  const [subjects, setSubjects] = useState([]);
168306
168335
  const [isLoading, setIsLoading] = useState(true);
@@ -168313,36 +168342,34 @@ function TopicManager() {
168313
168342
  const [itemToDelete, setItemToDelete] = useState(null);
168314
168343
  const [isPending, startTransition] = useTransition();
168315
168344
  const { toast: toast2 } = useToast();
168316
- const fetchData = () => {
168317
- setIsLoading(true);
168318
- try {
168319
- const topicsData = MetadataService.getTopics();
168320
- const subjectsData = MetadataService.getSubjects();
168321
- setTopics(topicsData);
168322
- setSubjects(subjectsData);
168323
- if (subjectsData.length > 0 && !selectedSubjectCode) {
168324
- setSelectedSubjectCode(subjectsData[0].code);
168345
+ const isControlled = initialData !== void 0;
168346
+ const refreshData = () => {
168347
+ if (!isControlled) {
168348
+ setIsLoading(true);
168349
+ try {
168350
+ setTopics(MetadataService.getTopics());
168351
+ setSubjects(MetadataService.getSubjects());
168352
+ } catch (error) {
168353
+ toast2({ title: "Error", description: "Failed to refresh topics or subjects.", variant: "destructive" });
168354
+ } finally {
168355
+ setIsLoading(false);
168325
168356
  }
168326
- } catch (error) {
168327
- toast2({
168328
- title: "Error",
168329
- description: "Failed to fetch topics or subjects.",
168330
- variant: "destructive"
168331
- });
168332
- } finally {
168333
- setIsLoading(false);
168334
168357
  }
168335
168358
  };
168336
168359
  useEffect(() => {
168337
- fetchData();
168338
- }, []);
168360
+ if (isControlled) {
168361
+ setTopics(initialData || []);
168362
+ setSubjects(subjectsProp || []);
168363
+ setIsLoading(isLoadingProp || false);
168364
+ } else {
168365
+ refreshData();
168366
+ }
168367
+ }, [isControlled, initialData, subjectsProp, isLoadingProp]);
168339
168368
  const handleAddItem = () => {
168340
168369
  setCurrentItem(null);
168341
168370
  setItemName("");
168342
168371
  setItemCode("");
168343
- if (subjects.length > 0) {
168344
- setSelectedSubjectCode(subjects[0].code);
168345
- }
168372
+ setSelectedSubjectCode(subjects.length > 0 ? subjects[0].code : "");
168346
168373
  setIsDialogOpen(true);
168347
168374
  };
168348
168375
  const handleEditItem = (topic) => {
@@ -168358,20 +168385,17 @@ function TopicManager() {
168358
168385
  };
168359
168386
  const confirmDelete = () => {
168360
168387
  if (!itemToDelete) return;
168361
- startTransition(() => {
168388
+ startTransition(async () => {
168362
168389
  try {
168363
- MetadataService.deleteTopic(itemToDelete.code);
168364
- toast2({
168365
- title: "Success",
168366
- description: `Topic "${itemToDelete.name}" deleted.`
168367
- });
168368
- fetchData();
168390
+ if (isControlled && onDelete) {
168391
+ await onDelete(itemToDelete);
168392
+ } else {
168393
+ MetadataService.deleteTopic(itemToDelete.code);
168394
+ refreshData();
168395
+ }
168396
+ toast2({ title: "Success", description: `Topic "${itemToDelete.name}" deleted.` });
168369
168397
  } catch (error) {
168370
- toast2({
168371
- title: "Error",
168372
- description: "Failed to delete topic.",
168373
- variant: "destructive"
168374
- });
168398
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
168375
168399
  } finally {
168376
168400
  setIsAlertOpen(false);
168377
168401
  setItemToDelete(null);
@@ -168380,144 +168404,43 @@ function TopicManager() {
168380
168404
  };
168381
168405
  const handleSubmit = () => {
168382
168406
  if (!itemName.trim() || !itemCode.trim() || !selectedSubjectCode) {
168383
- toast2({
168384
- title: "Validation Error",
168385
- description: "Name, Code, and Subject are required.",
168386
- variant: "destructive"
168387
- });
168407
+ toast2({ title: "Validation Error", description: "Name, Code, and Subject are required.", variant: "destructive" });
168388
168408
  return;
168389
168409
  }
168390
- startTransition(() => {
168410
+ startTransition(async () => {
168391
168411
  try {
168392
168412
  if (currentItem) {
168393
- MetadataService.updateTopic(
168394
- currentItem.id,
168395
- itemName,
168396
- itemCode,
168397
- selectedSubjectCode
168398
- );
168413
+ if (isControlled && onUpdate) {
168414
+ await onUpdate({ id: currentItem.id, name: itemName, code: itemCode, subjectCode: selectedSubjectCode });
168415
+ } else {
168416
+ MetadataService.updateTopic(currentItem.id, itemName, itemCode, selectedSubjectCode);
168417
+ refreshData();
168418
+ }
168419
+ toast2({ title: "Success", description: "Topic updated." });
168399
168420
  } else {
168400
- MetadataService.addTopic(
168401
- itemName,
168402
- itemCode,
168403
- selectedSubjectCode
168404
- );
168421
+ if (isControlled && onAdd) {
168422
+ await onAdd({ name: itemName, code: itemCode, subjectCode: selectedSubjectCode });
168423
+ } else {
168424
+ MetadataService.addTopic(itemName, itemCode, selectedSubjectCode);
168425
+ refreshData();
168426
+ }
168427
+ toast2({ title: "Success", description: "Topic added." });
168405
168428
  }
168406
- toast2({ title: "Success", description: "Topic saved." });
168407
- fetchData();
168408
168429
  setIsDialogOpen(false);
168409
168430
  } catch (error) {
168410
- toast2({
168411
- title: "Error",
168412
- description: "Failed to save topic.",
168413
- variant: "destructive"
168414
- });
168431
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
168415
168432
  }
168416
168433
  });
168417
168434
  };
168418
168435
  const getSubjectName = (subjectCode) => {
168419
168436
  return subjects.find((s4) => s4.code === subjectCode)?.name || "N/A";
168420
168437
  };
168421
- return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(Tag, { className: "mr-2 h-5 w-5 text-primary" }), "Manage Topics"), /* @__PURE__ */ React163__default.createElement(
168422
- Button,
168423
- {
168424
- onClick: handleAddItem,
168425
- size: "sm",
168426
- disabled: subjects.length === 0
168427
- },
168428
- /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }),
168429
- " Add Topic"
168430
- )), subjects.length === 0 && !isLoading && /* @__PURE__ */ React163__default.createElement("p", { className: "text-sm text-destructive" }, "Please add subjects before adding topics.")), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : topics.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No topics found. Add one to get started!") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, topics.map((topic) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: topic.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, topic.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, topic.name), /* @__PURE__ */ React163__default.createElement(TableCell, null, getSubjectName(topic.subjectCode), " ", "(", topic.subjectCode, ")"), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(
168431
- Button,
168432
- {
168433
- variant: "ghost",
168434
- size: "icon",
168435
- onClick: () => handleEditItem(topic),
168436
- className: "mr-2"
168437
- },
168438
- /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })
168439
- ), /* @__PURE__ */ React163__default.createElement(
168440
- Button,
168441
- {
168442
- variant: "ghost",
168443
- size: "icon",
168444
- onClick: () => handleDeleteItem(topic),
168445
- className: "text-destructive hover:text-destructive"
168446
- },
168447
- /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })
168448
- ))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Topic" : "Add New Topic")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Topic Code"), /* @__PURE__ */ React163__default.createElement(
168449
- Input,
168450
- {
168451
- id: "itemCode",
168452
- value: itemCode,
168453
- onChange: (e3) => setItemCode(
168454
- e3.target.value.toUpperCase()
168455
- ),
168456
- placeholder: "e.g., ALG-BASICS",
168457
- disabled: !!currentItem
168458
- }
168459
- )), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Topic Name"), /* @__PURE__ */ React163__default.createElement(
168460
- Input,
168461
- {
168462
- id: "itemName",
168463
- value: itemName,
168464
- onChange: (e3) => setItemName(e3.target.value),
168465
- placeholder: "e.g., Algebra Basics"
168466
- }
168467
- )), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject"), /* @__PURE__ */ React163__default.createElement(
168468
- Select2,
168469
- {
168470
- value: selectedSubjectCode,
168471
- onValueChange: setSelectedSubjectCode,
168472
- disabled: subjects.length === 0
168473
- },
168474
- /* @__PURE__ */ React163__default.createElement(SelectTrigger2, { id: "subjectCode" }, /* @__PURE__ */ React163__default.createElement(SelectValue2, { placeholder: "Select a subject" })),
168475
- /* @__PURE__ */ React163__default.createElement(SelectContent2, null, subjects.map((subject) => /* @__PURE__ */ React163__default.createElement(
168476
- SelectItem2,
168477
- {
168478
- key: subject.code,
168479
- value: subject.code
168480
- },
168481
- subject.name,
168482
- " (",
168483
- subject.code,
168484
- ")"
168485
- )))
168486
- ))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(
168487
- Button,
168488
- {
168489
- type: "button",
168490
- variant: "outline",
168491
- onClick: () => setIsDialogOpen(false),
168492
- disabled: isPending
168493
- },
168494
- "Cancel"
168495
- ), /* @__PURE__ */ React163__default.createElement(
168496
- Button,
168497
- {
168498
- type: "submit",
168499
- onClick: handleSubmit,
168500
- disabled: isPending || !itemName.trim() || !itemCode.trim() || !selectedSubjectCode
168501
- },
168502
- isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
168503
- " ",
168504
- "Save"
168505
- )))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete topic "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(
168506
- AlertDialogAction2,
168507
- {
168508
- onClick: confirmDelete,
168509
- disabled: isPending,
168510
- className: "bg-destructive hover:bg-destructive/90"
168511
- },
168512
- isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
168513
- " ",
168514
- "Delete"
168515
- ))))));
168438
+ return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(Tag, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Topics"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm", disabled: subjects.length === 0 }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Topic")), subjects.length === 0 && !isLoading && /* @__PURE__ */ React163__default.createElement("p", { className: "text-sm text-destructive" }, "Please add subjects before adding topics.")), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : topics.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No topics found. Add one to get started!") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, topics.map((topic) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: topic.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, topic.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, topic.name), /* @__PURE__ */ React163__default.createElement(TableCell, null, getSubjectName(topic.subjectCode), " (", topic.subjectCode, ")"), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(topic), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(topic), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Topic" : "Add New Topic")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Topic Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., ALG-BASICS", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Topic Name"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Algebra Basics" })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject"), /* @__PURE__ */ React163__default.createElement(Select2, { value: selectedSubjectCode, onValueChange: setSelectedSubjectCode, disabled: subjects.length === 0 }, /* @__PURE__ */ React163__default.createElement(SelectTrigger2, { id: "subjectCode" }, /* @__PURE__ */ React163__default.createElement(SelectValue2, { placeholder: "Select a subject" })), /* @__PURE__ */ React163__default.createElement(SelectContent2, null, subjects.map((subject) => /* @__PURE__ */ React163__default.createElement(SelectItem2, { key: subject.code, value: subject.code }, subject.name, " (", subject.code, ")")))))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemName.trim() || !itemCode.trim() || !selectedSubjectCode }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete topic "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
168516
168439
  }
168517
168440
 
168518
168441
  // src/react-ui/components/metadata/CategoryManager.tsx
168519
168442
  init_react_shim();
168520
- function CategoryManager() {
168443
+ function CategoryManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
168521
168444
  const [items, setItems] = useState([]);
168522
168445
  const [isLoading, setIsLoading] = useState(true);
168523
168446
  const [isDialogOpen, setIsDialogOpen] = useState(false);
@@ -168529,19 +168452,27 @@ function CategoryManager() {
168529
168452
  const [itemToDelete, setItemToDelete] = useState(null);
168530
168453
  const [isPending, startTransition] = useTransition();
168531
168454
  const { toast: toast2 } = useToast();
168532
- useEffect(() => {
168533
- fetchItems();
168534
- }, []);
168535
- const fetchItems = () => {
168536
- setIsLoading(true);
168537
- try {
168538
- setItems(MetadataService.getCategories());
168539
- } catch (error) {
168540
- toast2({ title: "Error", description: "Failed to fetch categories.", variant: "destructive" });
168541
- } finally {
168542
- setIsLoading(false);
168455
+ const isControlled = initialData !== void 0;
168456
+ const refreshData = () => {
168457
+ if (!isControlled) {
168458
+ setIsLoading(true);
168459
+ try {
168460
+ setItems(MetadataService.getCategories());
168461
+ } catch (error) {
168462
+ toast2({ title: "Error", description: "Failed to refresh categories.", variant: "destructive" });
168463
+ } finally {
168464
+ setIsLoading(false);
168465
+ }
168543
168466
  }
168544
168467
  };
168468
+ useEffect(() => {
168469
+ if (isControlled) {
168470
+ setItems(initialData || []);
168471
+ setIsLoading(isLoadingProp || false);
168472
+ } else {
168473
+ refreshData();
168474
+ }
168475
+ }, [isControlled, initialData, isLoadingProp]);
168545
168476
  const handleAddItem = () => {
168546
168477
  setCurrentItem(null);
168547
168478
  setItemName("");
@@ -168562,13 +168493,17 @@ function CategoryManager() {
168562
168493
  };
168563
168494
  const confirmDelete = () => {
168564
168495
  if (!itemToDelete) return;
168565
- startTransition(() => {
168496
+ startTransition(async () => {
168566
168497
  try {
168567
- MetadataService.deleteCategory(itemToDelete.code);
168498
+ if (isControlled && onDelete) {
168499
+ await onDelete(itemToDelete);
168500
+ } else {
168501
+ MetadataService.deleteCategory(itemToDelete.code);
168502
+ refreshData();
168503
+ }
168568
168504
  toast2({ title: "Success", description: `Category "${itemToDelete.name}" deleted.` });
168569
- fetchItems();
168570
168505
  } catch (error) {
168571
- toast2({ title: "Error", description: "Failed to delete category.", variant: "destructive" });
168506
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
168572
168507
  } finally {
168573
168508
  setIsAlertOpen(false);
168574
168509
  setItemToDelete(null);
@@ -168580,27 +168515,37 @@ function CategoryManager() {
168580
168515
  toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
168581
168516
  return;
168582
168517
  }
168583
- startTransition(() => {
168518
+ startTransition(async () => {
168584
168519
  try {
168585
168520
  if (currentItem) {
168586
- MetadataService.updateCategory(currentItem.id, itemName, itemCode, itemDescription);
168521
+ if (isControlled && onUpdate) {
168522
+ await onUpdate({ id: currentItem.id, name: itemName, code: itemCode, description: itemDescription });
168523
+ } else {
168524
+ MetadataService.updateCategory(currentItem.id, itemName, itemCode, itemDescription);
168525
+ refreshData();
168526
+ }
168527
+ toast2({ title: "Success", description: "Category updated." });
168587
168528
  } else {
168588
- MetadataService.addCategory(itemName, itemCode, itemDescription);
168529
+ if (isControlled && onAdd) {
168530
+ await onAdd({ name: itemName, code: itemCode, description: itemDescription });
168531
+ } else {
168532
+ MetadataService.addCategory(itemName, itemCode, itemDescription);
168533
+ refreshData();
168534
+ }
168535
+ toast2({ title: "Success", description: "Category added." });
168589
168536
  }
168590
- toast2({ title: "Success", description: "Category saved." });
168591
- fetchItems();
168592
168537
  setIsDialogOpen(false);
168593
168538
  } catch (error) {
168594
- toast2({ title: "Error", description: "Failed to save category.", variant: "destructive" });
168539
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
168595
168540
  }
168596
168541
  });
168597
168542
  };
168598
- return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(Layers, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Categories"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Category"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No categories found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Category" : "Add New Category")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., CORE_CONCEPT", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Core Concept" })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Fundamental ideas within a subject." }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemName.trim() || !itemCode.trim() }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), "Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), "Delete"))))));
168543
+ return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(Layers, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Categories"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Category"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No categories found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Category" : "Add New Category")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., CORE_CONCEPT", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Core Concept" })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Fundamental ideas within a subject." }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemName.trim() || !itemCode.trim() }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
168599
168544
  }
168600
168545
 
168601
168546
  // src/react-ui/components/metadata/BloomLevelManager.tsx
168602
168547
  init_react_shim();
168603
- function BloomLevelManager() {
168548
+ function BloomLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
168604
168549
  const [items, setItems] = useState([]);
168605
168550
  const [isLoading, setIsLoading] = useState(true);
168606
168551
  const [isDialogOpen, setIsDialogOpen] = useState(false);
@@ -168612,19 +168557,27 @@ function BloomLevelManager() {
168612
168557
  const [itemToDelete, setItemToDelete] = useState(null);
168613
168558
  const [isPending, startTransition] = useTransition();
168614
168559
  const { toast: toast2 } = useToast();
168615
- useEffect(() => {
168616
- fetchItems();
168617
- }, []);
168618
- const fetchItems = () => {
168619
- setIsLoading(true);
168620
- try {
168621
- setItems(MetadataService.getBloomLevels());
168622
- } catch (error) {
168623
- toast2({ title: "Error", description: "Failed to fetch Bloom's Levels.", variant: "destructive" });
168624
- } finally {
168625
- setIsLoading(false);
168560
+ const isControlled = initialData !== void 0;
168561
+ const refreshData = () => {
168562
+ if (!isControlled) {
168563
+ setIsLoading(true);
168564
+ try {
168565
+ setItems(MetadataService.getBloomLevels());
168566
+ } catch (error) {
168567
+ toast2({ title: "Error", description: "Failed to refresh Bloom's Levels.", variant: "destructive" });
168568
+ } finally {
168569
+ setIsLoading(false);
168570
+ }
168626
168571
  }
168627
168572
  };
168573
+ useEffect(() => {
168574
+ if (isControlled) {
168575
+ setItems(initialData || []);
168576
+ setIsLoading(isLoadingProp || false);
168577
+ } else {
168578
+ refreshData();
168579
+ }
168580
+ }, [isControlled, initialData, isLoadingProp]);
168628
168581
  const handleAddItem = () => {
168629
168582
  setCurrentItem(null);
168630
168583
  setItemCode("");
@@ -168645,13 +168598,17 @@ function BloomLevelManager() {
168645
168598
  };
168646
168599
  const confirmDelete = () => {
168647
168600
  if (!itemToDelete) return;
168648
- startTransition(() => {
168601
+ startTransition(async () => {
168649
168602
  try {
168650
- MetadataService.deleteBloomLevel(itemToDelete.code);
168603
+ if (isControlled && onDelete) {
168604
+ await onDelete(itemToDelete);
168605
+ } else {
168606
+ MetadataService.deleteBloomLevel(itemToDelete.code);
168607
+ refreshData();
168608
+ }
168651
168609
  toast2({ title: "Success", description: `Bloom's Level "${itemToDelete.name}" deleted.` });
168652
- fetchItems();
168653
168610
  } catch (error) {
168654
- toast2({ title: "Error", description: "Failed to delete Bloom's Level.", variant: "destructive" });
168611
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
168655
168612
  } finally {
168656
168613
  setIsAlertOpen(false);
168657
168614
  setItemToDelete(null);
@@ -168663,27 +168620,37 @@ function BloomLevelManager() {
168663
168620
  toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
168664
168621
  return;
168665
168622
  }
168666
- startTransition(() => {
168623
+ startTransition(async () => {
168667
168624
  try {
168668
168625
  if (currentItem) {
168669
- MetadataService.updateBloomLevel(currentItem.id, itemName, itemCode, itemDescription);
168626
+ if (isControlled && onUpdate) {
168627
+ await onUpdate({ id: currentItem.id, name: itemName, code: itemCode, description: itemDescription });
168628
+ } else {
168629
+ MetadataService.updateBloomLevel(currentItem.id, itemName, itemCode, itemDescription);
168630
+ refreshData();
168631
+ }
168632
+ toast2({ title: "Success", description: "Bloom's Level updated." });
168670
168633
  } else {
168671
- MetadataService.addBloomLevel(itemName, itemCode, itemDescription);
168634
+ if (isControlled && onAdd) {
168635
+ await onAdd({ name: itemName, code: itemCode, description: itemDescription });
168636
+ } else {
168637
+ MetadataService.addBloomLevel(itemName, itemCode, itemDescription);
168638
+ refreshData();
168639
+ }
168640
+ toast2({ title: "Success", description: "Bloom's Level added." });
168672
168641
  }
168673
- toast2({ title: "Success", description: "Bloom's Level saved." });
168674
- fetchItems();
168675
168642
  setIsDialogOpen(false);
168676
168643
  } catch (error) {
168677
- toast2({ title: "Error", description: "Failed to save Bloom's Level.", variant: "destructive" });
168644
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
168678
168645
  }
168679
168646
  });
168680
168647
  };
168681
- return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(Brain, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Bloom's Levels"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Bloom's Level"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Bloom's Levels found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Bloom's Level" : "Add New Bloom's Level")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., REMEMBER", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Remembering" })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Recall facts and basic concepts." }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemCode.trim() || !itemName.trim() }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), "Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), "Delete"))))));
168648
+ return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(Brain, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Bloom's Levels"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Bloom's Level"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Bloom's Levels found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Bloom's Level" : "Add New Bloom's Level")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., REMEMBER", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Remembering" })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Recall facts and basic concepts." }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemCode.trim() || !itemName.trim() }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
168682
168649
  }
168683
168650
 
168684
168651
  // src/react-ui/components/metadata/QuestionTypeManager.tsx
168685
168652
  init_react_shim();
168686
- function QuestionTypeManager() {
168653
+ function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
168687
168654
  const [items, setItems] = useState([]);
168688
168655
  const [isLoading, setIsLoading] = useState(true);
168689
168656
  const [isDialogOpen, setIsDialogOpen] = useState(false);
@@ -168695,19 +168662,27 @@ function QuestionTypeManager() {
168695
168662
  const [itemToDelete, setItemToDelete] = useState(null);
168696
168663
  const [isPending, startTransition] = useTransition();
168697
168664
  const { toast: toast2 } = useToast();
168698
- useEffect(() => {
168699
- fetchItems();
168700
- }, []);
168701
- const fetchItems = () => {
168702
- setIsLoading(true);
168703
- try {
168704
- setItems(MetadataService.getQuestionTypes());
168705
- } catch (error) {
168706
- toast2({ title: "Error", description: "Failed to fetch Question Types.", variant: "destructive" });
168707
- } finally {
168708
- setIsLoading(false);
168665
+ const isControlled = initialData !== void 0;
168666
+ const refreshData = () => {
168667
+ if (!isControlled) {
168668
+ setIsLoading(true);
168669
+ try {
168670
+ setItems(MetadataService.getQuestionTypes());
168671
+ } catch (error) {
168672
+ toast2({ title: "Error", description: "Failed to refresh Question Types.", variant: "destructive" });
168673
+ } finally {
168674
+ setIsLoading(false);
168675
+ }
168709
168676
  }
168710
168677
  };
168678
+ useEffect(() => {
168679
+ if (isControlled) {
168680
+ setItems(initialData || []);
168681
+ setIsLoading(isLoadingProp || false);
168682
+ } else {
168683
+ refreshData();
168684
+ }
168685
+ }, [isControlled, initialData, isLoadingProp]);
168711
168686
  const handleAddItem = () => {
168712
168687
  setCurrentItem(null);
168713
168688
  setItemCode("");
@@ -168728,13 +168703,17 @@ function QuestionTypeManager() {
168728
168703
  };
168729
168704
  const confirmDelete = () => {
168730
168705
  if (!itemToDelete) return;
168731
- startTransition(() => {
168706
+ startTransition(async () => {
168732
168707
  try {
168733
- MetadataService.deleteQuestionType(itemToDelete.code);
168708
+ if (isControlled && onDelete) {
168709
+ await onDelete(itemToDelete);
168710
+ } else {
168711
+ MetadataService.deleteQuestionType(itemToDelete.code);
168712
+ refreshData();
168713
+ }
168734
168714
  toast2({ title: "Success", description: `Question Type "${itemToDelete.name}" deleted.` });
168735
- fetchItems();
168736
168715
  } catch (error) {
168737
- toast2({ title: "Error", description: "Failed to delete Question Type.", variant: "destructive" });
168716
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
168738
168717
  } finally {
168739
168718
  setIsAlertOpen(false);
168740
168719
  setItemToDelete(null);
@@ -168746,27 +168725,37 @@ function QuestionTypeManager() {
168746
168725
  toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
168747
168726
  return;
168748
168727
  }
168749
- startTransition(() => {
168728
+ startTransition(async () => {
168750
168729
  try {
168751
168730
  if (currentItem) {
168752
- MetadataService.updateQuestionType(currentItem.id, itemName, itemCode, itemDescription);
168731
+ if (isControlled && onUpdate) {
168732
+ await onUpdate({ id: currentItem.id, name: itemName, code: itemCode, description: itemDescription });
168733
+ } else {
168734
+ MetadataService.updateQuestionType(currentItem.id, itemName, itemCode, itemDescription);
168735
+ refreshData();
168736
+ }
168737
+ toast2({ title: "Success", description: "Question Type updated." });
168753
168738
  } else {
168754
- MetadataService.addQuestionType(itemName, itemCode, itemDescription);
168739
+ if (isControlled && onAdd) {
168740
+ await onAdd({ name: itemName, code: itemCode, description: itemDescription });
168741
+ } else {
168742
+ MetadataService.addQuestionType(itemName, itemCode, itemDescription);
168743
+ refreshData();
168744
+ }
168745
+ toast2({ title: "Success", description: "Question Type added." });
168755
168746
  }
168756
- toast2({ title: "Success", description: "Question Type saved." });
168757
- fetchItems();
168758
168747
  setIsDialogOpen(false);
168759
168748
  } catch (error) {
168760
- toast2({ title: "Error", description: "Failed to save Question Type.", variant: "destructive" });
168749
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
168761
168750
  }
168762
168751
  });
168763
168752
  };
168764
- return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(CircleHelp, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Question Types"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Question Type"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Question Types found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Question Type" : "Add New Question Type")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., MCQ", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Multiple Choice" })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Select one answer from a list of options." }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemCode.trim() || !itemName.trim() }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), "Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), "Delete"))))));
168753
+ return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(CircleHelp, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Question Types"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Question Type"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Question Types found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Question Type" : "Add New Question Type")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toLowerCase().replace(/ /g, "_")), placeholder: "e.g., multiple_choice", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Multiple Choice" })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Select one answer from a list of options." }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemCode.trim() || !itemName.trim() }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
168765
168754
  }
168766
168755
 
168767
168756
  // src/react-ui/components/metadata/LearningObjectiveManager.tsx
168768
168757
  init_react_shim();
168769
- function LearningObjectiveManager() {
168758
+ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
168770
168759
  const [items, setItems] = useState([]);
168771
168760
  const [subjects, setSubjects] = useState([]);
168772
168761
  const [isLoading, setIsLoading] = useState(true);
@@ -168780,34 +168769,35 @@ function LearningObjectiveManager() {
168780
168769
  const [itemToDelete, setItemToDelete] = useState(null);
168781
168770
  const [isPending, startTransition] = useTransition();
168782
168771
  const { toast: toast2 } = useToast();
168783
- const fetchData = () => {
168784
- setIsLoading(true);
168785
- try {
168786
- const loData = MetadataService.getLearningObjectives();
168787
- const subjectsData = MetadataService.getSubjects();
168788
- setItems(loData);
168789
- setSubjects(subjectsData);
168790
- } catch (error) {
168791
- toast2({
168792
- title: "Error",
168793
- description: "Failed to fetch Learning Objectives or Subjects.",
168794
- variant: "destructive"
168795
- });
168796
- } finally {
168797
- setIsLoading(false);
168772
+ const isControlled = initialData !== void 0;
168773
+ const refreshData = () => {
168774
+ if (!isControlled) {
168775
+ setIsLoading(true);
168776
+ try {
168777
+ setItems(MetadataService.getLearningObjectives());
168778
+ setSubjects(MetadataService.getSubjects());
168779
+ } catch (error) {
168780
+ toast2({ title: "Error", description: "Failed to refresh data.", variant: "destructive" });
168781
+ } finally {
168782
+ setIsLoading(false);
168783
+ }
168798
168784
  }
168799
168785
  };
168800
168786
  useEffect(() => {
168801
- fetchData();
168802
- }, []);
168787
+ if (isControlled) {
168788
+ setItems(initialData || []);
168789
+ setSubjects(subjectsProp || []);
168790
+ setIsLoading(isLoadingProp || false);
168791
+ } else {
168792
+ refreshData();
168793
+ }
168794
+ }, [isControlled, initialData, subjectsProp, isLoadingProp]);
168803
168795
  const handleAddItem = () => {
168804
168796
  setCurrentItem(null);
168805
168797
  setItemName("");
168806
168798
  setItemCode("");
168807
168799
  setItemDescription("");
168808
- setSelectedSubjectCode(
168809
- subjects.length > 0 ? subjects[0].code : void 0
168810
- );
168800
+ setSelectedSubjectCode(subjects.length > 0 ? subjects[0].code : void 0);
168811
168801
  setIsDialogOpen(true);
168812
168802
  };
168813
168803
  const handleEditItem = (item) => {
@@ -168824,20 +168814,17 @@ function LearningObjectiveManager() {
168824
168814
  };
168825
168815
  const confirmDelete = () => {
168826
168816
  if (!itemToDelete) return;
168827
- startTransition(() => {
168817
+ startTransition(async () => {
168828
168818
  try {
168829
- MetadataService.deleteLearningObjective(itemToDelete.code);
168830
- toast2({
168831
- title: "Success",
168832
- description: `Learning Objective "${itemToDelete.name}" deleted.`
168833
- });
168834
- fetchData();
168819
+ if (isControlled && onDelete) {
168820
+ await onDelete(itemToDelete);
168821
+ } else {
168822
+ MetadataService.deleteLearningObjective(itemToDelete.code);
168823
+ refreshData();
168824
+ }
168825
+ toast2({ title: "Success", description: `Learning Objective "${itemToDelete.name}" deleted.` });
168835
168826
  } catch (error) {
168836
- toast2({
168837
- title: "Error",
168838
- description: "Failed to delete Learning Objective.",
168839
- variant: "destructive"
168840
- });
168827
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
168841
168828
  } finally {
168842
168829
  setIsAlertOpen(false);
168843
168830
  setItemToDelete(null);
@@ -168846,43 +168833,31 @@ function LearningObjectiveManager() {
168846
168833
  };
168847
168834
  const handleSubmit = () => {
168848
168835
  if (!itemName.trim() || !itemCode.trim()) {
168849
- toast2({
168850
- title: "Validation Error",
168851
- description: "Code and Name are required.",
168852
- variant: "destructive"
168853
- });
168836
+ toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
168854
168837
  return;
168855
168838
  }
168856
- startTransition(() => {
168839
+ startTransition(async () => {
168857
168840
  try {
168858
168841
  if (currentItem) {
168859
- MetadataService.updateLearningObjective(
168860
- currentItem.id,
168861
- itemName,
168862
- itemCode,
168863
- selectedSubjectCode,
168864
- itemDescription
168865
- );
168842
+ if (isControlled && onUpdate) {
168843
+ await onUpdate({ id: currentItem.id, name: itemName, code: itemCode, subjectCode: selectedSubjectCode, description: itemDescription });
168844
+ } else {
168845
+ MetadataService.updateLearningObjective(currentItem.id, itemName, itemCode, selectedSubjectCode, itemDescription);
168846
+ refreshData();
168847
+ }
168848
+ toast2({ title: "Success", description: "Learning Objective updated." });
168866
168849
  } else {
168867
- MetadataService.addLearningObjective(
168868
- itemName,
168869
- itemCode,
168870
- selectedSubjectCode,
168871
- itemDescription
168872
- );
168850
+ if (isControlled && onAdd) {
168851
+ await onAdd({ name: itemName, code: itemCode, subjectCode: selectedSubjectCode, description: itemDescription });
168852
+ } else {
168853
+ MetadataService.addLearningObjective(itemName, itemCode, selectedSubjectCode, itemDescription);
168854
+ refreshData();
168855
+ }
168856
+ toast2({ title: "Success", description: "Learning Objective added." });
168873
168857
  }
168874
- toast2({
168875
- title: "Success",
168876
- description: "Learning Objective saved."
168877
- });
168878
- fetchData();
168879
168858
  setIsDialogOpen(false);
168880
168859
  } catch (error) {
168881
- toast2({
168882
- title: "Error",
168883
- description: "Failed to save Learning Objective.",
168884
- variant: "destructive"
168885
- });
168860
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
168886
168861
  }
168887
168862
  });
168888
168863
  };
@@ -168890,100 +168865,12 @@ function LearningObjectiveManager() {
168890
168865
  if (!subjectCode) return "N/A";
168891
168866
  return subjects.find((s4) => s4.code === subjectCode)?.name || "N/A";
168892
168867
  };
168893
- return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " ", "Manage Learning Objectives"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React163__default.createElement(TableCell, null, getSubjectName(item.subjectCode)), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(
168894
- Button,
168895
- {
168896
- variant: "ghost",
168897
- size: "icon",
168898
- onClick: () => handleEditItem(item),
168899
- className: "mr-2"
168900
- },
168901
- /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })
168902
- ), /* @__PURE__ */ React163__default.createElement(
168903
- Button,
168904
- {
168905
- variant: "ghost",
168906
- size: "icon",
168907
- onClick: () => handleDeleteItem(item),
168908
- className: "text-destructive hover:text-destructive"
168909
- },
168910
- /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })
168911
- ))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React163__default.createElement(
168912
- Input,
168913
- {
168914
- id: "itemCode",
168915
- value: itemCode,
168916
- onChange: (e3) => setItemCode(
168917
- e3.target.value.toUpperCase()
168918
- ),
168919
- disabled: !!currentItem
168920
- }
168921
- )), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React163__default.createElement(
168922
- Input,
168923
- {
168924
- id: "itemName",
168925
- value: itemName,
168926
- onChange: (e3) => setItemName(e3.target.value)
168927
- }
168928
- )), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemSubject" }, "Subject (Optional)"), /* @__PURE__ */ React163__default.createElement(
168929
- Select2,
168930
- {
168931
- value: selectedSubjectCode || "",
168932
- onValueChange: (value) => setSelectedSubjectCode(
168933
- value === "_NONE_" ? void 0 : value
168934
- )
168935
- },
168936
- /* @__PURE__ */ React163__default.createElement(SelectTrigger2, { id: "itemSubject" }, /* @__PURE__ */ React163__default.createElement(SelectValue2, { placeholder: "Select a subject" })),
168937
- /* @__PURE__ */ React163__default.createElement(SelectContent2, null, /* @__PURE__ */ React163__default.createElement(SelectItem2, { value: "_NONE_" }, "No Specific Subject"), subjects.map((subject) => /* @__PURE__ */ React163__default.createElement(
168938
- SelectItem2,
168939
- {
168940
- key: subject.id,
168941
- value: subject.code
168942
- },
168943
- subject.name
168944
- )))
168945
- )), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React163__default.createElement(
168946
- Textarea,
168947
- {
168948
- id: "itemDescription",
168949
- value: itemDescription,
168950
- onChange: (e3) => setItemDescription(e3.target.value)
168951
- }
168952
- ))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(
168953
- Button,
168954
- {
168955
- type: "button",
168956
- variant: "outline",
168957
- onClick: () => setIsDialogOpen(false),
168958
- disabled: isPending
168959
- },
168960
- "Cancel"
168961
- ), /* @__PURE__ */ React163__default.createElement(
168962
- Button,
168963
- {
168964
- type: "submit",
168965
- onClick: handleSubmit,
168966
- disabled: isPending || !itemName.trim() || !itemCode.trim()
168967
- },
168968
- isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
168969
- " ",
168970
- "Save"
168971
- )))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(
168972
- AlertDialogAction2,
168973
- {
168974
- onClick: confirmDelete,
168975
- disabled: isPending,
168976
- className: "bg-destructive hover:bg-destructive/90"
168977
- },
168978
- isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }),
168979
- " ",
168980
- "Delete"
168981
- ))))));
168868
+ return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Learning Objectives"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React163__default.createElement(TableCell, null, getSubjectName(item.subjectCode)), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value) })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemSubject" }, "Subject (Optional)"), /* @__PURE__ */ React163__default.createElement(Select2, { value: selectedSubjectCode || "", onValueChange: (value) => setSelectedSubjectCode(value === "_NONE_" ? void 0 : value) }, /* @__PURE__ */ React163__default.createElement(SelectTrigger2, { id: "itemSubject" }, /* @__PURE__ */ React163__default.createElement(SelectValue2, { placeholder: "Select a subject" })), /* @__PURE__ */ React163__default.createElement(SelectContent2, null, /* @__PURE__ */ React163__default.createElement(SelectItem2, { value: "_NONE_" }, "No Specific Subject"), subjects.map((subject) => /* @__PURE__ */ React163__default.createElement(SelectItem2, { key: subject.id, value: subject.code }, subject.name))))), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value) }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemName.trim() || !itemCode.trim() }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
168982
168869
  }
168983
168870
 
168984
168871
  // src/react-ui/components/metadata/ContextManager.tsx
168985
168872
  init_react_shim();
168986
- function ContextManager() {
168873
+ function ContextManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
168987
168874
  const [items, setItems] = useState([]);
168988
168875
  const [isLoading, setIsLoading] = useState(true);
168989
168876
  const [isDialogOpen, setIsDialogOpen] = useState(false);
@@ -168995,19 +168882,27 @@ function ContextManager() {
168995
168882
  const [itemToDelete, setItemToDelete] = useState(null);
168996
168883
  const [isPending, startTransition] = useTransition();
168997
168884
  const { toast: toast2 } = useToast();
168998
- useEffect(() => {
168999
- fetchItems();
169000
- }, []);
169001
- const fetchItems = () => {
169002
- setIsLoading(true);
169003
- try {
169004
- setItems(MetadataService.getContexts());
169005
- } catch (error) {
169006
- toast2({ title: "Error", description: "Failed to fetch Contexts.", variant: "destructive" });
169007
- } finally {
169008
- setIsLoading(false);
168885
+ const isControlled = initialData !== void 0;
168886
+ const refreshData = () => {
168887
+ if (!isControlled) {
168888
+ setIsLoading(true);
168889
+ try {
168890
+ setItems(MetadataService.getContexts());
168891
+ } catch (error) {
168892
+ toast2({ title: "Error", description: "Failed to refresh Contexts.", variant: "destructive" });
168893
+ } finally {
168894
+ setIsLoading(false);
168895
+ }
169009
168896
  }
169010
168897
  };
168898
+ useEffect(() => {
168899
+ if (isControlled) {
168900
+ setItems(initialData || []);
168901
+ setIsLoading(isLoadingProp || false);
168902
+ } else {
168903
+ refreshData();
168904
+ }
168905
+ }, [isControlled, initialData, isLoadingProp]);
169011
168906
  const handleAddItem = () => {
169012
168907
  setCurrentItem(null);
169013
168908
  setItemName("");
@@ -169028,13 +168923,17 @@ function ContextManager() {
169028
168923
  };
169029
168924
  const confirmDelete = () => {
169030
168925
  if (!itemToDelete) return;
169031
- startTransition(() => {
168926
+ startTransition(async () => {
169032
168927
  try {
169033
- MetadataService.deleteContext(itemToDelete.code);
168928
+ if (isControlled && onDelete) {
168929
+ await onDelete(itemToDelete);
168930
+ } else {
168931
+ MetadataService.deleteContext(itemToDelete.code);
168932
+ refreshData();
168933
+ }
169034
168934
  toast2({ title: "Success", description: `Context "${itemToDelete.name}" deleted.` });
169035
- fetchItems();
169036
168935
  } catch (error) {
169037
- toast2({ title: "Error", description: "Failed to delete Context.", variant: "destructive" });
168936
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
169038
168937
  } finally {
169039
168938
  setIsAlertOpen(false);
169040
168939
  setItemToDelete(null);
@@ -169046,32 +168945,50 @@ function ContextManager() {
169046
168945
  toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
169047
168946
  return;
169048
168947
  }
169049
- startTransition(() => {
168948
+ startTransition(async () => {
169050
168949
  try {
169051
168950
  if (currentItem) {
169052
- MetadataService.updateContext(currentItem.id, itemName, itemCode, itemDescription);
168951
+ if (isControlled && onUpdate) {
168952
+ await onUpdate({ id: currentItem.id, name: itemName, code: itemCode, description: itemDescription });
168953
+ } else {
168954
+ MetadataService.updateContext(currentItem.id, itemName, itemCode, itemDescription);
168955
+ refreshData();
168956
+ }
168957
+ toast2({ title: "Success", description: "Context updated." });
169053
168958
  } else {
169054
- MetadataService.addContext(itemName, itemCode, itemDescription);
168959
+ if (isControlled && onAdd) {
168960
+ await onAdd({ name: itemName, code: itemCode, description: itemDescription });
168961
+ } else {
168962
+ MetadataService.addContext(itemName, itemCode, itemDescription);
168963
+ refreshData();
168964
+ }
168965
+ toast2({ title: "Success", description: "Context added." });
169055
168966
  }
169056
- toast2({ title: "Success", description: "Context saved." });
169057
- fetchItems();
169058
168967
  setIsDialogOpen(false);
169059
168968
  } catch (error) {
169060
- toast2({ title: "Error", description: "Failed to save Context.", variant: "destructive" });
168969
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
169061
168970
  }
169062
168971
  });
169063
168972
  };
169064
- return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(ScanText, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Contexts"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Context"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Contexts found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Context" : "Add New Context")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., HIST_INQ", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Historical Inquiry" })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Analyzing primary and secondary sources." }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemCode.trim() || !itemName.trim() }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), "Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), "Delete"))))));
168973
+ return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(ScanText, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Contexts"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Context"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Contexts found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Context" : "Add New Context")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., HIST_INQ", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React163__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Historical Inquiry" })), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Analyzing primary and secondary sources." }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemCode.trim() || !itemName.trim() }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
169065
168974
  }
169066
168975
 
169067
168976
  // src/react-ui/components/metadata/ApproachManager.tsx
169068
168977
  init_react_shim();
169069
168978
  var knowledgeDimensions = ["Factual", "Conceptual", "Procedural"];
169070
168979
  var rawDifficultyLevels = ["E", "E~M", "M", "M~H", "H"];
169071
- function ApproachManager() {
168980
+ function ApproachManager({
168981
+ initialData,
168982
+ bloomLevels: bloomLevelsProp,
168983
+ questionTypes: questionTypesProp,
168984
+ isLoading: isLoadingProp,
168985
+ onAdd,
168986
+ onUpdate,
168987
+ onDelete
168988
+ }) {
169072
168989
  const [items, setItems] = useState([]);
169073
168990
  const [bloomLevels, setBloomLevels] = useState([]);
169074
- const [iSpringQuizTypeOptions, setISpringQuizTypeOptions] = useState([]);
168991
+ const [questionTypes, setQuestionTypes] = useState([]);
169075
168992
  const [isLoading, setIsLoading] = useState(true);
169076
168993
  const [isDialogOpen, setIsDialogOpen] = useState(false);
169077
168994
  const [isAlertOpen, setIsAlertOpen] = useState(false);
@@ -169080,30 +168997,37 @@ function ApproachManager() {
169080
168997
  const [itemToDelete, setItemToDelete] = useState(null);
169081
168998
  const [isPending, startTransition] = useTransition();
169082
168999
  const { toast: toast2 } = useToast();
169083
- const fetchItems = () => {
169084
- setIsLoading(true);
169085
- try {
169086
- const approaches = MetadataService.getApproaches();
169087
- const bloomLevelsData = MetadataService.getBloomLevels();
169088
- const questionTypesData = MetadataService.getQuestionTypes();
169089
- setItems(approaches);
169090
- setBloomLevels(bloomLevelsData);
169091
- setISpringQuizTypeOptions(questionTypesData.map((qt) => ({ label: qt.name, value: qt.code })));
169092
- } catch (error) {
169093
- toast2({ title: "Error", description: "Failed to fetch metadata.", variant: "destructive" });
169094
- } finally {
169095
- setIsLoading(false);
169000
+ const isControlled = initialData !== void 0;
169001
+ const refreshData = () => {
169002
+ if (!isControlled) {
169003
+ setIsLoading(true);
169004
+ try {
169005
+ setItems(MetadataService.getApproaches());
169006
+ setBloomLevels(MetadataService.getBloomLevels());
169007
+ setQuestionTypes(MetadataService.getQuestionTypes());
169008
+ } catch (error) {
169009
+ toast2({ title: "Error", description: "Failed to refresh metadata for Approaches.", variant: "destructive" });
169010
+ } finally {
169011
+ setIsLoading(false);
169012
+ }
169096
169013
  }
169097
169014
  };
169098
169015
  useEffect(() => {
169099
- fetchItems();
169100
- }, []);
169016
+ if (isControlled) {
169017
+ setItems(initialData || []);
169018
+ setBloomLevels(bloomLevelsProp || []);
169019
+ setQuestionTypes(questionTypesProp || []);
169020
+ setIsLoading(isLoadingProp || false);
169021
+ } else {
169022
+ refreshData();
169023
+ }
169024
+ }, [isControlled, initialData, bloomLevelsProp, questionTypesProp, isLoadingProp]);
169101
169025
  const resetForm = () => {
169102
169026
  setFormState({
169103
169027
  knowledgeDimension: "Factual",
169104
169028
  rawDifficulty: "E",
169105
169029
  bloomLevelCode: bloomLevels.length > 0 ? bloomLevels[0].code : "",
169106
- iSpringQuizType: iSpringQuizTypeOptions.length > 0 ? iSpringQuizTypeOptions[0].value : "multiple_choice"
169030
+ iSpringQuizType: questionTypes.length > 0 ? questionTypes[0].code : "multiple_choice"
169107
169031
  });
169108
169032
  };
169109
169033
  const handleAddItem = () => {
@@ -169133,13 +169057,17 @@ function ApproachManager() {
169133
169057
  };
169134
169058
  const confirmDelete = () => {
169135
169059
  if (!itemToDelete) return;
169136
- startTransition(() => {
169060
+ startTransition(async () => {
169137
169061
  try {
169138
- MetadataService.deleteApproach(itemToDelete.code);
169062
+ if (isControlled && onDelete) {
169063
+ await onDelete(itemToDelete);
169064
+ } else {
169065
+ MetadataService.deleteApproach(itemToDelete.code);
169066
+ refreshData();
169067
+ }
169139
169068
  toast2({ title: "Success", description: `Approach "${itemToDelete.code}" deleted.` });
169140
- fetchItems();
169141
169069
  } catch (error) {
169142
- toast2({ title: "Error", description: "Failed to delete Approach.", variant: "destructive" });
169070
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
169143
169071
  } finally {
169144
169072
  setIsAlertOpen(false);
169145
169073
  setItemToDelete(null);
@@ -169147,28 +169075,37 @@ function ApproachManager() {
169147
169075
  });
169148
169076
  };
169149
169077
  const handleSubmit = () => {
169150
- const { code: code4, verbEn, verbVi } = formState;
169151
- if (!code4?.trim() || !verbEn?.trim() || !verbVi?.trim()) {
169152
- toast2({ title: "Validation Error", description: "Code, Verb (EN), and Verb (VI) are required.", variant: "destructive" });
169078
+ const { code: code4, verbEn, verbVi, bloomLevelCode, iSpringQuizType, knowledgeDimension, rawDifficulty } = formState;
169079
+ if (!code4?.trim() || !verbEn?.trim() || !verbVi?.trim() || !bloomLevelCode || !iSpringQuizType || !knowledgeDimension || !rawDifficulty) {
169080
+ toast2({ title: "Validation Error", description: "All fields except examples and context are required.", variant: "destructive" });
169153
169081
  return;
169154
169082
  }
169155
- startTransition(() => {
169083
+ startTransition(async () => {
169156
169084
  try {
169157
169085
  if (currentItem) {
169158
- MetadataService.updateApproach(currentItem.id, formState);
169086
+ if (isControlled && onUpdate) {
169087
+ await onUpdate({ ...currentItem, ...formState });
169088
+ } else {
169089
+ MetadataService.updateApproach(currentItem.id, formState);
169090
+ refreshData();
169091
+ }
169159
169092
  toast2({ title: "Success", description: "Approach updated." });
169160
169093
  } else {
169161
- MetadataService.addApproach(formState);
169094
+ if (isControlled && onAdd) {
169095
+ await onAdd(formState);
169096
+ } else {
169097
+ MetadataService.addApproach(formState);
169098
+ refreshData();
169099
+ }
169162
169100
  toast2({ title: "Success", description: "Approach added." });
169163
169101
  }
169164
- fetchItems();
169165
169102
  setIsDialogOpen(false);
169166
169103
  } catch (error) {
169167
- toast2({ title: "Error", description: error.message || "Failed to save Approach.", variant: "destructive" });
169104
+ toast2({ title: "Error", description: error.message, variant: "destructive" });
169168
169105
  }
169169
169106
  });
169170
169107
  };
169171
- return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(Settings2, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Approaches"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Approach"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Approaches found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Approach ID"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Verb (VI)"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Cognitive Level"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "iSpring Type"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.verbVi), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.bloomLevelCode), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.iSpringQuizType), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Approach" : "Add New Approach")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "code" }, "Approach Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e3) => setFormState((s4) => ({ ...s4, code: e3.target.value.toUpperCase() })), placeholder: "e.g., REM-FAC-IDT-MCQ", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "verbEn" }, "Verb (English)"), /* @__PURE__ */ React163__default.createElement(Input, { id: "verbEn", value: formState.verbEn || "", onChange: (e3) => setFormState((s4) => ({ ...s4, verbEn: e3.target.value })), placeholder: "e.g., Identify" }))), /* @__PURE__ */ React163__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "verbVi" }, "Verb (Vietnamese)"), /* @__PURE__ */ React163__default.createElement(Input, { id: "verbVi", value: formState.verbVi || "", onChange: (e3) => setFormState((s4) => ({ ...s4, verbVi: e3.target.value })), placeholder: "e.g., Nh\u1EADn d\u1EA1ng" })), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "bloomLevelCode" }, "Cognitive Level"), /* @__PURE__ */ React163__default.createElement(Select2, { value: formState.bloomLevelCode, onValueChange: (v) => setFormState((s4) => ({ ...s4, bloomLevelCode: v })) }, /* @__PURE__ */ React163__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React163__default.createElement(SelectValue2, null)), /* @__PURE__ */ React163__default.createElement(SelectContent2, null, bloomLevels.map((level) => /* @__PURE__ */ React163__default.createElement(SelectItem2, { key: level.code, value: level.code }, level.name)))))), /* @__PURE__ */ React163__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4" }, /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "knowledgeDimension" }, "Knowledge Dimension"), /* @__PURE__ */ React163__default.createElement(Select2, { value: formState.knowledgeDimension, onValueChange: (v) => setFormState((s4) => ({ ...s4, knowledgeDimension: v })) }, /* @__PURE__ */ React163__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React163__default.createElement(SelectValue2, null)), /* @__PURE__ */ React163__default.createElement(SelectContent2, null, knowledgeDimensions.map((kd) => /* @__PURE__ */ React163__default.createElement(SelectItem2, { key: kd, value: kd }, kd))))), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "iSpringQuizType" }, "iSpring Quiz Type"), /* @__PURE__ */ React163__default.createElement(Select2, { value: formState.iSpringQuizType, onValueChange: (v) => setFormState((s4) => ({ ...s4, iSpringQuizType: v })) }, /* @__PURE__ */ React163__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React163__default.createElement(SelectValue2, null)), /* @__PURE__ */ React163__default.createElement(SelectContent2, null, iSpringQuizTypeOptions.map((qt) => /* @__PURE__ */ React163__default.createElement(SelectItem2, { key: qt.value, value: qt.value }, qt.label))))), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "rawDifficulty" }, "Raw Difficulty"), /* @__PURE__ */ React163__default.createElement(Select2, { value: formState.rawDifficulty, onValueChange: (v) => setFormState((s4) => ({ ...s4, rawDifficulty: v })) }, /* @__PURE__ */ React163__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React163__default.createElement(SelectValue2, null)), /* @__PURE__ */ React163__default.createElement(SelectContent2, null, rawDifficultyLevels.map((rd) => /* @__PURE__ */ React163__default.createElement(SelectItem2, { key: rd, value: rd }, rd)))))), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "suggestContext" }, "Suggest Context (comma-separated codes)"), /* @__PURE__ */ React163__default.createElement(Input, { id: "suggestContext", value: formState.suggestContext || "", onChange: (e3) => setFormState((s4) => ({ ...s4, suggestContext: e3.target.value })), placeholder: "e.g., A, B, D, G, H" })), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "exampleEn" }, "Example (English)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "exampleEn", value: formState.exampleEn || "", onChange: (e3) => setFormState((s4) => ({ ...s4, exampleEn: e3.target.value })), placeholder: "English example prompt..." })), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "exampleVi" }, "Example (Vietnamese)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "exampleVi", value: formState.exampleVi || "", onChange: (e3) => setFormState((s4) => ({ ...s4, exampleVi: e3.target.value })), placeholder: "Vietnamese example prompt..." }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !formState.code?.trim() || !formState.verbEn?.trim() || !formState.verbVi?.trim() }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.code, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
169108
+ return /* @__PURE__ */ React163__default.createElement(Card, null, /* @__PURE__ */ React163__default.createElement(CardHeader, null, /* @__PURE__ */ React163__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React163__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React163__default.createElement(Settings2, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Approaches"), /* @__PURE__ */ React163__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React163__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Approach"))), /* @__PURE__ */ React163__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React163__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React163__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Approaches found.") : /* @__PURE__ */ React163__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React163__default.createElement(Table3, null, /* @__PURE__ */ React163__default.createElement(TableHeader, null, /* @__PURE__ */ React163__default.createElement(TableRow, null, /* @__PURE__ */ React163__default.createElement(TableHead, null, "Approach ID"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Verb (VI)"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "Cognitive Level"), /* @__PURE__ */ React163__default.createElement(TableHead, null, "iSpring Type"), /* @__PURE__ */ React163__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React163__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React163__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React163__default.createElement(TableCell, { className: "font-medium" }, item.code), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.verbVi), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.bloomLevelCode), /* @__PURE__ */ React163__default.createElement(TableCell, null, item.iSpringQuizType), /* @__PURE__ */ React163__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React163__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React163__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React163__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React163__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React163__default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React163__default.createElement(DialogHeader, null, /* @__PURE__ */ React163__default.createElement(DialogTitle2, null, currentItem ? "Edit Approach" : "Add New Approach")), /* @__PURE__ */ React163__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React163__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "code" }, "Approach Code"), /* @__PURE__ */ React163__default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e3) => setFormState((s4) => ({ ...s4, code: e3.target.value.toUpperCase() })), placeholder: "e.g., REM-FAC-IDT-MCQ", disabled: !!currentItem })), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "verbEn" }, "Verb (English)"), /* @__PURE__ */ React163__default.createElement(Input, { id: "verbEn", value: formState.verbEn || "", onChange: (e3) => setFormState((s4) => ({ ...s4, verbEn: e3.target.value })), placeholder: "e.g., Identify" }))), /* @__PURE__ */ React163__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "verbVi" }, "Verb (Vietnamese)"), /* @__PURE__ */ React163__default.createElement(Input, { id: "verbVi", value: formState.verbVi || "", onChange: (e3) => setFormState((s4) => ({ ...s4, verbVi: e3.target.value })), placeholder: "e.g., Nh\u1EADn d\u1EA1ng" })), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "bloomLevelCode" }, "Cognitive Level"), /* @__PURE__ */ React163__default.createElement(Select2, { value: formState.bloomLevelCode, onValueChange: (v) => setFormState((s4) => ({ ...s4, bloomLevelCode: v })) }, /* @__PURE__ */ React163__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React163__default.createElement(SelectValue2, null)), /* @__PURE__ */ React163__default.createElement(SelectContent2, null, bloomLevels.map((level) => /* @__PURE__ */ React163__default.createElement(SelectItem2, { key: level.code, value: level.code }, level.name)))))), /* @__PURE__ */ React163__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4" }, /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "knowledgeDimension" }, "Knowledge Dimension"), /* @__PURE__ */ React163__default.createElement(Select2, { value: formState.knowledgeDimension, onValueChange: (v) => setFormState((s4) => ({ ...s4, knowledgeDimension: v })) }, /* @__PURE__ */ React163__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React163__default.createElement(SelectValue2, null)), /* @__PURE__ */ React163__default.createElement(SelectContent2, null, knowledgeDimensions.map((kd) => /* @__PURE__ */ React163__default.createElement(SelectItem2, { key: kd, value: kd }, kd))))), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "iSpringQuizType" }, "iSpring Quiz Type"), /* @__PURE__ */ React163__default.createElement(Select2, { value: formState.iSpringQuizType, onValueChange: (v) => setFormState((s4) => ({ ...s4, iSpringQuizType: v })) }, /* @__PURE__ */ React163__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React163__default.createElement(SelectValue2, null)), /* @__PURE__ */ React163__default.createElement(SelectContent2, null, questionTypes.map((qt) => /* @__PURE__ */ React163__default.createElement(SelectItem2, { key: qt.code, value: qt.code }, qt.name))))), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "rawDifficulty" }, "Raw Difficulty"), /* @__PURE__ */ React163__default.createElement(Select2, { value: formState.rawDifficulty, onValueChange: (v) => setFormState((s4) => ({ ...s4, rawDifficulty: v })) }, /* @__PURE__ */ React163__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React163__default.createElement(SelectValue2, null)), /* @__PURE__ */ React163__default.createElement(SelectContent2, null, rawDifficultyLevels.map((rd) => /* @__PURE__ */ React163__default.createElement(SelectItem2, { key: rd, value: rd }, rd)))))), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "suggestContext" }, "Suggest Context (comma-separated codes)"), /* @__PURE__ */ React163__default.createElement(Input, { id: "suggestContext", value: formState.suggestContext || "", onChange: (e3) => setFormState((s4) => ({ ...s4, suggestContext: e3.target.value })), placeholder: "e.g., A, B, D, G, H" })), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "exampleEn" }, "Example (English)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "exampleEn", value: formState.exampleEn || "", onChange: (e3) => setFormState((s4) => ({ ...s4, exampleEn: e3.target.value })), placeholder: "English example prompt..." })), /* @__PURE__ */ React163__default.createElement("div", null, /* @__PURE__ */ React163__default.createElement(Label2, { htmlFor: "exampleVi" }, "Example (Vietnamese)"), /* @__PURE__ */ React163__default.createElement(Textarea, { id: "exampleVi", value: formState.exampleVi || "", onChange: (e3) => setFormState((s4) => ({ ...s4, exampleVi: e3.target.value })), placeholder: "Vietnamese example prompt..." }))), /* @__PURE__ */ React163__default.createElement(DialogFooter, null, /* @__PURE__ */ React163__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React163__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React163__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React163__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React163__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React163__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.code, '".')), /* @__PURE__ */ React163__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React163__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React163__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React163__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
169172
169109
  }
169173
169110
 
169174
169111
  // src/react-ui/components/metadata/MetadataTabs.tsx