@thanh01.pmt/interactive-quiz-kit 1.0.23 → 1.0.24

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.
@@ -29,6 +29,8 @@ var reactI18next = require('react-i18next');
29
29
  var ScrollAreaPrimitive = require('@radix-ui/react-scroll-area');
30
30
  var DialogPrimitive = require('@radix-ui/react-dialog');
31
31
  var SwitchPrimitives = require('@radix-ui/react-switch');
32
+ var dateFns = require('date-fns');
33
+ var AlertDialogPrimitive = require('@radix-ui/react-alert-dialog');
32
34
  var ToastPrimitives = require('@radix-ui/react-toast');
33
35
 
34
36
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -67,6 +69,7 @@ var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
67
69
  var ScrollAreaPrimitive__namespace = /*#__PURE__*/_interopNamespace(ScrollAreaPrimitive);
68
70
  var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
69
71
  var SwitchPrimitives__namespace = /*#__PURE__*/_interopNamespace(SwitchPrimitives);
72
+ var AlertDialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(AlertDialogPrimitive);
70
73
  var ToastPrimitives__namespace = /*#__PURE__*/_interopNamespace(ToastPrimitives);
71
74
 
72
75
  var __defProp = Object.defineProperty;
@@ -2698,6 +2701,260 @@ var KnowledgeCardService = class {
2698
2701
  }
2699
2702
  };
2700
2703
 
2704
+ // src/services/metadataService.ts
2705
+ var LocalStorageManager = class {
2706
+ constructor(key) {
2707
+ this.key = `iqk_metadata_${key}`;
2708
+ }
2709
+ getAll() {
2710
+ if (typeof window === "undefined") return [];
2711
+ try {
2712
+ const stored = localStorage.getItem(this.key);
2713
+ return stored ? JSON.parse(stored) : [];
2714
+ } catch (e) {
2715
+ console.error(`Error reading from localStorage key ${this.key}:`, e);
2716
+ return [];
2717
+ }
2718
+ }
2719
+ saveAll(items) {
2720
+ if (typeof window === "undefined") return;
2721
+ try {
2722
+ localStorage.setItem(this.key, JSON.stringify(items));
2723
+ } catch (e) {
2724
+ console.error(`Error writing to localStorage key ${this.key}:`, e);
2725
+ }
2726
+ }
2727
+ add(item) {
2728
+ const items = this.getAll();
2729
+ if (items.some((i) => i.code === item.code)) {
2730
+ throw new Error(`An item with code "${item.code}" already exists for ${this.key}.`);
2731
+ }
2732
+ const newItem = __spreadProps(__spreadValues({}, item), { id: generateUniqueId(`${this.key}_`) });
2733
+ this.saveAll([...items, newItem]);
2734
+ return newItem;
2735
+ }
2736
+ // ===== FIX IS HERE =====
2737
+ // Changed the type of 'updates' to allow 'code' to be part of the update object.
2738
+ update(id, updates) {
2739
+ const items = this.getAll();
2740
+ const index = items.findIndex((i) => i.id === id);
2741
+ if (index === -1) {
2742
+ console.warn(`Item with id "${id}" not found in ${this.key} for update.`);
2743
+ return null;
2744
+ }
2745
+ const updatedItem = __spreadValues(__spreadValues({}, items[index]), updates);
2746
+ items[index] = updatedItem;
2747
+ this.saveAll(items);
2748
+ return updatedItem;
2749
+ }
2750
+ // =======================
2751
+ delete(code) {
2752
+ const items = this.getAll();
2753
+ const newItems = items.filter((i) => i.code !== code);
2754
+ if (items.length === newItems.length) {
2755
+ return false;
2756
+ }
2757
+ this.saveAll(newItems);
2758
+ return true;
2759
+ }
2760
+ };
2761
+ var subjectManager = new LocalStorageManager("subjects");
2762
+ var gradeLevelManager = new LocalStorageManager("grade_levels");
2763
+ var topicManager = new LocalStorageManager("topics");
2764
+ var categoryManager = new LocalStorageManager("categories");
2765
+ var bloomLevelManager = new LocalStorageManager("bloom_levels");
2766
+ var questionTypeManager = new LocalStorageManager("question_types");
2767
+ var learningObjectiveManager = new LocalStorageManager("learning_objectives");
2768
+ var contextManager = new LocalStorageManager("contexts");
2769
+ var approachManager = new LocalStorageManager("approaches");
2770
+ function mapRawDifficultyToStandard(rawDifficulty) {
2771
+ switch (rawDifficulty) {
2772
+ case "E":
2773
+ case "E~M":
2774
+ return "easy";
2775
+ case "M":
2776
+ case "M~H":
2777
+ return "medium";
2778
+ case "H":
2779
+ return "hard";
2780
+ default:
2781
+ return "medium";
2782
+ }
2783
+ }
2784
+ var _MetadataService = class _MetadataService {
2785
+ };
2786
+ // --- Subject Services ---
2787
+ _MetadataService.getSubjects = () => subjectManager.getAll().sort((a, b) => a.name.localeCompare(b.name));
2788
+ _MetadataService.addSubject = (name, code) => {
2789
+ return subjectManager.add({ code, name, createdAt: (/* @__PURE__ */ new Date()).toISOString(), updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
2790
+ };
2791
+ _MetadataService.updateSubject = (id, name, code) => {
2792
+ return subjectManager.update(id, { name, code, updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
2793
+ };
2794
+ _MetadataService.deleteSubject = (code) => {
2795
+ const topics = _MetadataService.getTopics(code);
2796
+ if (topics.length > 0) {
2797
+ throw new Error("Cannot delete subject: It is referenced by topics.");
2798
+ }
2799
+ return subjectManager.delete(code);
2800
+ };
2801
+ // --- GradeLevel Services ---
2802
+ _MetadataService.getGradeLevels = () => gradeLevelManager.getAll().sort((a, b) => a.name.localeCompare(b.name));
2803
+ _MetadataService.addGradeLevel = (name, code) => gradeLevelManager.add({ name, code });
2804
+ _MetadataService.updateGradeLevel = (id, name, code) => gradeLevelManager.update(id, { name, code });
2805
+ _MetadataService.deleteGradeLevel = (code) => gradeLevelManager.delete(code);
2806
+ // --- Topic Services ---
2807
+ _MetadataService.getTopics = (subjectCode) => {
2808
+ const allTopics = topicManager.getAll();
2809
+ const filtered = subjectCode ? allTopics.filter((t) => t.subjectCode === subjectCode) : allTopics;
2810
+ return filtered.sort((a, b) => a.name.localeCompare(b.name));
2811
+ };
2812
+ _MetadataService.addTopic = (name, code, subjectCode) => topicManager.add({ name, code, subjectCode });
2813
+ _MetadataService.updateTopic = (id, name, code, subjectCode) => topicManager.update(id, { name, code, subjectCode });
2814
+ _MetadataService.deleteTopic = (code) => topicManager.delete(code);
2815
+ // --- BloomLevel Services ---
2816
+ _MetadataService.getBloomLevels = () => bloomLevelManager.getAll().sort((a, b) => a.name.localeCompare(b.name));
2817
+ _MetadataService.addBloomLevel = (name, code, description) => bloomLevelManager.add({ name, code, description });
2818
+ _MetadataService.updateBloomLevel = (id, name, code, description) => bloomLevelManager.update(id, { name, code, description });
2819
+ _MetadataService.deleteBloomLevel = (code) => bloomLevelManager.delete(code);
2820
+ // --- QuestionType Services ---
2821
+ _MetadataService.getQuestionTypes = () => questionTypeManager.getAll().sort((a, b) => a.name.localeCompare(b.name));
2822
+ _MetadataService.addQuestionType = (name, code, description) => questionTypeManager.add({ name, code, description });
2823
+ _MetadataService.updateQuestionType = (id, name, code, description) => questionTypeManager.update(id, { name, code, description });
2824
+ _MetadataService.deleteQuestionType = (code) => questionTypeManager.delete(code);
2825
+ // --- Category Services ---
2826
+ _MetadataService.getCategories = () => categoryManager.getAll().sort((a, b) => a.name.localeCompare(b.name));
2827
+ _MetadataService.addCategory = (name, code, description) => categoryManager.add({ name, code, description });
2828
+ _MetadataService.updateCategory = (id, name, code, description) => categoryManager.update(id, { name, code, description });
2829
+ _MetadataService.deleteCategory = (code) => categoryManager.delete(code);
2830
+ // --- Context Services ---
2831
+ _MetadataService.getContexts = () => contextManager.getAll().sort((a, b) => a.name.localeCompare(b.name));
2832
+ _MetadataService.addContext = (name, code, description) => contextManager.add({ name, code, description });
2833
+ _MetadataService.updateContext = (id, name, code, description) => contextManager.update(id, { name, code, description });
2834
+ _MetadataService.deleteContext = (code) => contextManager.delete(code);
2835
+ // --- Approach Services ---
2836
+ _MetadataService.getApproaches = () => approachManager.getAll().sort((a, b) => a.code.localeCompare(b.code));
2837
+ _MetadataService.addApproach = (approachData) => {
2838
+ const difficulty = mapRawDifficultyToStandard(approachData.rawDifficulty);
2839
+ return approachManager.add(__spreadProps(__spreadValues({}, approachData), { difficulty }));
2840
+ };
2841
+ _MetadataService.updateApproach = (id, approachData) => {
2842
+ const updates = __spreadValues({}, approachData);
2843
+ if (approachData.rawDifficulty) {
2844
+ updates.difficulty = mapRawDifficultyToStandard(approachData.rawDifficulty);
2845
+ }
2846
+ return approachManager.update(id, updates);
2847
+ };
2848
+ _MetadataService.deleteApproach = (code) => approachManager.delete(code);
2849
+ // --- LearningObjective Services ---
2850
+ _MetadataService.getLearningObjectives = (subjectCode) => {
2851
+ const allLOs = learningObjectiveManager.getAll();
2852
+ const filtered = subjectCode ? allLOs.filter((lo) => lo.subjectCode === subjectCode) : allLOs;
2853
+ return filtered.sort((a, b) => a.name.localeCompare(b.name));
2854
+ };
2855
+ _MetadataService.addLearningObjective = (name, code, subjectCode, description) => learningObjectiveManager.add({ name, code, subjectCode, description });
2856
+ _MetadataService.updateLearningObjective = (id, name, code, subjectCode, description) => learningObjectiveManager.update(id, { name, code, subjectCode, description });
2857
+ _MetadataService.deleteLearningObjective = (code) => learningObjectiveManager.delete(code);
2858
+ var MetadataService = _MetadataService;
2859
+
2860
+ // src/services/questionBankService.ts
2861
+ var LocalStorageManager2 = class {
2862
+ constructor(key) {
2863
+ this.key = key;
2864
+ }
2865
+ getAll() {
2866
+ if (typeof window === "undefined") return [];
2867
+ try {
2868
+ const stored = localStorage.getItem(this.key);
2869
+ return stored ? JSON.parse(stored) : [];
2870
+ } catch (e) {
2871
+ console.error(`Error reading from localStorage key ${this.key}:`, e);
2872
+ return [];
2873
+ }
2874
+ }
2875
+ saveAll(items) {
2876
+ if (typeof window === "undefined") return;
2877
+ try {
2878
+ localStorage.setItem(this.key, JSON.stringify(items));
2879
+ } catch (e) {
2880
+ console.error(`Error writing to localStorage key ${this.key}:`, e);
2881
+ }
2882
+ }
2883
+ };
2884
+ var questionBankManager = new LocalStorageManager2("iqk_question_bank");
2885
+ var QuestionBankService = class {
2886
+ static getQuestions(filters) {
2887
+ let questions = questionBankManager.getAll();
2888
+ if (filters) {
2889
+ if (filters.subjectCode) {
2890
+ questions = questions.filter((q) => q.subjectCode === filters.subjectCode);
2891
+ }
2892
+ if (filters.topicCode) {
2893
+ questions = questions.filter((q) => q.topicCode === filters.topicCode);
2894
+ }
2895
+ if (filters.gradeLevelCode) {
2896
+ questions = questions.filter((q) => q.gradeLevelCode === filters.gradeLevelCode);
2897
+ }
2898
+ if (filters.bloomLevelCode) {
2899
+ questions = questions.filter((q) => q.bloomLevelCode === filters.bloomLevelCode);
2900
+ }
2901
+ if (filters.questionTypeCode) {
2902
+ questions = questions.filter((q) => q.questionTypeCode === filters.questionTypeCode);
2903
+ }
2904
+ if (filters.difficulty) {
2905
+ questions = questions.filter((q) => q.difficulty === filters.difficulty);
2906
+ }
2907
+ if (filters.searchTerm) {
2908
+ const lowercasedTerm = filters.searchTerm.toLowerCase();
2909
+ questions = questions.filter(
2910
+ (q) => q.text.toLowerCase().includes(lowercasedTerm) || q.code.toLowerCase().includes(lowercasedTerm)
2911
+ );
2912
+ }
2913
+ }
2914
+ return questions.sort((a, b) => new Date(b.lastModified).getTime() - new Date(a.lastModified).getTime());
2915
+ }
2916
+ static getQuestionByCode(code) {
2917
+ return questionBankManager.getAll().find((q) => q.code === code);
2918
+ }
2919
+ // CHANGE 2: Simplified function signature. It now takes the full object to be added.
2920
+ static addQuestion(questionData) {
2921
+ const allQuestions = questionBankManager.getAll();
2922
+ if (allQuestions.some((q) => q.code === questionData.code)) {
2923
+ throw new Error(`A question with code "${questionData.code}" already exists.`);
2924
+ }
2925
+ const newQuestion = __spreadProps(__spreadValues({}, questionData), {
2926
+ id: generateUniqueId("qb_"),
2927
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
2928
+ });
2929
+ questionBankManager.saveAll([...allQuestions, newQuestion]);
2930
+ return newQuestion;
2931
+ }
2932
+ // CHANGE 2: Simplified function signature.
2933
+ static updateQuestion(id, updates) {
2934
+ const allQuestions = questionBankManager.getAll();
2935
+ const index = allQuestions.findIndex((q) => q.id === id);
2936
+ if (index === -1) {
2937
+ console.warn(`Question with id "${id}" not found for update.`);
2938
+ return null;
2939
+ }
2940
+ const updatedQuestion = __spreadProps(__spreadValues(__spreadValues({}, allQuestions[index]), updates), {
2941
+ lastModified: (/* @__PURE__ */ new Date()).toISOString()
2942
+ });
2943
+ allQuestions[index] = updatedQuestion;
2944
+ questionBankManager.saveAll(allQuestions);
2945
+ return updatedQuestion;
2946
+ }
2947
+ static deleteQuestionByCode(code) {
2948
+ const allQuestions = questionBankManager.getAll();
2949
+ const newQuestions = allQuestions.filter((q) => q.code !== code);
2950
+ if (allQuestions.length === newQuestions.length) {
2951
+ return false;
2952
+ }
2953
+ questionBankManager.saveAll(newQuestions);
2954
+ return true;
2955
+ }
2956
+ };
2957
+
2701
2958
  // src/services/HTMLLauncherGenerator.ts
2702
2959
  var escapeAttribute = (unsafe) => {
2703
2960
  if (typeof unsafe !== "string") return "";
@@ -11130,6 +11387,1498 @@ var QuizAuthoringTool = ({
11130
11387
  }
11131
11388
  ));
11132
11389
  };
11390
+ var Table2 = React53__namespace.forwardRef((_a, ref) => {
11391
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11392
+ return /* @__PURE__ */ React53__namespace.createElement("div", { className: "relative w-full overflow-auto" }, /* @__PURE__ */ React53__namespace.createElement(
11393
+ "table",
11394
+ __spreadValues({
11395
+ ref,
11396
+ className: cn("w-full caption-bottom text-sm", className)
11397
+ }, props)
11398
+ ));
11399
+ });
11400
+ Table2.displayName = "Table";
11401
+ var TableHeader = React53__namespace.forwardRef((_a, ref) => {
11402
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11403
+ return /* @__PURE__ */ React53__namespace.createElement("thead", __spreadValues({ ref, className: cn("[&_tr]:border-b", className) }, props));
11404
+ });
11405
+ TableHeader.displayName = "TableHeader";
11406
+ var TableBody = React53__namespace.forwardRef((_a, ref) => {
11407
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11408
+ return /* @__PURE__ */ React53__namespace.createElement(
11409
+ "tbody",
11410
+ __spreadValues({
11411
+ ref,
11412
+ className: cn("[&_tr:last-child]:border-0", className)
11413
+ }, props)
11414
+ );
11415
+ });
11416
+ TableBody.displayName = "TableBody";
11417
+ var TableFooter = React53__namespace.forwardRef((_a, ref) => {
11418
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11419
+ return /* @__PURE__ */ React53__namespace.createElement(
11420
+ "tfoot",
11421
+ __spreadValues({
11422
+ ref,
11423
+ className: cn(
11424
+ "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
11425
+ className
11426
+ )
11427
+ }, props)
11428
+ );
11429
+ });
11430
+ TableFooter.displayName = "TableFooter";
11431
+ var TableRow = React53__namespace.forwardRef((_a, ref) => {
11432
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11433
+ return /* @__PURE__ */ React53__namespace.createElement(
11434
+ "tr",
11435
+ __spreadValues({
11436
+ ref,
11437
+ className: cn(
11438
+ "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
11439
+ className
11440
+ )
11441
+ }, props)
11442
+ );
11443
+ });
11444
+ TableRow.displayName = "TableRow";
11445
+ var TableHead = React53__namespace.forwardRef((_a, ref) => {
11446
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11447
+ return /* @__PURE__ */ React53__namespace.createElement(
11448
+ "th",
11449
+ __spreadValues({
11450
+ ref,
11451
+ className: cn(
11452
+ "h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
11453
+ className
11454
+ )
11455
+ }, props)
11456
+ );
11457
+ });
11458
+ TableHead.displayName = "TableHead";
11459
+ var TableCell = React53__namespace.forwardRef((_a, ref) => {
11460
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11461
+ return /* @__PURE__ */ React53__namespace.createElement(
11462
+ "td",
11463
+ __spreadValues({
11464
+ ref,
11465
+ className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className)
11466
+ }, props)
11467
+ );
11468
+ });
11469
+ TableCell.displayName = "TableCell";
11470
+ var TableCaption = React53__namespace.forwardRef((_a, ref) => {
11471
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11472
+ return /* @__PURE__ */ React53__namespace.createElement(
11473
+ "caption",
11474
+ __spreadValues({
11475
+ ref,
11476
+ className: cn("mt-4 text-sm text-muted-foreground", className)
11477
+ }, props)
11478
+ );
11479
+ });
11480
+ TableCaption.displayName = "TableCaption";
11481
+ function QuestionList({
11482
+ questions,
11483
+ onEdit,
11484
+ onDelete,
11485
+ onView
11486
+ }) {
11487
+ const [metadata, setMetadata] = React53.useState({ subjects: [], topics: [], gradeLevels: [], questionTypes: [], bloomLevels: [] });
11488
+ React53.useEffect(() => {
11489
+ const subjectsData = MetadataService.getSubjects();
11490
+ const topicsData = MetadataService.getTopics();
11491
+ const gradeLevelsData = MetadataService.getGradeLevels();
11492
+ const questionTypesData = MetadataService.getQuestionTypes();
11493
+ const bloomLevelsData = MetadataService.getBloomLevels();
11494
+ setMetadata({
11495
+ subjects: subjectsData,
11496
+ topics: topicsData,
11497
+ gradeLevels: gradeLevelsData,
11498
+ questionTypes: questionTypesData,
11499
+ bloomLevels: bloomLevelsData
11500
+ });
11501
+ }, []);
11502
+ const getLookupName = (code, items) => {
11503
+ var _a;
11504
+ if (!code || !items) return "N/A";
11505
+ return ((_a = items.find((item) => item.code === code)) == null ? void 0 : _a.name) || code;
11506
+ };
11507
+ if (questions.length === 0) {
11508
+ return /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-8" }, "No questions match the current filters. Try adjusting your search or add new questions.");
11509
+ }
11510
+ return /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React53__namespace.default.createElement(Table2, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHead, { className: "w-[30%]" }, "Question Text"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Type"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Grade"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Bloom's"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Last Modified"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React53__namespace.default.createElement(TableBody, null, questions.map((question) => /* @__PURE__ */ React53__namespace.default.createElement(TableRow, { key: question.id }, /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-medium max-w-xs truncate", title: question.text }, question.text), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, question.code), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, /* @__PURE__ */ React53__namespace.default.createElement(Badge, { variant: "secondary" }, getLookupName(question.questionTypeCode, metadata.questionTypes))), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, getLookupName(question.subjectCode, metadata.subjects)), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, getLookupName(question.topicCode, metadata.topics)), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, getLookupName(question.gradeLevelCode, metadata.gradeLevels)), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, /* @__PURE__ */ React53__namespace.default.createElement(Badge, { variant: "outline" }, getLookupName(question.bloomLevelCode, metadata.bloomLevels))), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, dateFns.format(new Date(question.lastModified), "MMM d, yyyy")), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "text-right" }, onView && /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => onView(question), className: "mr-1" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Eye, { className: "h-4 w-4" })), /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => onEdit(question), className: "mr-1" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Edit3, { className: "h-4 w-4" })), /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => onDelete(question), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Trash2, { className: "h-4 w-4" }))))))));
11511
+ }
11512
+ var ALL_ITEMS_VALUE = "_ALL_ITEMS_";
11513
+ function QuestionFilters({
11514
+ onFilterChange,
11515
+ initialFilters = {}
11516
+ }) {
11517
+ const [searchTerm, setSearchTerm] = React53.useState(initialFilters.searchTerm || "");
11518
+ const [subjectCode, setSubjectCode] = React53.useState(initialFilters.subjectCode || "");
11519
+ const [topicCode, setTopicCode] = React53.useState(initialFilters.topicCode || "");
11520
+ const [gradeLevelCode, setGradeLevelCode] = React53.useState(initialFilters.gradeLevelCode || "");
11521
+ const [bloomLevelCode, setBloomLevelCode] = React53.useState(initialFilters.bloomLevelCode || "");
11522
+ const [questionTypeCode, setQuestionTypeCode] = React53.useState(initialFilters.questionTypeCode || "");
11523
+ const [difficulty, setDifficulty] = React53.useState(initialFilters.difficulty || "");
11524
+ const [subjects, setSubjects] = React53.useState([]);
11525
+ const [allTopics, setAllTopics] = React53.useState([]);
11526
+ const [gradeLevels, setGradeLevels] = React53.useState([]);
11527
+ const [questionTypes, setQuestionTypes] = React53.useState([]);
11528
+ const [bloomLevels, setBloomLevels] = React53.useState([]);
11529
+ const [filteredTopics, setFilteredTopics] = React53.useState([]);
11530
+ React53.useEffect(() => {
11531
+ const subjectsData = MetadataService.getSubjects();
11532
+ const topicsData = MetadataService.getTopics();
11533
+ const gradeLevelsData = MetadataService.getGradeLevels();
11534
+ const questionTypesData = MetadataService.getQuestionTypes();
11535
+ const bloomLevelsData = MetadataService.getBloomLevels();
11536
+ setSubjects(subjectsData);
11537
+ setAllTopics(topicsData);
11538
+ setGradeLevels(gradeLevelsData);
11539
+ setQuestionTypes(questionTypesData);
11540
+ setBloomLevels(bloomLevelsData);
11541
+ }, []);
11542
+ React53.useEffect(() => {
11543
+ if (subjectCode) {
11544
+ const relatedTopics = allTopics.filter((t) => t.subjectCode === subjectCode);
11545
+ setFilteredTopics(relatedTopics);
11546
+ if (topicCode && !relatedTopics.find((t) => t.code === topicCode)) {
11547
+ setTopicCode("");
11548
+ }
11549
+ } else {
11550
+ setFilteredTopics(allTopics);
11551
+ setTopicCode("");
11552
+ }
11553
+ }, [subjectCode, allTopics, topicCode]);
11554
+ const handleApplyFilters = () => {
11555
+ onFilterChange({
11556
+ searchTerm: searchTerm || void 0,
11557
+ subjectCode: subjectCode || void 0,
11558
+ topicCode: topicCode || void 0,
11559
+ gradeLevelCode: gradeLevelCode || void 0,
11560
+ bloomLevelCode: bloomLevelCode || void 0,
11561
+ questionTypeCode: questionTypeCode || void 0,
11562
+ difficulty: difficulty || void 0
11563
+ });
11564
+ };
11565
+ const handleClearFilters = () => {
11566
+ setSearchTerm("");
11567
+ setSubjectCode("");
11568
+ setTopicCode("");
11569
+ setGradeLevelCode("");
11570
+ setBloomLevelCode("");
11571
+ setQuestionTypeCode("");
11572
+ setDifficulty("");
11573
+ onFilterChange({});
11574
+ };
11575
+ const createSelectHandler = (setter) => {
11576
+ return (selectedValue) => {
11577
+ setter(selectedValue === ALL_ITEMS_VALUE ? "" : selectedValue);
11578
+ };
11579
+ };
11580
+ return /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "p-4 mb-6 bg-card border rounded-lg shadow-sm" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-7 gap-4 items-end" }, /* @__PURE__ */ React53__namespace.default.createElement(
11581
+ Input,
11582
+ {
11583
+ placeholder: "Search questions...",
11584
+ value: searchTerm,
11585
+ onChange: (e) => setSearchTerm(e.target.value),
11586
+ className: "lg:col-span-2 xl:col-span-1"
11587
+ }
11588
+ ), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: subjectCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setSubjectCode) }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, { placeholder: "Subject" })), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { value: ALL_ITEMS_VALUE }, "All Subjects"), subjects.map((s) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: s.code, value: s.code }, s.name)))), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: topicCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setTopicCode), disabled: !subjectCode || filteredTopics.length === 0 }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, { placeholder: "Topic" })), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { value: ALL_ITEMS_VALUE }, "All Topics"), filteredTopics.map((t) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: t.code, value: t.code }, t.name)))), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: gradeLevelCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setGradeLevelCode) }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, { placeholder: "Grade Level" })), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { value: ALL_ITEMS_VALUE }, "All Grade Levels"), gradeLevels.map((gl) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: gl.code, value: gl.code }, gl.name)))), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: bloomLevelCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setBloomLevelCode) }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, { placeholder: "Bloom's Level" })), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { value: ALL_ITEMS_VALUE }, "All Levels"), bloomLevels.map((bl) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: bl.code, value: bl.code }, bl.name)))), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: questionTypeCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setQuestionTypeCode) }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, { placeholder: "Question Type" })), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { value: ALL_ITEMS_VALUE }, "All Types"), questionTypes.map((qt) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: qt.code, value: qt.code }, qt.name)))), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: difficulty || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setDifficulty) }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, { placeholder: "Difficulty" })), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { value: ALL_ITEMS_VALUE }, "All Difficulties"), /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { value: "easy" }, "Easy"), /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { value: "medium" }, "Medium"), /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { value: "hard" }, "Hard"))), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "flex gap-2 col-span-full sm:col-span-1 xl:col-span-2 xl:col-start-6" }, /* @__PURE__ */ React53__namespace.default.createElement(Button, { onClick: handleApplyFilters, className: "w-full sm:w-auto flex-grow" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Search, { className: "mr-2 h-4 w-4" }), " Apply"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { onClick: handleClearFilters, variant: "outline", className: "w-full sm:w-auto flex-grow" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.XCircle, { className: "mr-2 h-4 w-4" }), " Clear"))));
11589
+ }
11590
+ function QuestionFormDialog({
11591
+ isOpen,
11592
+ onOpenChange,
11593
+ onSave,
11594
+ questionToEdit
11595
+ }) {
11596
+ const [code, setCode] = React53.useState("");
11597
+ const [subjectCode, setSubjectCode] = React53.useState("");
11598
+ const [topicCode, setTopicCode] = React53.useState("");
11599
+ const [gradeLevelCode, setGradeLevelCode] = React53.useState("");
11600
+ const [bloomLevelCode, setBloomLevelCode] = React53.useState("");
11601
+ const [isQuestionEditorOpen, setIsQuestionEditorOpen] = React53.useState(false);
11602
+ const [questionConfig, setQuestionConfig] = React53.useState(null);
11603
+ const [subjects, setSubjects] = React53.useState([]);
11604
+ const [topics, setTopics] = React53.useState([]);
11605
+ const [gradeLevels, setGradeLevels] = React53.useState([]);
11606
+ const [bloomLevels, setBloomLevels] = React53.useState([]);
11607
+ const [filteredTopics, setFilteredTopics] = React53.useState([]);
11608
+ const [isPending, startTransition] = React53.useTransition();
11609
+ const { toast: toast2 } = useToast();
11610
+ React53.useEffect(() => {
11611
+ var _a, _b, _c;
11612
+ const subjectsData = MetadataService.getSubjects();
11613
+ const topicsData = MetadataService.getTopics();
11614
+ const gradeLevelsData = MetadataService.getGradeLevels();
11615
+ const bloomLevelsData = MetadataService.getBloomLevels();
11616
+ setSubjects(subjectsData);
11617
+ setTopics(topicsData);
11618
+ setGradeLevels(gradeLevelsData);
11619
+ setBloomLevels(bloomLevelsData);
11620
+ if (isOpen) {
11621
+ if (questionToEdit) {
11622
+ setCode(questionToEdit.code);
11623
+ setSubjectCode(questionToEdit.subjectCode);
11624
+ setTopicCode(questionToEdit.topicCode);
11625
+ setGradeLevelCode(questionToEdit.gradeLevelCode);
11626
+ setBloomLevelCode(questionToEdit.bloomLevelCode);
11627
+ setQuestionConfig(questionToEdit.questionConfig);
11628
+ } else {
11629
+ const defaultSubject = ((_a = subjectsData[0]) == null ? void 0 : _a.code) || "";
11630
+ const defaultGrade = ((_b = gradeLevelsData[0]) == null ? void 0 : _b.code) || "";
11631
+ const defaultBloom = ((_c = bloomLevelsData[0]) == null ? void 0 : _c.code) || "";
11632
+ setCode("");
11633
+ setSubjectCode(defaultSubject);
11634
+ setGradeLevelCode(defaultGrade);
11635
+ setBloomLevelCode(defaultBloom);
11636
+ setTopicCode("");
11637
+ setQuestionConfig(null);
11638
+ }
11639
+ }
11640
+ }, [questionToEdit, isOpen]);
11641
+ React53.useEffect(() => {
11642
+ var _a;
11643
+ if (subjectCode) {
11644
+ const relatedTopics = topics.filter((t) => t.subjectCode === subjectCode);
11645
+ setFilteredTopics(relatedTopics);
11646
+ if (topicCode && !relatedTopics.find((t) => t.code === topicCode)) {
11647
+ setTopicCode(((_a = relatedTopics[0]) == null ? void 0 : _a.code) || "");
11648
+ }
11649
+ } else {
11650
+ setFilteredTopics([]);
11651
+ setTopicCode("");
11652
+ }
11653
+ }, [subjectCode, topics, topicCode]);
11654
+ const handleOpenQuestionEditor = (type) => {
11655
+ if (questionToEdit && questionConfig) {
11656
+ setIsQuestionEditorOpen(true);
11657
+ } else if (type) {
11658
+ const newTemplate = QuizEditorService.createNewQuestionTemplate(type);
11659
+ setQuestionConfig(newTemplate);
11660
+ setIsQuestionEditorOpen(true);
11661
+ }
11662
+ };
11663
+ const handleQuestionConfigSave = (savedConfig) => {
11664
+ setQuestionConfig(savedConfig);
11665
+ setIsQuestionEditorOpen(false);
11666
+ };
11667
+ const handleSubmit = () => {
11668
+ if (!code.trim() || !subjectCode || !topicCode || !gradeLevelCode || !bloomLevelCode) {
11669
+ toast2({ title: "Validation Error", description: "Please fill all metadata fields (Code, Subject, Topic, etc.).", variant: "destructive" });
11670
+ return;
11671
+ }
11672
+ if (!questionConfig) {
11673
+ toast2({ title: "Validation Error", description: "Question content is missing. Please create or edit the question details.", variant: "destructive" });
11674
+ return;
11675
+ }
11676
+ startTransition(() => {
11677
+ try {
11678
+ const finalDataPayload = {
11679
+ code,
11680
+ text: questionConfig.prompt.replace(/<[^>]*>?/gm, "").substring(0, 200),
11681
+ subjectCode,
11682
+ topicCode,
11683
+ gradeLevelCode,
11684
+ bloomLevelCode,
11685
+ questionTypeCode: questionConfig.questionType,
11686
+ difficulty: questionConfig.difficulty,
11687
+ questionConfig: __spreadProps(__spreadValues({}, questionConfig), {
11688
+ subject: subjectCode,
11689
+ topic: topicCode,
11690
+ gradeBand: gradeLevelCode,
11691
+ bloomLevel: bloomLevelCode
11692
+ })
11693
+ };
11694
+ if (questionToEdit) {
11695
+ QuestionBankService.updateQuestion(questionToEdit.id, finalDataPayload);
11696
+ toast2({ title: "Success", description: "Question updated." });
11697
+ } else {
11698
+ QuestionBankService.addQuestion(finalDataPayload);
11699
+ toast2({ title: "Success", description: "Question added." });
11700
+ }
11701
+ onSave();
11702
+ onOpenChange(false);
11703
+ } catch (error) {
11704
+ toast2({ title: "Error", description: error.message || "Failed to save question.", variant: "destructive" });
11705
+ }
11706
+ });
11707
+ };
11708
+ const dialogTitle = questionToEdit ? "Edit Question Metadata" : "Create New Question";
11709
+ const dialogDescription = "First, define the metadata for the question. Then, edit the question's content and logic.";
11710
+ return /* @__PURE__ */ React53__namespace.default.createElement(React53__namespace.default.Fragment, null, /* @__PURE__ */ React53__namespace.default.createElement(Dialog, { open: isOpen, onOpenChange }, /* @__PURE__ */ React53__namespace.default.createElement(DialogContent, { className: "sm:max-w-xl md:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React53__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(DialogTitle, null, dialogTitle), /* @__PURE__ */ React53__namespace.default.createElement(DialogDescription, null, dialogDescription)), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "code" }, "Question Code"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "code", value: code, onChange: (e) => setCode(e.target.value.toUpperCase()), placeholder: "Unique code (e.g., MATH-ALG-001)", disabled: !!questionToEdit })), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "gradeLevelCode" }, "Grade Level"), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: gradeLevelCode, onValueChange: setGradeLevelCode }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, { id: "gradeLevelCode" }, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, { placeholder: "Select Grade Level" })), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, gradeLevels.map((gl) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: gl.code, value: gl.code }, gl.name)))))), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "subjectCode" }, "Subject"), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: subjectCode, onValueChange: setSubjectCode }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, { id: "subjectCode" }, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, { placeholder: "Select Subject" })), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, subjects.map((s) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: s.code, value: s.code }, s.name))))), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "topicCode" }, "Topic"), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: topicCode, onValueChange: setTopicCode, disabled: !subjectCode || filteredTopics.length === 0 }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, { id: "topicCode" }, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, { placeholder: "Select Topic" })), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, filteredTopics.map((t) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: t.code, value: t.code }, t.name)))))), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "bloomLevelCode" }, "Bloom's Level"), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: bloomLevelCode, onValueChange: setBloomLevelCode }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, { id: "bloomLevelCode" }, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, { placeholder: "Select Bloom's Level" })), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, bloomLevels.map((bl) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: bl.code, value: bl.code }, bl.name))))), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "pt-4 border-t" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { className: "font-semibold" }, "Question Content & Logic"), questionConfig ? /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "p-3 mt-2 border rounded-md bg-muted/30 flex justify-between items-center" }, /* @__PURE__ */ React53__namespace.default.createElement("div", null, /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "font-medium" }, "Type: ", /* @__PURE__ */ React53__namespace.default.createElement("span", { className: "font-normal" }, questionConfig.questionType)), /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-sm text-muted-foreground truncate max-w-md" }, "Prompt: ", questionConfig.prompt.replace(/<[^>]*>?/gm, "") || "Not set")), /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "outline", onClick: () => handleOpenQuestionEditor() }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Edit, { className: "mr-2 h-4 w-4" }), " Edit Content")) : /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "p-3 mt-2 border-dashed border-2 rounded-md text-center" }, /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-muted-foreground mb-2" }, "No content has been created yet."), /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "default", onClick: () => handleOpenQuestionEditor("multiple_choice") }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.BookCopy, { className: "mr-2 h-4 w-4" }), " Create Question Content")))), /* @__PURE__ */ React53__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => onOpenChange(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !questionConfig }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), " Save Question")))), questionConfig && /* @__PURE__ */ React53__namespace.default.createElement(
11711
+ EditQuestionModal,
11712
+ {
11713
+ isOpen: isQuestionEditorOpen,
11714
+ onClose: () => setIsQuestionEditorOpen(false),
11715
+ questionData: questionConfig,
11716
+ onSave: handleQuestionConfigSave
11717
+ }
11718
+ ));
11719
+ }
11720
+ var AlertDialog = AlertDialogPrimitive__namespace.Root;
11721
+ var AlertDialogPortal = AlertDialogPrimitive__namespace.Portal;
11722
+ var AlertDialogOverlay = React53__namespace.forwardRef((_a, ref) => {
11723
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11724
+ return /* @__PURE__ */ React53__namespace.createElement(
11725
+ AlertDialogPrimitive__namespace.Overlay,
11726
+ __spreadProps(__spreadValues({
11727
+ className: cn(
11728
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
11729
+ className
11730
+ )
11731
+ }, props), {
11732
+ ref
11733
+ })
11734
+ );
11735
+ });
11736
+ AlertDialogOverlay.displayName = AlertDialogPrimitive__namespace.Overlay.displayName;
11737
+ var AlertDialogContent = React53__namespace.forwardRef((_a, ref) => {
11738
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11739
+ return /* @__PURE__ */ React53__namespace.createElement(AlertDialogPortal, null, /* @__PURE__ */ React53__namespace.createElement(AlertDialogOverlay, null), /* @__PURE__ */ React53__namespace.createElement(
11740
+ AlertDialogPrimitive__namespace.Content,
11741
+ __spreadValues({
11742
+ ref,
11743
+ className: cn(
11744
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
11745
+ className
11746
+ )
11747
+ }, props)
11748
+ ));
11749
+ });
11750
+ AlertDialogContent.displayName = AlertDialogPrimitive__namespace.Content.displayName;
11751
+ var AlertDialogHeader = (_a) => {
11752
+ var _b = _a, {
11753
+ className
11754
+ } = _b, props = __objRest(_b, [
11755
+ "className"
11756
+ ]);
11757
+ return /* @__PURE__ */ React53__namespace.createElement(
11758
+ "div",
11759
+ __spreadValues({
11760
+ className: cn(
11761
+ "flex flex-col space-y-2 text-center sm:text-left",
11762
+ className
11763
+ )
11764
+ }, props)
11765
+ );
11766
+ };
11767
+ AlertDialogHeader.displayName = "AlertDialogHeader";
11768
+ var AlertDialogFooter = (_a) => {
11769
+ var _b = _a, {
11770
+ className
11771
+ } = _b, props = __objRest(_b, [
11772
+ "className"
11773
+ ]);
11774
+ return /* @__PURE__ */ React53__namespace.createElement(
11775
+ "div",
11776
+ __spreadValues({
11777
+ className: cn(
11778
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
11779
+ className
11780
+ )
11781
+ }, props)
11782
+ );
11783
+ };
11784
+ AlertDialogFooter.displayName = "AlertDialogFooter";
11785
+ var AlertDialogTitle = React53__namespace.forwardRef((_a, ref) => {
11786
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11787
+ return /* @__PURE__ */ React53__namespace.createElement(
11788
+ AlertDialogPrimitive__namespace.Title,
11789
+ __spreadValues({
11790
+ ref,
11791
+ className: cn("text-lg font-semibold", className)
11792
+ }, props)
11793
+ );
11794
+ });
11795
+ AlertDialogTitle.displayName = AlertDialogPrimitive__namespace.Title.displayName;
11796
+ var AlertDialogDescription = React53__namespace.forwardRef((_a, ref) => {
11797
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11798
+ return /* @__PURE__ */ React53__namespace.createElement(
11799
+ AlertDialogPrimitive__namespace.Description,
11800
+ __spreadValues({
11801
+ ref,
11802
+ className: cn("text-sm text-muted-foreground", className)
11803
+ }, props)
11804
+ );
11805
+ });
11806
+ AlertDialogDescription.displayName = AlertDialogPrimitive__namespace.Description.displayName;
11807
+ var AlertDialogAction = React53__namespace.forwardRef((_a, ref) => {
11808
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11809
+ return /* @__PURE__ */ React53__namespace.createElement(
11810
+ AlertDialogPrimitive__namespace.Action,
11811
+ __spreadValues({
11812
+ ref,
11813
+ className: cn(buttonVariants(), className)
11814
+ }, props)
11815
+ );
11816
+ });
11817
+ AlertDialogAction.displayName = AlertDialogPrimitive__namespace.Action.displayName;
11818
+ var AlertDialogCancel = React53__namespace.forwardRef((_a, ref) => {
11819
+ var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
11820
+ return /* @__PURE__ */ React53__namespace.createElement(
11821
+ AlertDialogPrimitive__namespace.Cancel,
11822
+ __spreadValues({
11823
+ ref,
11824
+ className: cn(
11825
+ buttonVariants({ variant: "outline" }),
11826
+ "mt-2 sm:mt-0",
11827
+ className
11828
+ )
11829
+ }, props)
11830
+ );
11831
+ });
11832
+ AlertDialogCancel.displayName = AlertDialogPrimitive__namespace.Cancel.displayName;
11833
+
11834
+ // src/react-ui/components/elements/skeleton.tsx
11835
+ function Skeleton(_a) {
11836
+ var _b = _a, {
11837
+ className
11838
+ } = _b, props = __objRest(_b, [
11839
+ "className"
11840
+ ]);
11841
+ return /* @__PURE__ */ React.createElement(
11842
+ "div",
11843
+ __spreadValues({
11844
+ className: cn("animate-pulse rounded-md bg-muted", className)
11845
+ }, props)
11846
+ );
11847
+ }
11848
+ function SubjectManager() {
11849
+ const [subjects, setSubjects] = React53.useState([]);
11850
+ const [isLoading, setIsLoading] = React53.useState(true);
11851
+ const [isDialogOpen, setIsDialogOpen] = React53.useState(false);
11852
+ const [isAlertOpen, setIsAlertOpen] = React53.useState(false);
11853
+ const [currentSubject, setCurrentSubject] = React53.useState(null);
11854
+ const [subjectName, setSubjectName] = React53.useState("");
11855
+ const [subjectCode, setSubjectCode] = React53.useState("");
11856
+ const [itemToDelete, setItemToDelete] = React53.useState(null);
11857
+ const [isPending, startTransition] = React53.useTransition();
11858
+ const { toast: toast2 } = useToast();
11859
+ React53.useEffect(() => {
11860
+ setIsLoading(true);
11861
+ try {
11862
+ const data = MetadataService.getSubjects();
11863
+ setSubjects(data);
11864
+ } catch (error) {
11865
+ toast2({ title: "Error", description: "Failed to fetch subjects from local storage.", variant: "destructive" });
11866
+ } finally {
11867
+ setIsLoading(false);
11868
+ }
11869
+ }, []);
11870
+ const refreshData = () => {
11871
+ setSubjects(MetadataService.getSubjects());
11872
+ };
11873
+ const handleAddItem = () => {
11874
+ setCurrentSubject(null);
11875
+ setSubjectName("");
11876
+ setSubjectCode("");
11877
+ setIsDialogOpen(true);
11878
+ };
11879
+ const handleEditItem = (subject) => {
11880
+ setCurrentSubject(subject);
11881
+ setSubjectName(subject.name);
11882
+ setSubjectCode(subject.code);
11883
+ setIsDialogOpen(true);
11884
+ };
11885
+ const handleDeleteItem = (subject) => {
11886
+ setItemToDelete(subject);
11887
+ setIsAlertOpen(true);
11888
+ };
11889
+ const confirmDelete = () => {
11890
+ if (!itemToDelete) return;
11891
+ startTransition(() => {
11892
+ try {
11893
+ MetadataService.deleteSubject(itemToDelete.code);
11894
+ toast2({ title: "Success", description: `Subject "${itemToDelete.name}" deleted.` });
11895
+ refreshData();
11896
+ } catch (error) {
11897
+ toast2({ title: "Error", description: error.message || "Failed to delete subject.", variant: "destructive" });
11898
+ } finally {
11899
+ setIsAlertOpen(false);
11900
+ setItemToDelete(null);
11901
+ }
11902
+ });
11903
+ };
11904
+ const handleSubmit = () => {
11905
+ if (!subjectName.trim() || !subjectCode.trim()) {
11906
+ toast2({ title: "Validation Error", description: "Please enter Subject Name and Subject Code.", variant: "destructive" });
11907
+ return;
11908
+ }
11909
+ startTransition(() => {
11910
+ try {
11911
+ if (currentSubject) {
11912
+ MetadataService.updateSubject(currentSubject.id, subjectName, subjectCode);
11913
+ toast2({ title: "Success", description: "Subject updated." });
11914
+ } else {
11915
+ MetadataService.addSubject(subjectName, subjectCode);
11916
+ toast2({ title: "Success", description: "Subject added." });
11917
+ }
11918
+ refreshData();
11919
+ setIsDialogOpen(false);
11920
+ } catch (error) {
11921
+ toast2({ title: "Error", description: error.message || "Failed to save subject.", variant: "destructive" });
11922
+ }
11923
+ });
11924
+ };
11925
+ return /* @__PURE__ */ React53__namespace.default.createElement(Card, null, /* @__PURE__ */ React53__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React53__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.BookCopy, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Subjects"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.PlusCircle, { className: "mr-2 h-4 w-4" }), " Add Subject"))), /* @__PURE__ */ React53__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "h-8 w-8 animate-spin text-primary" })) : subjects.length === 0 ? /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No subjects found. Add one to get started!") : /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React53__namespace.default.createElement(Table2, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Created At"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Updated At"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React53__namespace.default.createElement(TableBody, null, subjects.map((subject) => /* @__PURE__ */ React53__namespace.default.createElement(TableRow, { key: subject.id }, /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, subject.code), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-medium" }, subject.name), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, dateFns.format(new Date(subject.createdAt), "dd/MM/yyyy HH:mm")), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, dateFns.format(new Date(subject.updatedAt), "dd/MM/yyyy HH:mm")), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(subject), className: "mr-2" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Edit3, { className: "h-4 w-4" })), /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(subject), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React53__namespace.default.createElement(Dialog, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React53__namespace.default.createElement(DialogContent, { className: "sm:max-w-md" }, /* @__PURE__ */ React53__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(DialogTitle, null, currentSubject ? "Edit Subject" : "Add New Subject"), /* @__PURE__ */ React53__namespace.default.createElement(DialogDescription, null, currentSubject ? "Update the details of the subject." : "Enter details for the new subject.")), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React53__namespace.default.createElement(
11926
+ Input,
11927
+ {
11928
+ id: "subjectCode",
11929
+ value: subjectCode,
11930
+ onChange: (e) => setSubjectCode(e.target.value.toUpperCase()),
11931
+ placeholder: "e.g., MATH",
11932
+ disabled: !!currentSubject
11933
+ }
11934
+ )), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "subjectName" }, "Subject Name"), /* @__PURE__ */ React53__namespace.default.createElement(
11935
+ Input,
11936
+ {
11937
+ id: "subjectName",
11938
+ value: subjectName,
11939
+ onChange: (e) => setSubjectName(e.target.value),
11940
+ placeholder: "e.g., Mathematics"
11941
+ }
11942
+ ))), /* @__PURE__ */ React53__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !subjectName.trim() || !subjectCode.trim() }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Save")))), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialog, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogContent, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogTitle, null, "Are you sure?"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogDescription, null, 'This action cannot be undone. This will permanently delete the subject "', itemToDelete == null ? void 0 : itemToDelete.name, '" (Code: ', itemToDelete == null ? void 0 : itemToDelete.code, "). Ensure no topics, questions, or learning objectives reference this subject.")), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogCancel, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogAction, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Delete"))))));
11943
+ }
11944
+ function GradeLevelManager() {
11945
+ const [items, setItems] = React53.useState([]);
11946
+ const [isLoading, setIsLoading] = React53.useState(true);
11947
+ const [isDialogOpen, setIsDialogOpen] = React53.useState(false);
11948
+ const [isAlertOpen, setIsAlertOpen] = React53.useState(false);
11949
+ const [currentItem, setCurrentItem] = React53.useState(null);
11950
+ const [itemName, setItemName] = React53.useState("");
11951
+ const [itemCode, setItemCode] = React53.useState("");
11952
+ const [itemToDelete, setItemToDelete] = React53.useState(null);
11953
+ const [isPending, startTransition] = React53.useTransition();
11954
+ const { toast: toast2 } = useToast();
11955
+ React53.useEffect(() => {
11956
+ fetchItems();
11957
+ }, []);
11958
+ const fetchItems = () => {
11959
+ setIsLoading(true);
11960
+ try {
11961
+ setItems(MetadataService.getGradeLevels());
11962
+ } catch (error) {
11963
+ toast2({ title: "Error", description: "Failed to fetch grade levels.", variant: "destructive" });
11964
+ } finally {
11965
+ setIsLoading(false);
11966
+ }
11967
+ };
11968
+ const handleAddItem = () => {
11969
+ setCurrentItem(null);
11970
+ setItemName("");
11971
+ setItemCode("");
11972
+ setIsDialogOpen(true);
11973
+ };
11974
+ const handleEditItem = (item) => {
11975
+ setCurrentItem(item);
11976
+ setItemName(item.name);
11977
+ setItemCode(item.code);
11978
+ setIsDialogOpen(true);
11979
+ };
11980
+ const handleDeleteItem = (item) => {
11981
+ setItemToDelete(item);
11982
+ setIsAlertOpen(true);
11983
+ };
11984
+ const confirmDelete = () => {
11985
+ if (!itemToDelete) return;
11986
+ startTransition(() => {
11987
+ try {
11988
+ MetadataService.deleteGradeLevel(itemToDelete.code);
11989
+ toast2({ title: "Success", description: `Grade Level "${itemToDelete.name}" deleted.` });
11990
+ fetchItems();
11991
+ } catch (error) {
11992
+ toast2({ title: "Error", description: "Failed to delete grade level.", variant: "destructive" });
11993
+ } finally {
11994
+ setIsAlertOpen(false);
11995
+ setItemToDelete(null);
11996
+ }
11997
+ });
11998
+ };
11999
+ const handleSubmit = () => {
12000
+ if (!itemName.trim() || !itemCode.trim()) {
12001
+ toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
12002
+ return;
12003
+ }
12004
+ startTransition(() => {
12005
+ try {
12006
+ if (currentItem) {
12007
+ MetadataService.updateGradeLevel(currentItem.id, itemName, itemCode);
12008
+ } else {
12009
+ MetadataService.addGradeLevel(itemName, itemCode);
12010
+ }
12011
+ toast2({ title: "Success", description: `Grade Level saved.` });
12012
+ fetchItems();
12013
+ setIsDialogOpen(false);
12014
+ } catch (error) {
12015
+ toast2({ title: "Error", description: "Failed to save grade level.", variant: "destructive" });
12016
+ }
12017
+ });
12018
+ };
12019
+ return /* @__PURE__ */ React53__namespace.default.createElement(Card, null, /* @__PURE__ */ React53__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React53__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Award, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Grade Levels"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.PlusCircle, { className: "mr-2 h-4 w-4" }), " Add Grade Level"))), /* @__PURE__ */ React53__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No grade levels found.") : /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React53__namespace.default.createElement(Table2, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React53__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React53__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Edit3, { className: "h-4 w-4" })), /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React53__namespace.default.createElement(Dialog, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React53__namespace.default.createElement(DialogContent, { className: "sm:max-w-md" }, /* @__PURE__ */ React53__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(DialogTitle, null, currentItem ? "Edit Grade Level" : "Add New Grade Level")), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e) => setItemCode(e.target.value.toUpperCase()), placeholder: "e.g., G9", disabled: !!currentItem })), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "itemName", value: itemName, onChange: (e) => setItemName(e.target.value), placeholder: "e.g., Grade 9" }))), /* @__PURE__ */ React53__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemName.trim() || !itemCode.trim() }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Save")))), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialog, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogContent, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogTitle, null, "Are you sure?"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogDescription, null, 'This will permanently delete "', itemToDelete == null ? void 0 : itemToDelete.name, '".')), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogCancel, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogAction, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Delete"))))));
12020
+ }
12021
+ function TopicManager() {
12022
+ const [topics, setTopics] = React53.useState([]);
12023
+ const [subjects, setSubjects] = React53.useState([]);
12024
+ const [isLoading, setIsLoading] = React53.useState(true);
12025
+ const [isDialogOpen, setIsDialogOpen] = React53.useState(false);
12026
+ const [isAlertOpen, setIsAlertOpen] = React53.useState(false);
12027
+ const [currentItem, setCurrentItem] = React53.useState(null);
12028
+ const [itemName, setItemName] = React53.useState("");
12029
+ const [itemCode, setItemCode] = React53.useState("");
12030
+ const [selectedSubjectCode, setSelectedSubjectCode] = React53.useState("");
12031
+ const [itemToDelete, setItemToDelete] = React53.useState(null);
12032
+ const [isPending, startTransition] = React53.useTransition();
12033
+ const { toast: toast2 } = useToast();
12034
+ const fetchData = () => {
12035
+ setIsLoading(true);
12036
+ try {
12037
+ const topicsData = MetadataService.getTopics();
12038
+ const subjectsData = MetadataService.getSubjects();
12039
+ setTopics(topicsData);
12040
+ setSubjects(subjectsData);
12041
+ if (subjectsData.length > 0 && !selectedSubjectCode) {
12042
+ setSelectedSubjectCode(subjectsData[0].code);
12043
+ }
12044
+ } catch (error) {
12045
+ toast2({
12046
+ title: "Error",
12047
+ description: "Failed to fetch topics or subjects.",
12048
+ variant: "destructive"
12049
+ });
12050
+ } finally {
12051
+ setIsLoading(false);
12052
+ }
12053
+ };
12054
+ React53.useEffect(() => {
12055
+ fetchData();
12056
+ }, []);
12057
+ const handleAddItem = () => {
12058
+ setCurrentItem(null);
12059
+ setItemName("");
12060
+ setItemCode("");
12061
+ if (subjects.length > 0) {
12062
+ setSelectedSubjectCode(subjects[0].code);
12063
+ }
12064
+ setIsDialogOpen(true);
12065
+ };
12066
+ const handleEditItem = (topic) => {
12067
+ setCurrentItem(topic);
12068
+ setItemName(topic.name);
12069
+ setItemCode(topic.code);
12070
+ setSelectedSubjectCode(topic.subjectCode);
12071
+ setIsDialogOpen(true);
12072
+ };
12073
+ const handleDeleteItem = (topic) => {
12074
+ setItemToDelete(topic);
12075
+ setIsAlertOpen(true);
12076
+ };
12077
+ const confirmDelete = () => {
12078
+ if (!itemToDelete) return;
12079
+ startTransition(() => {
12080
+ try {
12081
+ MetadataService.deleteTopic(itemToDelete.code);
12082
+ toast2({
12083
+ title: "Success",
12084
+ description: `Topic "${itemToDelete.name}" deleted.`
12085
+ });
12086
+ fetchData();
12087
+ } catch (error) {
12088
+ toast2({
12089
+ title: "Error",
12090
+ description: "Failed to delete topic.",
12091
+ variant: "destructive"
12092
+ });
12093
+ } finally {
12094
+ setIsAlertOpen(false);
12095
+ setItemToDelete(null);
12096
+ }
12097
+ });
12098
+ };
12099
+ const handleSubmit = () => {
12100
+ if (!itemName.trim() || !itemCode.trim() || !selectedSubjectCode) {
12101
+ toast2({
12102
+ title: "Validation Error",
12103
+ description: "Name, Code, and Subject are required.",
12104
+ variant: "destructive"
12105
+ });
12106
+ return;
12107
+ }
12108
+ startTransition(() => {
12109
+ try {
12110
+ if (currentItem) {
12111
+ MetadataService.updateTopic(
12112
+ currentItem.id,
12113
+ itemName,
12114
+ itemCode,
12115
+ selectedSubjectCode
12116
+ );
12117
+ } else {
12118
+ MetadataService.addTopic(
12119
+ itemName,
12120
+ itemCode,
12121
+ selectedSubjectCode
12122
+ );
12123
+ }
12124
+ toast2({ title: "Success", description: "Topic saved." });
12125
+ fetchData();
12126
+ setIsDialogOpen(false);
12127
+ } catch (error) {
12128
+ toast2({
12129
+ title: "Error",
12130
+ description: "Failed to save topic.",
12131
+ variant: "destructive"
12132
+ });
12133
+ }
12134
+ });
12135
+ };
12136
+ const getSubjectName = (subjectCode) => {
12137
+ var _a;
12138
+ return ((_a = subjects.find((s) => s.code === subjectCode)) == null ? void 0 : _a.name) || "N/A";
12139
+ };
12140
+ return /* @__PURE__ */ React53__namespace.default.createElement(Card, null, /* @__PURE__ */ React53__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React53__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Tag, { className: "mr-2 h-5 w-5 text-primary" }), "Manage Topics"), /* @__PURE__ */ React53__namespace.default.createElement(
12141
+ Button,
12142
+ {
12143
+ onClick: handleAddItem,
12144
+ size: "sm",
12145
+ disabled: subjects.length === 0
12146
+ },
12147
+ /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.PlusCircle, { className: "mr-2 h-4 w-4" }),
12148
+ " Add Topic"
12149
+ )), subjects.length === 0 && !isLoading && /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-sm text-destructive" }, "Please add subjects before adding topics.")), /* @__PURE__ */ React53__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "h-8 w-8 animate-spin text-primary" })) : topics.length === 0 ? /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No topics found. Add one to get started!") : /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React53__namespace.default.createElement(Table2, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React53__namespace.default.createElement(TableBody, null, topics.map((topic) => /* @__PURE__ */ React53__namespace.default.createElement(TableRow, { key: topic.id }, /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, topic.code), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-medium" }, topic.name), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, getSubjectName(topic.subjectCode), " ", "(", topic.subjectCode, ")"), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React53__namespace.default.createElement(
12150
+ Button,
12151
+ {
12152
+ variant: "ghost",
12153
+ size: "icon",
12154
+ onClick: () => handleEditItem(topic),
12155
+ className: "mr-2"
12156
+ },
12157
+ /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Edit3, { className: "h-4 w-4" })
12158
+ ), /* @__PURE__ */ React53__namespace.default.createElement(
12159
+ Button,
12160
+ {
12161
+ variant: "ghost",
12162
+ size: "icon",
12163
+ onClick: () => handleDeleteItem(topic),
12164
+ className: "text-destructive hover:text-destructive"
12165
+ },
12166
+ /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Trash2, { className: "h-4 w-4" })
12167
+ ))))))), /* @__PURE__ */ React53__namespace.default.createElement(Dialog, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React53__namespace.default.createElement(DialogContent, { className: "sm:max-w-md" }, /* @__PURE__ */ React53__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(DialogTitle, null, currentItem ? "Edit Topic" : "Add New Topic")), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemCode" }, "Topic Code"), /* @__PURE__ */ React53__namespace.default.createElement(
12168
+ Input,
12169
+ {
12170
+ id: "itemCode",
12171
+ value: itemCode,
12172
+ onChange: (e) => setItemCode(
12173
+ e.target.value.toUpperCase()
12174
+ ),
12175
+ placeholder: "e.g., ALG-BASICS",
12176
+ disabled: !!currentItem
12177
+ }
12178
+ )), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemName" }, "Topic Name"), /* @__PURE__ */ React53__namespace.default.createElement(
12179
+ Input,
12180
+ {
12181
+ id: "itemName",
12182
+ value: itemName,
12183
+ onChange: (e) => setItemName(e.target.value),
12184
+ placeholder: "e.g., Algebra Basics"
12185
+ }
12186
+ )), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "subjectCode" }, "Subject"), /* @__PURE__ */ React53__namespace.default.createElement(
12187
+ Select,
12188
+ {
12189
+ value: selectedSubjectCode,
12190
+ onValueChange: setSelectedSubjectCode,
12191
+ disabled: subjects.length === 0
12192
+ },
12193
+ /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, { id: "subjectCode" }, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, { placeholder: "Select a subject" })),
12194
+ /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, subjects.map((subject) => /* @__PURE__ */ React53__namespace.default.createElement(
12195
+ SelectItem,
12196
+ {
12197
+ key: subject.code,
12198
+ value: subject.code
12199
+ },
12200
+ subject.name,
12201
+ " (",
12202
+ subject.code,
12203
+ ")"
12204
+ )))
12205
+ ))), /* @__PURE__ */ React53__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(
12206
+ Button,
12207
+ {
12208
+ type: "button",
12209
+ variant: "outline",
12210
+ onClick: () => setIsDialogOpen(false),
12211
+ disabled: isPending
12212
+ },
12213
+ "Cancel"
12214
+ ), /* @__PURE__ */ React53__namespace.default.createElement(
12215
+ Button,
12216
+ {
12217
+ type: "submit",
12218
+ onClick: handleSubmit,
12219
+ disabled: isPending || !itemName.trim() || !itemCode.trim() || !selectedSubjectCode
12220
+ },
12221
+ isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
12222
+ " ",
12223
+ "Save"
12224
+ )))), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialog, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogContent, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogTitle, null, "Are you sure?"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogDescription, null, 'This will permanently delete topic "', itemToDelete == null ? void 0 : itemToDelete.name, '".')), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogCancel, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(
12225
+ AlertDialogAction,
12226
+ {
12227
+ onClick: confirmDelete,
12228
+ disabled: isPending,
12229
+ className: "bg-destructive hover:bg-destructive/90"
12230
+ },
12231
+ isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
12232
+ " ",
12233
+ "Delete"
12234
+ ))))));
12235
+ }
12236
+ function CategoryManager() {
12237
+ const [items, setItems] = React53.useState([]);
12238
+ const [isLoading, setIsLoading] = React53.useState(true);
12239
+ const [isDialogOpen, setIsDialogOpen] = React53.useState(false);
12240
+ const [isAlertOpen, setIsAlertOpen] = React53.useState(false);
12241
+ const [currentItem, setCurrentItem] = React53.useState(null);
12242
+ const [itemName, setItemName] = React53.useState("");
12243
+ const [itemCode, setItemCode] = React53.useState("");
12244
+ const [itemDescription, setItemDescription] = React53.useState("");
12245
+ const [itemToDelete, setItemToDelete] = React53.useState(null);
12246
+ const [isPending, startTransition] = React53.useTransition();
12247
+ const { toast: toast2 } = useToast();
12248
+ React53.useEffect(() => {
12249
+ fetchItems();
12250
+ }, []);
12251
+ const fetchItems = () => {
12252
+ setIsLoading(true);
12253
+ try {
12254
+ setItems(MetadataService.getCategories());
12255
+ } catch (error) {
12256
+ toast2({ title: "Error", description: "Failed to fetch categories.", variant: "destructive" });
12257
+ } finally {
12258
+ setIsLoading(false);
12259
+ }
12260
+ };
12261
+ const handleAddItem = () => {
12262
+ setCurrentItem(null);
12263
+ setItemName("");
12264
+ setItemCode("");
12265
+ setItemDescription("");
12266
+ setIsDialogOpen(true);
12267
+ };
12268
+ const handleEditItem = (item) => {
12269
+ setCurrentItem(item);
12270
+ setItemName(item.name);
12271
+ setItemCode(item.code);
12272
+ setItemDescription(item.description || "");
12273
+ setIsDialogOpen(true);
12274
+ };
12275
+ const handleDeleteItem = (item) => {
12276
+ setItemToDelete(item);
12277
+ setIsAlertOpen(true);
12278
+ };
12279
+ const confirmDelete = () => {
12280
+ if (!itemToDelete) return;
12281
+ startTransition(() => {
12282
+ try {
12283
+ MetadataService.deleteCategory(itemToDelete.code);
12284
+ toast2({ title: "Success", description: `Category "${itemToDelete.name}" deleted.` });
12285
+ fetchItems();
12286
+ } catch (error) {
12287
+ toast2({ title: "Error", description: "Failed to delete category.", variant: "destructive" });
12288
+ } finally {
12289
+ setIsAlertOpen(false);
12290
+ setItemToDelete(null);
12291
+ }
12292
+ });
12293
+ };
12294
+ const handleSubmit = () => {
12295
+ if (!itemName.trim() || !itemCode.trim()) {
12296
+ toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
12297
+ return;
12298
+ }
12299
+ startTransition(() => {
12300
+ try {
12301
+ if (currentItem) {
12302
+ MetadataService.updateCategory(currentItem.id, itemName, itemCode, itemDescription);
12303
+ } else {
12304
+ MetadataService.addCategory(itemName, itemCode, itemDescription);
12305
+ }
12306
+ toast2({ title: "Success", description: "Category saved." });
12307
+ fetchItems();
12308
+ setIsDialogOpen(false);
12309
+ } catch (error) {
12310
+ toast2({ title: "Error", description: "Failed to save category.", variant: "destructive" });
12311
+ }
12312
+ });
12313
+ };
12314
+ return /* @__PURE__ */ React53__namespace.default.createElement(Card, null, /* @__PURE__ */ React53__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React53__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Layers, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Categories"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.PlusCircle, { className: "mr-2 h-4 w-4" }), " Add Category"))), /* @__PURE__ */ React53__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No categories found.") : /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React53__namespace.default.createElement(Table2, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React53__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React53__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, item.description), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Edit3, { className: "h-4 w-4" })), /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React53__namespace.default.createElement(Dialog, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React53__namespace.default.createElement(DialogContent, { className: "sm:max-w-md" }, /* @__PURE__ */ React53__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(DialogTitle, null, currentItem ? "Edit Category" : "Add New Category")), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e) => setItemCode(e.target.value.toUpperCase()), placeholder: "e.g., CORE_CONCEPT", disabled: !!currentItem })), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "itemName", value: itemName, onChange: (e) => setItemName(e.target.value), placeholder: "e.g., Core Concept" })), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React53__namespace.default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e) => setItemDescription(e.target.value), placeholder: "e.g., Fundamental ideas within a subject." }))), /* @__PURE__ */ React53__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemName.trim() || !itemCode.trim() }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Save")))), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialog, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogContent, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogTitle, null, "Are you sure?"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogDescription, null, 'This will permanently delete "', itemToDelete == null ? void 0 : itemToDelete.name, '".')), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogCancel, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogAction, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Delete"))))));
12315
+ }
12316
+ function BloomLevelManager() {
12317
+ const [items, setItems] = React53.useState([]);
12318
+ const [isLoading, setIsLoading] = React53.useState(true);
12319
+ const [isDialogOpen, setIsDialogOpen] = React53.useState(false);
12320
+ const [isAlertOpen, setIsAlertOpen] = React53.useState(false);
12321
+ const [currentItem, setCurrentItem] = React53.useState(null);
12322
+ const [itemCode, setItemCode] = React53.useState("");
12323
+ const [itemName, setItemName] = React53.useState("");
12324
+ const [itemDescription, setItemDescription] = React53.useState("");
12325
+ const [itemToDelete, setItemToDelete] = React53.useState(null);
12326
+ const [isPending, startTransition] = React53.useTransition();
12327
+ const { toast: toast2 } = useToast();
12328
+ React53.useEffect(() => {
12329
+ fetchItems();
12330
+ }, []);
12331
+ const fetchItems = () => {
12332
+ setIsLoading(true);
12333
+ try {
12334
+ setItems(MetadataService.getBloomLevels());
12335
+ } catch (error) {
12336
+ toast2({ title: "Error", description: "Failed to fetch Bloom's Levels.", variant: "destructive" });
12337
+ } finally {
12338
+ setIsLoading(false);
12339
+ }
12340
+ };
12341
+ const handleAddItem = () => {
12342
+ setCurrentItem(null);
12343
+ setItemCode("");
12344
+ setItemName("");
12345
+ setItemDescription("");
12346
+ setIsDialogOpen(true);
12347
+ };
12348
+ const handleEditItem = (item) => {
12349
+ setCurrentItem(item);
12350
+ setItemCode(item.code);
12351
+ setItemName(item.name);
12352
+ setItemDescription(item.description || "");
12353
+ setIsDialogOpen(true);
12354
+ };
12355
+ const handleDeleteItem = (item) => {
12356
+ setItemToDelete(item);
12357
+ setIsAlertOpen(true);
12358
+ };
12359
+ const confirmDelete = () => {
12360
+ if (!itemToDelete) return;
12361
+ startTransition(() => {
12362
+ try {
12363
+ MetadataService.deleteBloomLevel(itemToDelete.code);
12364
+ toast2({ title: "Success", description: `Bloom's Level "${itemToDelete.name}" deleted.` });
12365
+ fetchItems();
12366
+ } catch (error) {
12367
+ toast2({ title: "Error", description: "Failed to delete Bloom's Level.", variant: "destructive" });
12368
+ } finally {
12369
+ setIsAlertOpen(false);
12370
+ setItemToDelete(null);
12371
+ }
12372
+ });
12373
+ };
12374
+ const handleSubmit = () => {
12375
+ if (!itemName.trim() || !itemCode.trim()) {
12376
+ toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
12377
+ return;
12378
+ }
12379
+ startTransition(() => {
12380
+ try {
12381
+ if (currentItem) {
12382
+ MetadataService.updateBloomLevel(currentItem.id, itemName, itemCode, itemDescription);
12383
+ } else {
12384
+ MetadataService.addBloomLevel(itemName, itemCode, itemDescription);
12385
+ }
12386
+ toast2({ title: "Success", description: "Bloom's Level saved." });
12387
+ fetchItems();
12388
+ setIsDialogOpen(false);
12389
+ } catch (error) {
12390
+ toast2({ title: "Error", description: "Failed to save Bloom's Level.", variant: "destructive" });
12391
+ }
12392
+ });
12393
+ };
12394
+ return /* @__PURE__ */ React53__namespace.default.createElement(Card, null, /* @__PURE__ */ React53__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React53__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Brain, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Bloom's Levels"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.PlusCircle, { className: "mr-2 h-4 w-4" }), " Add Bloom's Level"))), /* @__PURE__ */ React53__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Bloom's Levels found.") : /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React53__namespace.default.createElement(Table2, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React53__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React53__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, item.description), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Edit3, { className: "h-4 w-4" })), /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React53__namespace.default.createElement(Dialog, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React53__namespace.default.createElement(DialogContent, { className: "sm:max-w-md" }, /* @__PURE__ */ React53__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(DialogTitle, null, currentItem ? "Edit Bloom's Level" : "Add New Bloom's Level")), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e) => setItemCode(e.target.value.toUpperCase()), placeholder: "e.g., REMEMBER", disabled: !!currentItem })), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "itemName", value: itemName, onChange: (e) => setItemName(e.target.value), placeholder: "e.g., Remembering" })), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React53__namespace.default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e) => setItemDescription(e.target.value), placeholder: "e.g., Recall facts and basic concepts." }))), /* @__PURE__ */ React53__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemCode.trim() || !itemName.trim() }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Save")))), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialog, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogContent, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogTitle, null, "Are you sure?"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogDescription, null, 'This will permanently delete "', itemToDelete == null ? void 0 : itemToDelete.name, '".')), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogCancel, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogAction, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Delete"))))));
12395
+ }
12396
+ function QuestionTypeManager() {
12397
+ const [items, setItems] = React53.useState([]);
12398
+ const [isLoading, setIsLoading] = React53.useState(true);
12399
+ const [isDialogOpen, setIsDialogOpen] = React53.useState(false);
12400
+ const [isAlertOpen, setIsAlertOpen] = React53.useState(false);
12401
+ const [currentItem, setCurrentItem] = React53.useState(null);
12402
+ const [itemCode, setItemCode] = React53.useState("");
12403
+ const [itemName, setItemName] = React53.useState("");
12404
+ const [itemDescription, setItemDescription] = React53.useState("");
12405
+ const [itemToDelete, setItemToDelete] = React53.useState(null);
12406
+ const [isPending, startTransition] = React53.useTransition();
12407
+ const { toast: toast2 } = useToast();
12408
+ React53.useEffect(() => {
12409
+ fetchItems();
12410
+ }, []);
12411
+ const fetchItems = () => {
12412
+ setIsLoading(true);
12413
+ try {
12414
+ setItems(MetadataService.getQuestionTypes());
12415
+ } catch (error) {
12416
+ toast2({ title: "Error", description: "Failed to fetch Question Types.", variant: "destructive" });
12417
+ } finally {
12418
+ setIsLoading(false);
12419
+ }
12420
+ };
12421
+ const handleAddItem = () => {
12422
+ setCurrentItem(null);
12423
+ setItemCode("");
12424
+ setItemName("");
12425
+ setItemDescription("");
12426
+ setIsDialogOpen(true);
12427
+ };
12428
+ const handleEditItem = (item) => {
12429
+ setCurrentItem(item);
12430
+ setItemCode(item.code);
12431
+ setItemName(item.name);
12432
+ setItemDescription(item.description || "");
12433
+ setIsDialogOpen(true);
12434
+ };
12435
+ const handleDeleteItem = (item) => {
12436
+ setItemToDelete(item);
12437
+ setIsAlertOpen(true);
12438
+ };
12439
+ const confirmDelete = () => {
12440
+ if (!itemToDelete) return;
12441
+ startTransition(() => {
12442
+ try {
12443
+ MetadataService.deleteQuestionType(itemToDelete.code);
12444
+ toast2({ title: "Success", description: `Question Type "${itemToDelete.name}" deleted.` });
12445
+ fetchItems();
12446
+ } catch (error) {
12447
+ toast2({ title: "Error", description: "Failed to delete Question Type.", variant: "destructive" });
12448
+ } finally {
12449
+ setIsAlertOpen(false);
12450
+ setItemToDelete(null);
12451
+ }
12452
+ });
12453
+ };
12454
+ const handleSubmit = () => {
12455
+ if (!itemName.trim() || !itemCode.trim()) {
12456
+ toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
12457
+ return;
12458
+ }
12459
+ startTransition(() => {
12460
+ try {
12461
+ if (currentItem) {
12462
+ MetadataService.updateQuestionType(currentItem.id, itemName, itemCode, itemDescription);
12463
+ } else {
12464
+ MetadataService.addQuestionType(itemName, itemCode, itemDescription);
12465
+ }
12466
+ toast2({ title: "Success", description: "Question Type saved." });
12467
+ fetchItems();
12468
+ setIsDialogOpen(false);
12469
+ } catch (error) {
12470
+ toast2({ title: "Error", description: "Failed to save Question Type.", variant: "destructive" });
12471
+ }
12472
+ });
12473
+ };
12474
+ return /* @__PURE__ */ React53__namespace.default.createElement(Card, null, /* @__PURE__ */ React53__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React53__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.HelpCircle, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Question Types"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.PlusCircle, { className: "mr-2 h-4 w-4" }), " Add Question Type"))), /* @__PURE__ */ React53__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Question Types found.") : /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React53__namespace.default.createElement(Table2, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React53__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React53__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, item.description), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Edit3, { className: "h-4 w-4" })), /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React53__namespace.default.createElement(Dialog, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React53__namespace.default.createElement(DialogContent, { className: "sm:max-w-md" }, /* @__PURE__ */ React53__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(DialogTitle, null, currentItem ? "Edit Question Type" : "Add New Question Type")), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e) => setItemCode(e.target.value.toUpperCase()), placeholder: "e.g., MCQ", disabled: !!currentItem })), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "itemName", value: itemName, onChange: (e) => setItemName(e.target.value), placeholder: "e.g., Multiple Choice" })), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React53__namespace.default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e) => setItemDescription(e.target.value), placeholder: "e.g., Select one answer from a list of options." }))), /* @__PURE__ */ React53__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemCode.trim() || !itemName.trim() }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Save")))), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialog, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogContent, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogTitle, null, "Are you sure?"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogDescription, null, 'This will permanently delete "', itemToDelete == null ? void 0 : itemToDelete.name, '".')), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogCancel, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogAction, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Delete"))))));
12475
+ }
12476
+ function LearningObjectiveManager() {
12477
+ const [items, setItems] = React53.useState([]);
12478
+ const [subjects, setSubjects] = React53.useState([]);
12479
+ const [isLoading, setIsLoading] = React53.useState(true);
12480
+ const [isDialogOpen, setIsDialogOpen] = React53.useState(false);
12481
+ const [isAlertOpen, setIsAlertOpen] = React53.useState(false);
12482
+ const [currentItem, setCurrentItem] = React53.useState(null);
12483
+ const [itemName, setItemName] = React53.useState("");
12484
+ const [itemCode, setItemCode] = React53.useState("");
12485
+ const [itemDescription, setItemDescription] = React53.useState("");
12486
+ const [selectedSubjectCode, setSelectedSubjectCode] = React53.useState(void 0);
12487
+ const [itemToDelete, setItemToDelete] = React53.useState(null);
12488
+ const [isPending, startTransition] = React53.useTransition();
12489
+ const { toast: toast2 } = useToast();
12490
+ const fetchData = () => {
12491
+ setIsLoading(true);
12492
+ try {
12493
+ const loData = MetadataService.getLearningObjectives();
12494
+ const subjectsData = MetadataService.getSubjects();
12495
+ setItems(loData);
12496
+ setSubjects(subjectsData);
12497
+ } catch (error) {
12498
+ toast2({
12499
+ title: "Error",
12500
+ description: "Failed to fetch Learning Objectives or Subjects.",
12501
+ variant: "destructive"
12502
+ });
12503
+ } finally {
12504
+ setIsLoading(false);
12505
+ }
12506
+ };
12507
+ React53.useEffect(() => {
12508
+ fetchData();
12509
+ }, []);
12510
+ const handleAddItem = () => {
12511
+ setCurrentItem(null);
12512
+ setItemName("");
12513
+ setItemCode("");
12514
+ setItemDescription("");
12515
+ setSelectedSubjectCode(
12516
+ subjects.length > 0 ? subjects[0].code : void 0
12517
+ );
12518
+ setIsDialogOpen(true);
12519
+ };
12520
+ const handleEditItem = (item) => {
12521
+ setCurrentItem(item);
12522
+ setItemName(item.name);
12523
+ setItemCode(item.code);
12524
+ setItemDescription(item.description || "");
12525
+ setSelectedSubjectCode(item.subjectCode);
12526
+ setIsDialogOpen(true);
12527
+ };
12528
+ const handleDeleteItem = (item) => {
12529
+ setItemToDelete(item);
12530
+ setIsAlertOpen(true);
12531
+ };
12532
+ const confirmDelete = () => {
12533
+ if (!itemToDelete) return;
12534
+ startTransition(() => {
12535
+ try {
12536
+ MetadataService.deleteLearningObjective(itemToDelete.code);
12537
+ toast2({
12538
+ title: "Success",
12539
+ description: `Learning Objective "${itemToDelete.name}" deleted.`
12540
+ });
12541
+ fetchData();
12542
+ } catch (error) {
12543
+ toast2({
12544
+ title: "Error",
12545
+ description: "Failed to delete Learning Objective.",
12546
+ variant: "destructive"
12547
+ });
12548
+ } finally {
12549
+ setIsAlertOpen(false);
12550
+ setItemToDelete(null);
12551
+ }
12552
+ });
12553
+ };
12554
+ const handleSubmit = () => {
12555
+ if (!itemName.trim() || !itemCode.trim()) {
12556
+ toast2({
12557
+ title: "Validation Error",
12558
+ description: "Code and Name are required.",
12559
+ variant: "destructive"
12560
+ });
12561
+ return;
12562
+ }
12563
+ startTransition(() => {
12564
+ try {
12565
+ if (currentItem) {
12566
+ MetadataService.updateLearningObjective(
12567
+ currentItem.id,
12568
+ itemName,
12569
+ itemCode,
12570
+ selectedSubjectCode,
12571
+ itemDescription
12572
+ );
12573
+ } else {
12574
+ MetadataService.addLearningObjective(
12575
+ itemName,
12576
+ itemCode,
12577
+ selectedSubjectCode,
12578
+ itemDescription
12579
+ );
12580
+ }
12581
+ toast2({
12582
+ title: "Success",
12583
+ description: "Learning Objective saved."
12584
+ });
12585
+ fetchData();
12586
+ setIsDialogOpen(false);
12587
+ } catch (error) {
12588
+ toast2({
12589
+ title: "Error",
12590
+ description: "Failed to save Learning Objective.",
12591
+ variant: "destructive"
12592
+ });
12593
+ }
12594
+ });
12595
+ };
12596
+ const getSubjectName = (subjectCode) => {
12597
+ var _a;
12598
+ if (!subjectCode) return "N/A";
12599
+ return ((_a = subjects.find((s) => s.code === subjectCode)) == null ? void 0 : _a.name) || "N/A";
12600
+ };
12601
+ return /* @__PURE__ */ React53__namespace.default.createElement(Card, null, /* @__PURE__ */ React53__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React53__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " ", "Manage Learning Objectives"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.PlusCircle, { className: "mr-2 h-4 w-4" }), " Add Learning Objective"))), /* @__PURE__ */ React53__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React53__namespace.default.createElement(Table2, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React53__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React53__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, getSubjectName(item.subjectCode)), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, item.description), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React53__namespace.default.createElement(
12602
+ Button,
12603
+ {
12604
+ variant: "ghost",
12605
+ size: "icon",
12606
+ onClick: () => handleEditItem(item),
12607
+ className: "mr-2"
12608
+ },
12609
+ /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Edit3, { className: "h-4 w-4" })
12610
+ ), /* @__PURE__ */ React53__namespace.default.createElement(
12611
+ Button,
12612
+ {
12613
+ variant: "ghost",
12614
+ size: "icon",
12615
+ onClick: () => handleDeleteItem(item),
12616
+ className: "text-destructive hover:text-destructive"
12617
+ },
12618
+ /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Trash2, { className: "h-4 w-4" })
12619
+ ))))))), /* @__PURE__ */ React53__namespace.default.createElement(Dialog, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React53__namespace.default.createElement(DialogContent, { className: "sm:max-w-md" }, /* @__PURE__ */ React53__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(DialogTitle, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(
12620
+ Input,
12621
+ {
12622
+ id: "itemCode",
12623
+ value: itemCode,
12624
+ onChange: (e) => setItemCode(
12625
+ e.target.value.toUpperCase()
12626
+ ),
12627
+ disabled: !!currentItem
12628
+ }
12629
+ )), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(
12630
+ Input,
12631
+ {
12632
+ id: "itemName",
12633
+ value: itemName,
12634
+ onChange: (e) => setItemName(e.target.value)
12635
+ }
12636
+ )), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemSubject" }, "Subject (Optional)"), /* @__PURE__ */ React53__namespace.default.createElement(
12637
+ Select,
12638
+ {
12639
+ value: selectedSubjectCode || "",
12640
+ onValueChange: (value) => setSelectedSubjectCode(
12641
+ value === "_NONE_" ? void 0 : value
12642
+ )
12643
+ },
12644
+ /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, { id: "itemSubject" }, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, { placeholder: "Select a subject" })),
12645
+ /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { value: "_NONE_" }, "No Specific Subject"), subjects.map((subject) => /* @__PURE__ */ React53__namespace.default.createElement(
12646
+ SelectItem,
12647
+ {
12648
+ key: subject.id,
12649
+ value: subject.code
12650
+ },
12651
+ subject.name
12652
+ )))
12653
+ )), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React53__namespace.default.createElement(
12654
+ Textarea,
12655
+ {
12656
+ id: "itemDescription",
12657
+ value: itemDescription,
12658
+ onChange: (e) => setItemDescription(e.target.value)
12659
+ }
12660
+ ))), /* @__PURE__ */ React53__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(
12661
+ Button,
12662
+ {
12663
+ type: "button",
12664
+ variant: "outline",
12665
+ onClick: () => setIsDialogOpen(false),
12666
+ disabled: isPending
12667
+ },
12668
+ "Cancel"
12669
+ ), /* @__PURE__ */ React53__namespace.default.createElement(
12670
+ Button,
12671
+ {
12672
+ type: "submit",
12673
+ onClick: handleSubmit,
12674
+ disabled: isPending || !itemName.trim() || !itemCode.trim()
12675
+ },
12676
+ isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
12677
+ " ",
12678
+ "Save"
12679
+ )))), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialog, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogContent, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogTitle, null, "Are you sure?"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogDescription, null, 'This will permanently delete "', itemToDelete == null ? void 0 : itemToDelete.name, '".')), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogCancel, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(
12680
+ AlertDialogAction,
12681
+ {
12682
+ onClick: confirmDelete,
12683
+ disabled: isPending,
12684
+ className: "bg-destructive hover:bg-destructive/90"
12685
+ },
12686
+ isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
12687
+ " ",
12688
+ "Delete"
12689
+ ))))));
12690
+ }
12691
+ function ContextManager() {
12692
+ const [items, setItems] = React53.useState([]);
12693
+ const [isLoading, setIsLoading] = React53.useState(true);
12694
+ const [isDialogOpen, setIsDialogOpen] = React53.useState(false);
12695
+ const [isAlertOpen, setIsAlertOpen] = React53.useState(false);
12696
+ const [currentItem, setCurrentItem] = React53.useState(null);
12697
+ const [itemName, setItemName] = React53.useState("");
12698
+ const [itemCode, setItemCode] = React53.useState("");
12699
+ const [itemDescription, setItemDescription] = React53.useState("");
12700
+ const [itemToDelete, setItemToDelete] = React53.useState(null);
12701
+ const [isPending, startTransition] = React53.useTransition();
12702
+ const { toast: toast2 } = useToast();
12703
+ React53.useEffect(() => {
12704
+ fetchItems();
12705
+ }, []);
12706
+ const fetchItems = () => {
12707
+ setIsLoading(true);
12708
+ try {
12709
+ setItems(MetadataService.getContexts());
12710
+ } catch (error) {
12711
+ toast2({ title: "Error", description: "Failed to fetch Contexts.", variant: "destructive" });
12712
+ } finally {
12713
+ setIsLoading(false);
12714
+ }
12715
+ };
12716
+ const handleAddItem = () => {
12717
+ setCurrentItem(null);
12718
+ setItemName("");
12719
+ setItemCode("");
12720
+ setItemDescription("");
12721
+ setIsDialogOpen(true);
12722
+ };
12723
+ const handleEditItem = (item) => {
12724
+ setCurrentItem(item);
12725
+ setItemName(item.name);
12726
+ setItemCode(item.code);
12727
+ setItemDescription(item.description || "");
12728
+ setIsDialogOpen(true);
12729
+ };
12730
+ const handleDeleteItem = (item) => {
12731
+ setItemToDelete(item);
12732
+ setIsAlertOpen(true);
12733
+ };
12734
+ const confirmDelete = () => {
12735
+ if (!itemToDelete) return;
12736
+ startTransition(() => {
12737
+ try {
12738
+ MetadataService.deleteContext(itemToDelete.code);
12739
+ toast2({ title: "Success", description: `Context "${itemToDelete.name}" deleted.` });
12740
+ fetchItems();
12741
+ } catch (error) {
12742
+ toast2({ title: "Error", description: "Failed to delete Context.", variant: "destructive" });
12743
+ } finally {
12744
+ setIsAlertOpen(false);
12745
+ setItemToDelete(null);
12746
+ }
12747
+ });
12748
+ };
12749
+ const handleSubmit = () => {
12750
+ if (!itemName.trim() || !itemCode.trim()) {
12751
+ toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
12752
+ return;
12753
+ }
12754
+ startTransition(() => {
12755
+ try {
12756
+ if (currentItem) {
12757
+ MetadataService.updateContext(currentItem.id, itemName, itemCode, itemDescription);
12758
+ } else {
12759
+ MetadataService.addContext(itemName, itemCode, itemDescription);
12760
+ }
12761
+ toast2({ title: "Success", description: "Context saved." });
12762
+ fetchItems();
12763
+ setIsDialogOpen(false);
12764
+ } catch (error) {
12765
+ toast2({ title: "Error", description: "Failed to save Context.", variant: "destructive" });
12766
+ }
12767
+ });
12768
+ };
12769
+ return /* @__PURE__ */ React53__namespace.default.createElement(Card, null, /* @__PURE__ */ React53__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React53__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.ScanText, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Contexts"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.PlusCircle, { className: "mr-2 h-4 w-4" }), " Add Context"))), /* @__PURE__ */ React53__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Contexts found.") : /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React53__namespace.default.createElement(Table2, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React53__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React53__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, item.description), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Edit3, { className: "h-4 w-4" })), /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React53__namespace.default.createElement(Dialog, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React53__namespace.default.createElement(DialogContent, { className: "sm:max-w-md" }, /* @__PURE__ */ React53__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(DialogTitle, null, currentItem ? "Edit Context" : "Add New Context")), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e) => setItemCode(e.target.value.toUpperCase()), placeholder: "e.g., HIST_INQ", disabled: !!currentItem })), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "itemName", value: itemName, onChange: (e) => setItemName(e.target.value), placeholder: "e.g., Historical Inquiry" })), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React53__namespace.default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e) => setItemDescription(e.target.value), placeholder: "e.g., Analyzing primary and secondary sources." }))), /* @__PURE__ */ React53__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemCode.trim() || !itemName.trim() }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Save")))), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialog, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogContent, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogTitle, null, "Are you sure?"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogDescription, null, 'This will permanently delete "', itemToDelete == null ? void 0 : itemToDelete.name, '".')), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogCancel, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogAction, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Delete"))))));
12770
+ }
12771
+ var knowledgeDimensions = ["Factual", "Conceptual", "Procedural"];
12772
+ var rawDifficultyLevels = ["E", "E~M", "M", "M~H", "H"];
12773
+ function ApproachManager() {
12774
+ var _a, _b, _c;
12775
+ const [items, setItems] = React53.useState([]);
12776
+ const [bloomLevels, setBloomLevels] = React53.useState([]);
12777
+ const [iSpringQuizTypeOptions, setISpringQuizTypeOptions] = React53.useState([]);
12778
+ const [isLoading, setIsLoading] = React53.useState(true);
12779
+ const [isDialogOpen, setIsDialogOpen] = React53.useState(false);
12780
+ const [isAlertOpen, setIsAlertOpen] = React53.useState(false);
12781
+ const [currentItem, setCurrentItem] = React53.useState(null);
12782
+ const [formState, setFormState] = React53.useState({});
12783
+ const [itemToDelete, setItemToDelete] = React53.useState(null);
12784
+ const [isPending, startTransition] = React53.useTransition();
12785
+ const { toast: toast2 } = useToast();
12786
+ const fetchItems = () => {
12787
+ setIsLoading(true);
12788
+ try {
12789
+ const approaches = MetadataService.getApproaches();
12790
+ const bloomLevelsData = MetadataService.getBloomLevels();
12791
+ const questionTypesData = MetadataService.getQuestionTypes();
12792
+ setItems(approaches);
12793
+ setBloomLevels(bloomLevelsData);
12794
+ setISpringQuizTypeOptions(questionTypesData.map((qt) => ({ label: qt.name, value: qt.code })));
12795
+ } catch (error) {
12796
+ toast2({ title: "Error", description: "Failed to fetch metadata.", variant: "destructive" });
12797
+ } finally {
12798
+ setIsLoading(false);
12799
+ }
12800
+ };
12801
+ React53.useEffect(() => {
12802
+ fetchItems();
12803
+ }, []);
12804
+ const resetForm = () => {
12805
+ setFormState({
12806
+ knowledgeDimension: "Factual",
12807
+ rawDifficulty: "E",
12808
+ bloomLevelCode: bloomLevels.length > 0 ? bloomLevels[0].code : "",
12809
+ iSpringQuizType: iSpringQuizTypeOptions.length > 0 ? iSpringQuizTypeOptions[0].value : "multiple_choice"
12810
+ });
12811
+ };
12812
+ const handleAddItem = () => {
12813
+ setCurrentItem(null);
12814
+ resetForm();
12815
+ setIsDialogOpen(true);
12816
+ };
12817
+ const handleEditItem = (item) => {
12818
+ setCurrentItem(item);
12819
+ setFormState({
12820
+ code: item.code,
12821
+ verbEn: item.verbEn,
12822
+ verbVi: item.verbVi,
12823
+ bloomLevelCode: item.bloomLevelCode,
12824
+ knowledgeDimension: item.knowledgeDimension,
12825
+ iSpringQuizType: item.iSpringQuizType,
12826
+ rawDifficulty: item.rawDifficulty,
12827
+ suggestContext: item.suggestContext,
12828
+ exampleEn: item.exampleEn,
12829
+ exampleVi: item.exampleVi
12830
+ });
12831
+ setIsDialogOpen(true);
12832
+ };
12833
+ const handleDeleteItem = (item) => {
12834
+ setItemToDelete(item);
12835
+ setIsAlertOpen(true);
12836
+ };
12837
+ const confirmDelete = () => {
12838
+ if (!itemToDelete) return;
12839
+ startTransition(() => {
12840
+ try {
12841
+ MetadataService.deleteApproach(itemToDelete.code);
12842
+ toast2({ title: "Success", description: `Approach "${itemToDelete.code}" deleted.` });
12843
+ fetchItems();
12844
+ } catch (error) {
12845
+ toast2({ title: "Error", description: "Failed to delete Approach.", variant: "destructive" });
12846
+ } finally {
12847
+ setIsAlertOpen(false);
12848
+ setItemToDelete(null);
12849
+ }
12850
+ });
12851
+ };
12852
+ const handleSubmit = () => {
12853
+ const { code, verbEn, verbVi } = formState;
12854
+ if (!(code == null ? void 0 : code.trim()) || !(verbEn == null ? void 0 : verbEn.trim()) || !(verbVi == null ? void 0 : verbVi.trim())) {
12855
+ toast2({ title: "Validation Error", description: "Code, Verb (EN), and Verb (VI) are required.", variant: "destructive" });
12856
+ return;
12857
+ }
12858
+ startTransition(() => {
12859
+ try {
12860
+ if (currentItem) {
12861
+ MetadataService.updateApproach(currentItem.id, formState);
12862
+ toast2({ title: "Success", description: "Approach updated." });
12863
+ } else {
12864
+ MetadataService.addApproach(formState);
12865
+ toast2({ title: "Success", description: "Approach added." });
12866
+ }
12867
+ fetchItems();
12868
+ setIsDialogOpen(false);
12869
+ } catch (error) {
12870
+ toast2({ title: "Error", description: error.message || "Failed to save Approach.", variant: "destructive" });
12871
+ }
12872
+ });
12873
+ };
12874
+ return /* @__PURE__ */ React53__namespace.default.createElement(Card, null, /* @__PURE__ */ React53__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React53__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Settings2, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Approaches"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.PlusCircle, { className: "mr-2 h-4 w-4" }), " Add Approach"))), /* @__PURE__ */ React53__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React53__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Approaches found.") : /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React53__namespace.default.createElement(Table2, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Approach ID"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Verb (VI)"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "Cognitive Level"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, null, "iSpring Type"), /* @__PURE__ */ React53__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React53__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React53__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "font-medium" }, item.code), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, item.verbVi), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, item.bloomLevelCode), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, null, item.iSpringQuizType), /* @__PURE__ */ React53__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Edit3, { className: "h-4 w-4" })), /* @__PURE__ */ React53__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React53__namespace.default.createElement(Dialog, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React53__namespace.default.createElement(DialogContent, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React53__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(DialogTitle, null, currentItem ? "Edit Approach" : "Add New Approach")), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", null, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "code" }, "Approach Code"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e) => setFormState((s) => __spreadProps(__spreadValues({}, s), { code: e.target.value.toUpperCase() })), placeholder: "e.g., REM-FAC-IDT-MCQ", disabled: !!currentItem })), /* @__PURE__ */ React53__namespace.default.createElement("div", null, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "verbEn" }, "Verb (English)"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "verbEn", value: formState.verbEn || "", onChange: (e) => setFormState((s) => __spreadProps(__spreadValues({}, s), { verbEn: e.target.value })), placeholder: "e.g., Identify" }))), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", null, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "verbVi" }, "Verb (Vietnamese)"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "verbVi", value: formState.verbVi || "", onChange: (e) => setFormState((s) => __spreadProps(__spreadValues({}, s), { verbVi: e.target.value })), placeholder: "e.g., Nh\u1EADn d\u1EA1ng" })), /* @__PURE__ */ React53__namespace.default.createElement("div", null, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "bloomLevelCode" }, "Cognitive Level"), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: formState.bloomLevelCode, onValueChange: (v) => setFormState((s) => __spreadProps(__spreadValues({}, s), { bloomLevelCode: v })) }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, null)), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, bloomLevels.map((level) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: level.code, value: level.code }, level.name)))))), /* @__PURE__ */ React53__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4" }, /* @__PURE__ */ React53__namespace.default.createElement("div", null, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "knowledgeDimension" }, "Knowledge Dimension"), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: formState.knowledgeDimension, onValueChange: (v) => setFormState((s) => __spreadProps(__spreadValues({}, s), { knowledgeDimension: v })) }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, null)), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, knowledgeDimensions.map((kd) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: kd, value: kd }, kd))))), /* @__PURE__ */ React53__namespace.default.createElement("div", null, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "iSpringQuizType" }, "iSpring Quiz Type"), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: formState.iSpringQuizType, onValueChange: (v) => setFormState((s) => __spreadProps(__spreadValues({}, s), { iSpringQuizType: v })) }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, null)), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, iSpringQuizTypeOptions.map((qt) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: qt.value, value: qt.value }, qt.label))))), /* @__PURE__ */ React53__namespace.default.createElement("div", null, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "rawDifficulty" }, "Raw Difficulty"), /* @__PURE__ */ React53__namespace.default.createElement(Select, { value: formState.rawDifficulty, onValueChange: (v) => setFormState((s) => __spreadProps(__spreadValues({}, s), { rawDifficulty: v })) }, /* @__PURE__ */ React53__namespace.default.createElement(SelectTrigger, null, /* @__PURE__ */ React53__namespace.default.createElement(SelectValue, null)), /* @__PURE__ */ React53__namespace.default.createElement(SelectContent, null, rawDifficultyLevels.map((rd) => /* @__PURE__ */ React53__namespace.default.createElement(SelectItem, { key: rd, value: rd }, rd)))))), /* @__PURE__ */ React53__namespace.default.createElement("div", null, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "suggestContext" }, "Suggest Context (comma-separated codes)"), /* @__PURE__ */ React53__namespace.default.createElement(Input, { id: "suggestContext", value: formState.suggestContext || "", onChange: (e) => setFormState((s) => __spreadProps(__spreadValues({}, s), { suggestContext: e.target.value })), placeholder: "e.g., A, B, D, G, H" })), /* @__PURE__ */ React53__namespace.default.createElement("div", null, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "exampleEn" }, "Example (English)"), /* @__PURE__ */ React53__namespace.default.createElement(Textarea, { id: "exampleEn", value: formState.exampleEn || "", onChange: (e) => setFormState((s) => __spreadProps(__spreadValues({}, s), { exampleEn: e.target.value })), placeholder: "English example prompt..." })), /* @__PURE__ */ React53__namespace.default.createElement("div", null, /* @__PURE__ */ React53__namespace.default.createElement(Label, { htmlFor: "exampleVi" }, "Example (Vietnamese)"), /* @__PURE__ */ React53__namespace.default.createElement(Textarea, { id: "exampleVi", value: formState.exampleVi || "", onChange: (e) => setFormState((s) => __spreadProps(__spreadValues({}, s), { exampleVi: e.target.value })), placeholder: "Vietnamese example prompt..." }))), /* @__PURE__ */ React53__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !((_a = formState.code) == null ? void 0 : _a.trim()) || !((_b = formState.verbEn) == null ? void 0 : _b.trim()) || !((_c = formState.verbVi) == null ? void 0 : _c.trim()) }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialog, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogContent, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogTitle, null, "Are you sure?"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogDescription, null, 'This will permanently delete "', itemToDelete == null ? void 0 : itemToDelete.code, '".')), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogCancel, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React53__namespace.default.createElement(AlertDialogAction, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React53__namespace.default.createElement(lucideReact.Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
12875
+ }
12876
+
12877
+ // src/react-ui/components/metadata/MetadataTabs.tsx
12878
+ function MetadataTabs() {
12879
+ const tabGridCols = "grid-cols-3 sm:grid-cols-3 md:grid-cols-5 lg:grid-cols-9";
12880
+ return /* @__PURE__ */ React53__namespace.default.createElement(Tabs, { defaultValue: "subjects", className: "w-full" }, /* @__PURE__ */ React53__namespace.default.createElement(TabsList, { className: `grid w-full ${tabGridCols}` }, /* @__PURE__ */ React53__namespace.default.createElement(TabsTrigger, { value: "subjects" }, "Subjects"), /* @__PURE__ */ React53__namespace.default.createElement(TabsTrigger, { value: "gradeLevels" }, "Grade Levels"), /* @__PURE__ */ React53__namespace.default.createElement(TabsTrigger, { value: "topics" }, "Topics"), /* @__PURE__ */ React53__namespace.default.createElement(TabsTrigger, { value: "categories" }, "Categories"), /* @__PURE__ */ React53__namespace.default.createElement(TabsTrigger, { value: "bloomLevels" }, "Bloom Levels"), /* @__PURE__ */ React53__namespace.default.createElement(TabsTrigger, { value: "questionTypes" }, "Question Types"), /* @__PURE__ */ React53__namespace.default.createElement(TabsTrigger, { value: "learningObjectives" }, "Learning Objectives"), /* @__PURE__ */ React53__namespace.default.createElement(TabsTrigger, { value: "contexts" }, "Contexts"), /* @__PURE__ */ React53__namespace.default.createElement(TabsTrigger, { value: "approaches" }, "Approaches")), /* @__PURE__ */ React53__namespace.default.createElement(TabsContent, { value: "subjects" }, /* @__PURE__ */ React53__namespace.default.createElement(React53.Suspense, { fallback: /* @__PURE__ */ React53__namespace.default.createElement(Skeleton, { className: "h-64 w-full" }) }, /* @__PURE__ */ React53__namespace.default.createElement(SubjectManager, null))), /* @__PURE__ */ React53__namespace.default.createElement(TabsContent, { value: "gradeLevels" }, /* @__PURE__ */ React53__namespace.default.createElement(React53.Suspense, { fallback: /* @__PURE__ */ React53__namespace.default.createElement(Skeleton, { className: "h-64 w-full" }) }, /* @__PURE__ */ React53__namespace.default.createElement(GradeLevelManager, null))), /* @__PURE__ */ React53__namespace.default.createElement(TabsContent, { value: "topics" }, /* @__PURE__ */ React53__namespace.default.createElement(React53.Suspense, { fallback: /* @__PURE__ */ React53__namespace.default.createElement(Skeleton, { className: "h-64 w-full" }) }, /* @__PURE__ */ React53__namespace.default.createElement(TopicManager, null))), /* @__PURE__ */ React53__namespace.default.createElement(TabsContent, { value: "categories" }, /* @__PURE__ */ React53__namespace.default.createElement(React53.Suspense, { fallback: /* @__PURE__ */ React53__namespace.default.createElement(Skeleton, { className: "h-64 w-full" }) }, /* @__PURE__ */ React53__namespace.default.createElement(CategoryManager, null))), /* @__PURE__ */ React53__namespace.default.createElement(TabsContent, { value: "bloomLevels" }, /* @__PURE__ */ React53__namespace.default.createElement(React53.Suspense, { fallback: /* @__PURE__ */ React53__namespace.default.createElement(Skeleton, { className: "h-64 w-full" }) }, /* @__PURE__ */ React53__namespace.default.createElement(BloomLevelManager, null))), /* @__PURE__ */ React53__namespace.default.createElement(TabsContent, { value: "questionTypes" }, /* @__PURE__ */ React53__namespace.default.createElement(React53.Suspense, { fallback: /* @__PURE__ */ React53__namespace.default.createElement(Skeleton, { className: "h-64 w-full" }) }, /* @__PURE__ */ React53__namespace.default.createElement(QuestionTypeManager, null))), /* @__PURE__ */ React53__namespace.default.createElement(TabsContent, { value: "learningObjectives" }, /* @__PURE__ */ React53__namespace.default.createElement(React53.Suspense, { fallback: /* @__PURE__ */ React53__namespace.default.createElement(Skeleton, { className: "h-64 w-full" }) }, /* @__PURE__ */ React53__namespace.default.createElement(LearningObjectiveManager, null))), /* @__PURE__ */ React53__namespace.default.createElement(TabsContent, { value: "contexts" }, /* @__PURE__ */ React53__namespace.default.createElement(React53.Suspense, { fallback: /* @__PURE__ */ React53__namespace.default.createElement(Skeleton, { className: "h-64 w-full" }) }, /* @__PURE__ */ React53__namespace.default.createElement(ContextManager, null))), /* @__PURE__ */ React53__namespace.default.createElement(TabsContent, { value: "approaches" }, /* @__PURE__ */ React53__namespace.default.createElement(React53.Suspense, { fallback: /* @__PURE__ */ React53__namespace.default.createElement(Skeleton, { className: "h-64 w-full" }) }, /* @__PURE__ */ React53__namespace.default.createElement(ApproachManager, null))));
12881
+ }
11133
12882
  var ToastProvider = ToastPrimitives__namespace.Provider;
11134
12883
  var ToastViewport = React53__namespace.forwardRef((_a, ref) => {
11135
12884
  var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
@@ -11234,21 +12983,37 @@ function Toaster() {
11234
12983
 
11235
12984
  exports.AIFullQuizGeneratorModal = AIFullQuizGeneratorModal;
11236
12985
  exports.AIQuestionGeneratorModal = AIQuestionGeneratorModal;
12986
+ exports.APIKeyManagerModal = APIKeyManagerModal;
11237
12987
  exports.APIKeyService = APIKeyService;
11238
12988
  exports.AchievementService = AchievementService;
12989
+ exports.ApproachManager = ApproachManager;
12990
+ exports.BloomLevelManager = BloomLevelManager;
12991
+ exports.CategoryManager = CategoryManager;
12992
+ exports.ContextManager = ContextManager;
11239
12993
  exports.EditQuestionModal = EditQuestionModal;
11240
12994
  exports.GEMINI_API_KEY_SERVICE_NAME = GEMINI_API_KEY_SERVICE_NAME;
12995
+ exports.GradeLevelManager = GradeLevelManager;
11241
12996
  exports.ImportQuestionsModal = ImportQuestionsModal;
11242
12997
  exports.KnowledgeCardService = KnowledgeCardService;
12998
+ exports.LearningObjectiveManager = LearningObjectiveManager;
12999
+ exports.MetadataService = MetadataService;
13000
+ exports.MetadataTabs = MetadataTabs;
11243
13001
  exports.PracticeHistoryService = PracticeHistoryService;
13002
+ exports.QuestionBankService = QuestionBankService;
13003
+ exports.QuestionFilters = QuestionFilters;
13004
+ exports.QuestionFormDialog = QuestionFormDialog;
11244
13005
  exports.QuestionImportService = QuestionImportService;
13006
+ exports.QuestionList = QuestionList;
13007
+ exports.QuestionTypeManager = QuestionTypeManager;
11245
13008
  exports.QuizAuthoringTool = QuizAuthoringTool;
11246
13009
  exports.QuizEditorService = QuizEditorService;
11247
13010
  exports.QuizEngine = QuizEngine;
11248
13011
  exports.QuoteService = QuoteService;
11249
13012
  exports.SCORMExportModal = SCORMExportModal;
11250
13013
  exports.SCORMService = SCORMService;
13014
+ exports.SubjectManager = SubjectManager;
11251
13015
  exports.Toaster = Toaster;
13016
+ exports.TopicManager = TopicManager;
11252
13017
  exports.UserConfigService = UserConfigService;
11253
13018
  exports.assessAndMapDocument = assessAndMapDocument;
11254
13019
  exports.cn = cn;