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