@thanh01.pmt/interactive-quiz-kit 1.0.69 → 1.0.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai.cjs +42 -44
- package/dist/ai.mjs +42 -44
- package/dist/authoring.cjs +98 -45
- package/dist/authoring.mjs +98 -45
- package/dist/react-ui.cjs +98 -45
- package/dist/react-ui.mjs +98 -45
- package/package.json +1 -1
package/dist/ai.cjs
CHANGED
|
@@ -2496,6 +2496,7 @@ function validateConsecutiveTypes(quizPlan) {
|
|
|
2496
2496
|
|
|
2497
2497
|
// src/services/TopicDataService.ts
|
|
2498
2498
|
var TopicDataService = class {
|
|
2499
|
+
// ... saveData, mergeData, getData, clearData methods remain the same ...
|
|
2499
2500
|
static saveData(data) {
|
|
2500
2501
|
try {
|
|
2501
2502
|
if (typeof window === "undefined") return;
|
|
@@ -2540,47 +2541,41 @@ var TopicDataService = class {
|
|
|
2540
2541
|
}
|
|
2541
2542
|
const headerLine = lines.shift();
|
|
2542
2543
|
const headers = headerLine.split(" ").map((h) => h.trim());
|
|
2543
|
-
|
|
2544
|
-
const errorMsg = `Invalid TSV header. Expected: "${this.EXPECTED_HEADERS.join(" ")}". Received: "${headers.join(" ")}"`;
|
|
2545
|
-
return { data: [], errors: [errorMsg] };
|
|
2546
|
-
}
|
|
2544
|
+
const headerMap = headers.map((h) => this.HEADER_MAP[h] || null);
|
|
2547
2545
|
const data = [];
|
|
2548
2546
|
const errors = [];
|
|
2549
2547
|
lines.forEach((line, index) => {
|
|
2550
|
-
const values = line.split(" ")
|
|
2551
|
-
|
|
2552
|
-
|
|
2548
|
+
const values = line.split(" ");
|
|
2549
|
+
const rowObject = {};
|
|
2550
|
+
headerMap.forEach((propName, i) => {
|
|
2551
|
+
if (propName) {
|
|
2552
|
+
const value = values[i]?.trim() || "";
|
|
2553
|
+
if (propName === "keywords" || propName === "stemElements" || propName === "bloomLevelsGuideline") {
|
|
2554
|
+
rowObject[propName] = value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
2555
|
+
} else {
|
|
2556
|
+
rowObject[propName] = value;
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
});
|
|
2560
|
+
if (!rowObject.code) {
|
|
2561
|
+
errors.push(`Line ${index + 2}: Missing required value for 'LO ID'.`);
|
|
2553
2562
|
return;
|
|
2554
2563
|
}
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
name,
|
|
2558
|
-
loDescription,
|
|
2559
|
-
subject,
|
|
2560
|
-
category,
|
|
2561
|
-
topic,
|
|
2562
|
-
keywordsStr,
|
|
2563
|
-
grade,
|
|
2564
|
-
stemElementsStr,
|
|
2565
|
-
bloomLevelsStr
|
|
2566
|
-
] = values;
|
|
2567
|
-
if (!loId || !loDescription || !subject || !category || !topic) {
|
|
2568
|
-
errors.push(`Line ${index + 2}: Missing required fields (LO ID, LO Description, Subject, Category, or Topic).`);
|
|
2569
|
-
return;
|
|
2564
|
+
if (!rowObject.name) {
|
|
2565
|
+
rowObject.name = rowObject.code;
|
|
2570
2566
|
}
|
|
2571
2567
|
const learningObjective = {
|
|
2572
2568
|
id: generateUniqueId("lo_"),
|
|
2573
|
-
code:
|
|
2574
|
-
name,
|
|
2575
|
-
description:
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
bloomLevelsGuideline: bloomLevelsStr.split(",").map((b) => b.trim()).filter(Boolean)
|
|
2569
|
+
code: rowObject.code,
|
|
2570
|
+
name: rowObject.name,
|
|
2571
|
+
description: rowObject.description,
|
|
2572
|
+
subject: rowObject.subject || "",
|
|
2573
|
+
category: rowObject.category || "",
|
|
2574
|
+
topic: rowObject.topic || "",
|
|
2575
|
+
grade: rowObject.grade || "",
|
|
2576
|
+
keywords: rowObject.keywords || [],
|
|
2577
|
+
stemElements: rowObject.stemElements || [],
|
|
2578
|
+
bloomLevelsGuideline: rowObject.bloomLevelsGuideline || []
|
|
2584
2579
|
};
|
|
2585
2580
|
data.push(learningObjective);
|
|
2586
2581
|
});
|
|
@@ -2608,17 +2603,20 @@ var TopicDataService = class {
|
|
|
2608
2603
|
}
|
|
2609
2604
|
};
|
|
2610
2605
|
TopicDataService.STORAGE_KEY = "interactive_quiz_kit_learning_objectives";
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
"LO
|
|
2614
|
-
"
|
|
2615
|
-
|
|
2616
|
-
"
|
|
2617
|
-
"
|
|
2618
|
-
"
|
|
2619
|
-
"
|
|
2620
|
-
"
|
|
2621
|
-
|
|
2606
|
+
// Define a map for flexible header mapping
|
|
2607
|
+
TopicDataService.HEADER_MAP = {
|
|
2608
|
+
"LO ID": "code",
|
|
2609
|
+
"LO Name": "name",
|
|
2610
|
+
// Ready for future addition
|
|
2611
|
+
"LO Description": "description",
|
|
2612
|
+
"Subject": "subject",
|
|
2613
|
+
"Category": "category",
|
|
2614
|
+
"Topic": "topic",
|
|
2615
|
+
"Keywords": "keywords",
|
|
2616
|
+
"Grade": "grade",
|
|
2617
|
+
"STEM Element(s)": "stemElements",
|
|
2618
|
+
"Bloom\u2019s Level(s) Guideline": "bloomLevelsGuideline"
|
|
2619
|
+
};
|
|
2622
2620
|
|
|
2623
2621
|
// src/ai/flows/generate-questions-from-quiz-plan.ts
|
|
2624
2622
|
var MAX_ATTEMPTS = 3;
|
package/dist/ai.mjs
CHANGED
|
@@ -2494,6 +2494,7 @@ function validateConsecutiveTypes(quizPlan) {
|
|
|
2494
2494
|
|
|
2495
2495
|
// src/services/TopicDataService.ts
|
|
2496
2496
|
var TopicDataService = class {
|
|
2497
|
+
// ... saveData, mergeData, getData, clearData methods remain the same ...
|
|
2497
2498
|
static saveData(data) {
|
|
2498
2499
|
try {
|
|
2499
2500
|
if (typeof window === "undefined") return;
|
|
@@ -2538,47 +2539,41 @@ var TopicDataService = class {
|
|
|
2538
2539
|
}
|
|
2539
2540
|
const headerLine = lines.shift();
|
|
2540
2541
|
const headers = headerLine.split(" ").map((h) => h.trim());
|
|
2541
|
-
|
|
2542
|
-
const errorMsg = `Invalid TSV header. Expected: "${this.EXPECTED_HEADERS.join(" ")}". Received: "${headers.join(" ")}"`;
|
|
2543
|
-
return { data: [], errors: [errorMsg] };
|
|
2544
|
-
}
|
|
2542
|
+
const headerMap = headers.map((h) => this.HEADER_MAP[h] || null);
|
|
2545
2543
|
const data = [];
|
|
2546
2544
|
const errors = [];
|
|
2547
2545
|
lines.forEach((line, index) => {
|
|
2548
|
-
const values = line.split(" ")
|
|
2549
|
-
|
|
2550
|
-
|
|
2546
|
+
const values = line.split(" ");
|
|
2547
|
+
const rowObject = {};
|
|
2548
|
+
headerMap.forEach((propName, i) => {
|
|
2549
|
+
if (propName) {
|
|
2550
|
+
const value = values[i]?.trim() || "";
|
|
2551
|
+
if (propName === "keywords" || propName === "stemElements" || propName === "bloomLevelsGuideline") {
|
|
2552
|
+
rowObject[propName] = value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
2553
|
+
} else {
|
|
2554
|
+
rowObject[propName] = value;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
});
|
|
2558
|
+
if (!rowObject.code) {
|
|
2559
|
+
errors.push(`Line ${index + 2}: Missing required value for 'LO ID'.`);
|
|
2551
2560
|
return;
|
|
2552
2561
|
}
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
name,
|
|
2556
|
-
loDescription,
|
|
2557
|
-
subject,
|
|
2558
|
-
category,
|
|
2559
|
-
topic,
|
|
2560
|
-
keywordsStr,
|
|
2561
|
-
grade,
|
|
2562
|
-
stemElementsStr,
|
|
2563
|
-
bloomLevelsStr
|
|
2564
|
-
] = values;
|
|
2565
|
-
if (!loId || !loDescription || !subject || !category || !topic) {
|
|
2566
|
-
errors.push(`Line ${index + 2}: Missing required fields (LO ID, LO Description, Subject, Category, or Topic).`);
|
|
2567
|
-
return;
|
|
2562
|
+
if (!rowObject.name) {
|
|
2563
|
+
rowObject.name = rowObject.code;
|
|
2568
2564
|
}
|
|
2569
2565
|
const learningObjective = {
|
|
2570
2566
|
id: generateUniqueId("lo_"),
|
|
2571
|
-
code:
|
|
2572
|
-
name,
|
|
2573
|
-
description:
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
bloomLevelsGuideline: bloomLevelsStr.split(",").map((b) => b.trim()).filter(Boolean)
|
|
2567
|
+
code: rowObject.code,
|
|
2568
|
+
name: rowObject.name,
|
|
2569
|
+
description: rowObject.description,
|
|
2570
|
+
subject: rowObject.subject || "",
|
|
2571
|
+
category: rowObject.category || "",
|
|
2572
|
+
topic: rowObject.topic || "",
|
|
2573
|
+
grade: rowObject.grade || "",
|
|
2574
|
+
keywords: rowObject.keywords || [],
|
|
2575
|
+
stemElements: rowObject.stemElements || [],
|
|
2576
|
+
bloomLevelsGuideline: rowObject.bloomLevelsGuideline || []
|
|
2582
2577
|
};
|
|
2583
2578
|
data.push(learningObjective);
|
|
2584
2579
|
});
|
|
@@ -2606,17 +2601,20 @@ var TopicDataService = class {
|
|
|
2606
2601
|
}
|
|
2607
2602
|
};
|
|
2608
2603
|
TopicDataService.STORAGE_KEY = "interactive_quiz_kit_learning_objectives";
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
"LO
|
|
2612
|
-
"
|
|
2613
|
-
|
|
2614
|
-
"
|
|
2615
|
-
"
|
|
2616
|
-
"
|
|
2617
|
-
"
|
|
2618
|
-
"
|
|
2619
|
-
|
|
2604
|
+
// Define a map for flexible header mapping
|
|
2605
|
+
TopicDataService.HEADER_MAP = {
|
|
2606
|
+
"LO ID": "code",
|
|
2607
|
+
"LO Name": "name",
|
|
2608
|
+
// Ready for future addition
|
|
2609
|
+
"LO Description": "description",
|
|
2610
|
+
"Subject": "subject",
|
|
2611
|
+
"Category": "category",
|
|
2612
|
+
"Topic": "topic",
|
|
2613
|
+
"Keywords": "keywords",
|
|
2614
|
+
"Grade": "grade",
|
|
2615
|
+
"STEM Element(s)": "stemElements",
|
|
2616
|
+
"Bloom\u2019s Level(s) Guideline": "bloomLevelsGuideline"
|
|
2617
|
+
};
|
|
2620
2618
|
|
|
2621
2619
|
// src/ai/flows/generate-questions-from-quiz-plan.ts
|
|
2622
2620
|
var MAX_ATTEMPTS = 3;
|
package/dist/authoring.cjs
CHANGED
|
@@ -8832,6 +8832,7 @@ init_react_shim();
|
|
|
8832
8832
|
// src/services/TopicDataService.ts
|
|
8833
8833
|
init_react_shim();
|
|
8834
8834
|
var TopicDataService = class {
|
|
8835
|
+
// ... saveData, mergeData, getData, clearData methods remain the same ...
|
|
8835
8836
|
static saveData(data) {
|
|
8836
8837
|
try {
|
|
8837
8838
|
if (typeof window === "undefined") return;
|
|
@@ -8876,47 +8877,41 @@ var TopicDataService = class {
|
|
|
8876
8877
|
}
|
|
8877
8878
|
const headerLine = lines.shift();
|
|
8878
8879
|
const headers = headerLine.split(" ").map((h2) => h2.trim());
|
|
8879
|
-
|
|
8880
|
-
const errorMsg = `Invalid TSV header. Expected: "${this.EXPECTED_HEADERS.join(" ")}". Received: "${headers.join(" ")}"`;
|
|
8881
|
-
return { data: [], errors: [errorMsg] };
|
|
8882
|
-
}
|
|
8880
|
+
const headerMap = headers.map((h2) => this.HEADER_MAP[h2] || null);
|
|
8883
8881
|
const data = [];
|
|
8884
8882
|
const errors2 = [];
|
|
8885
8883
|
lines.forEach((line, index3) => {
|
|
8886
|
-
const values = line.split(" ")
|
|
8887
|
-
|
|
8888
|
-
|
|
8884
|
+
const values = line.split(" ");
|
|
8885
|
+
const rowObject = {};
|
|
8886
|
+
headerMap.forEach((propName, i) => {
|
|
8887
|
+
if (propName) {
|
|
8888
|
+
const value = values[i]?.trim() || "";
|
|
8889
|
+
if (propName === "keywords" || propName === "stemElements" || propName === "bloomLevelsGuideline") {
|
|
8890
|
+
rowObject[propName] = value.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
8891
|
+
} else {
|
|
8892
|
+
rowObject[propName] = value;
|
|
8893
|
+
}
|
|
8894
|
+
}
|
|
8895
|
+
});
|
|
8896
|
+
if (!rowObject.code) {
|
|
8897
|
+
errors2.push(`Line ${index3 + 2}: Missing required value for 'LO ID'.`);
|
|
8889
8898
|
return;
|
|
8890
8899
|
}
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
name3,
|
|
8894
|
-
loDescription,
|
|
8895
|
-
subject,
|
|
8896
|
-
category,
|
|
8897
|
-
topic,
|
|
8898
|
-
keywordsStr,
|
|
8899
|
-
grade,
|
|
8900
|
-
stemElementsStr,
|
|
8901
|
-
bloomLevelsStr
|
|
8902
|
-
] = values;
|
|
8903
|
-
if (!loId || !loDescription || !subject || !category || !topic) {
|
|
8904
|
-
errors2.push(`Line ${index3 + 2}: Missing required fields (LO ID, LO Description, Subject, Category, or Topic).`);
|
|
8905
|
-
return;
|
|
8900
|
+
if (!rowObject.name) {
|
|
8901
|
+
rowObject.name = rowObject.code;
|
|
8906
8902
|
}
|
|
8907
8903
|
const learningObjective = {
|
|
8908
8904
|
id: generateUniqueId("lo_"),
|
|
8909
|
-
code:
|
|
8910
|
-
name:
|
|
8911
|
-
description:
|
|
8912
|
-
|
|
8913
|
-
|
|
8914
|
-
|
|
8915
|
-
|
|
8916
|
-
|
|
8917
|
-
|
|
8918
|
-
|
|
8919
|
-
bloomLevelsGuideline: bloomLevelsStr.split(",").map((b) => b.trim()).filter(Boolean)
|
|
8905
|
+
code: rowObject.code,
|
|
8906
|
+
name: rowObject.name,
|
|
8907
|
+
description: rowObject.description,
|
|
8908
|
+
subject: rowObject.subject || "",
|
|
8909
|
+
category: rowObject.category || "",
|
|
8910
|
+
topic: rowObject.topic || "",
|
|
8911
|
+
grade: rowObject.grade || "",
|
|
8912
|
+
keywords: rowObject.keywords || [],
|
|
8913
|
+
stemElements: rowObject.stemElements || [],
|
|
8914
|
+
bloomLevelsGuideline: rowObject.bloomLevelsGuideline || []
|
|
8920
8915
|
};
|
|
8921
8916
|
data.push(learningObjective);
|
|
8922
8917
|
});
|
|
@@ -8944,17 +8939,20 @@ var TopicDataService = class {
|
|
|
8944
8939
|
}
|
|
8945
8940
|
};
|
|
8946
8941
|
TopicDataService.STORAGE_KEY = "interactive_quiz_kit_learning_objectives";
|
|
8947
|
-
|
|
8948
|
-
|
|
8949
|
-
"LO
|
|
8950
|
-
"
|
|
8951
|
-
|
|
8952
|
-
"
|
|
8953
|
-
"
|
|
8954
|
-
"
|
|
8955
|
-
"
|
|
8956
|
-
"
|
|
8957
|
-
|
|
8942
|
+
// Define a map for flexible header mapping
|
|
8943
|
+
TopicDataService.HEADER_MAP = {
|
|
8944
|
+
"LO ID": "code",
|
|
8945
|
+
"LO Name": "name",
|
|
8946
|
+
// Ready for future addition
|
|
8947
|
+
"LO Description": "description",
|
|
8948
|
+
"Subject": "subject",
|
|
8949
|
+
"Category": "category",
|
|
8950
|
+
"Topic": "topic",
|
|
8951
|
+
"Keywords": "keywords",
|
|
8952
|
+
"Grade": "grade",
|
|
8953
|
+
"STEM Element(s)": "stemElements",
|
|
8954
|
+
"Bloom\u2019s Level(s) Guideline": "bloomLevelsGuideline"
|
|
8955
|
+
};
|
|
8958
8956
|
|
|
8959
8957
|
// src/ai/flows/generate-questions-from-quiz-plan.ts
|
|
8960
8958
|
var MAX_ATTEMPTS = 3;
|
|
@@ -76432,11 +76430,17 @@ function MetadataImportControls({ metadataName, onImport }) {
|
|
|
76432
76430
|
const fileInputRef = React119.useRef(null);
|
|
76433
76431
|
const { toast: toast2 } = useToast();
|
|
76434
76432
|
const processAndImportRecords = async (records, importSource) => {
|
|
76433
|
+
console.log(`[ImportControls] Processing ${records.length} records from ${importSource} for ${metadataName}.`);
|
|
76435
76434
|
if (records.length === 0) {
|
|
76436
76435
|
toast2({ title: "No Data", description: `The selected ${importSource === "file" ? "file" : "JSON string"} contains no data to import.`, variant: "destructive" });
|
|
76437
76436
|
return;
|
|
76438
76437
|
}
|
|
76439
|
-
|
|
76438
|
+
try {
|
|
76439
|
+
await onImport(records);
|
|
76440
|
+
} catch (error) {
|
|
76441
|
+
console.error(`[ImportControls] Error during onImport callback for ${metadataName}:`, error);
|
|
76442
|
+
toast2({ title: "Import Failed", description: `An error occurred while saving the data: ${error instanceof Error ? error.message : String(error)}`, variant: "destructive" });
|
|
76443
|
+
}
|
|
76440
76444
|
setIsOpen(false);
|
|
76441
76445
|
setJsonString("");
|
|
76442
76446
|
};
|
|
@@ -76468,8 +76472,10 @@ function MetadataImportControls({ metadataName, onImport }) {
|
|
|
76468
76472
|
return record;
|
|
76469
76473
|
});
|
|
76470
76474
|
}
|
|
76475
|
+
console.log(`[ImportControls] File parsed successfully. Found ${records.length} records.`);
|
|
76471
76476
|
await processAndImportRecords(records, "file");
|
|
76472
76477
|
} catch (err) {
|
|
76478
|
+
console.error("[ImportControls] Error parsing file:", err);
|
|
76473
76479
|
toast2({ title: "Import Error", description: `Failed to process file: ${err.message}`, variant: "destructive" });
|
|
76474
76480
|
}
|
|
76475
76481
|
});
|
|
@@ -77389,6 +77395,53 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
|
|
|
77389
77395
|
});
|
|
77390
77396
|
};
|
|
77391
77397
|
const handleImport = async (records) => {
|
|
77398
|
+
console.log(`[LO Manager] handleImport called with ${records.length} raw records.`);
|
|
77399
|
+
if (!onBulkAdd) {
|
|
77400
|
+
console.error("[LO Manager] onBulkAdd handler is not provided.");
|
|
77401
|
+
return;
|
|
77402
|
+
}
|
|
77403
|
+
const parseStringToArray = (input) => {
|
|
77404
|
+
if (Array.isArray(input)) return input;
|
|
77405
|
+
if (typeof input === "string") return input.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
77406
|
+
return [];
|
|
77407
|
+
};
|
|
77408
|
+
const validationResult = records.reduce((acc, rec) => {
|
|
77409
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
77410
|
+
acc.valid.push({
|
|
77411
|
+
code: rec.code,
|
|
77412
|
+
name: rec.name,
|
|
77413
|
+
description: rec.description || rec.name,
|
|
77414
|
+
subject: rec.subject || "",
|
|
77415
|
+
subjectCode: rec.subjectCode,
|
|
77416
|
+
category: rec.category || "",
|
|
77417
|
+
categoryCode: rec.categoryCode,
|
|
77418
|
+
topic: rec.topic || "",
|
|
77419
|
+
topicCode: rec.topicCode,
|
|
77420
|
+
grade: rec.grade || "",
|
|
77421
|
+
gradeCode: rec.gradeCode,
|
|
77422
|
+
keywords: parseStringToArray(rec.keywords),
|
|
77423
|
+
stemElements: parseStringToArray(rec.stemElements),
|
|
77424
|
+
bloomLevelsGuideline: parseStringToArray(rec.bloomLevelsGuideline)
|
|
77425
|
+
});
|
|
77426
|
+
} else {
|
|
77427
|
+
acc.invalidCount++;
|
|
77428
|
+
}
|
|
77429
|
+
return acc;
|
|
77430
|
+
}, { valid: [], invalidCount: 0 });
|
|
77431
|
+
console.log(`[LO Manager] Validation complete. ${validationResult.valid.length} valid records found.`);
|
|
77432
|
+
if (validationResult.invalidCount > 0) {
|
|
77433
|
+
toast2({
|
|
77434
|
+
title: "Import Warning",
|
|
77435
|
+
description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
|
|
77436
|
+
variant: "destructive"
|
|
77437
|
+
});
|
|
77438
|
+
}
|
|
77439
|
+
if (validationResult.valid.length > 0) {
|
|
77440
|
+
console.log("[LO Manager] Calling onBulkAdd prop with validated data...");
|
|
77441
|
+
await onBulkAdd(validationResult.valid);
|
|
77442
|
+
} else {
|
|
77443
|
+
console.log("[LO Manager] No valid records to import.");
|
|
77444
|
+
}
|
|
77392
77445
|
};
|
|
77393
77446
|
return /* @__PURE__ */ React119__namespace.default.createElement(Card, null, /* @__PURE__ */ React119__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React119__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React119__namespace.default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Learning Objectives"), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React119__namespace.default.createElement(MetadataImportControls, { metadataName: "Learning Objectives", onImport: handleImport }), /* @__PURE__ */ React119__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React119__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React119__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React119__namespace.default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React119__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React119__namespace.default.createElement(Table2, null, /* @__PURE__ */ React119__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React119__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React119__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React119__namespace.default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React119__namespace.default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React119__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React119__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React119__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React119__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React119__namespace.default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React119__namespace.default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React119__namespace.default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React119__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React119__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React119__namespace.default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React119__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React119__namespace.default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React119__namespace.default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React119__namespace.default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React119__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e2) => handleFormChange("code", e2.target.value.toUpperCase()), disabled: !!currentItem })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "name", value: formState.name || "", onChange: (e2) => handleFormChange("name", e2.target.value) }))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "subject", value: formState.subject || "", onChange: (e2) => handleFormChange("subject", e2.target.value) })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React119__namespace.default.createElement(EditableCombobox, { options: subjects.map((s2) => ({ value: s2.code, label: s2.name })), value: formState.subjectCode || "", onChange: (val) => handleFormChange("subjectCode", val), placeholder: "Select a subject..." }))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "category", value: formState.category || "", onChange: (e2) => handleFormChange("category", e2.target.value) })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "categoryCode", value: formState.categoryCode || "", onChange: (e2) => handleFormChange("categoryCode", e2.target.value) }))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "topic", value: formState.topic || "", onChange: (e2) => handleFormChange("topic", e2.target.value) })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "topicCode", value: formState.topicCode || "", onChange: (e2) => handleFormChange("topicCode", e2.target.value) }))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "grade", value: formState.grade || "", onChange: (e2) => handleFormChange("grade", e2.target.value) })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "gradeCode", value: formState.gradeCode || "", onChange: (e2) => handleFormChange("gradeCode", e2.target.value) }))), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React119__namespace.default.createElement(Textarea, { id: "keywords", value: formState.keywords?.join(", ") || "", onChange: (e2) => handleFormChange("keywords", e2.target.value.split(",").map((s2) => s2.trim())) })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React119__namespace.default.createElement(Textarea, { id: "stemElements", value: formState.stemElements?.join(", ") || "", onChange: (e2) => handleFormChange("stemElements", e2.target.value.split(",").map((s2) => s2.trim())) })), /* @__PURE__ */ React119__namespace.default.createElement("div", null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React119__namespace.default.createElement(Textarea, { id: "bloomLevelsGuideline", value: formState.bloomLevelsGuideline?.join(", ") || "", onChange: (e2) => handleFormChange("bloomLevelsGuideline", e2.target.value.split(",").map((s2) => s2.trim())) }))), /* @__PURE__ */ React119__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React119__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React119__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !formState.name?.trim() || !formState.code?.trim() }, isPending && /* @__PURE__ */ React119__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React119__namespace.default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React119__namespace.default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React119__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
77394
77447
|
}
|
package/dist/authoring.mjs
CHANGED
|
@@ -8767,6 +8767,7 @@ init_react_shim();
|
|
|
8767
8767
|
// src/services/TopicDataService.ts
|
|
8768
8768
|
init_react_shim();
|
|
8769
8769
|
var TopicDataService = class {
|
|
8770
|
+
// ... saveData, mergeData, getData, clearData methods remain the same ...
|
|
8770
8771
|
static saveData(data) {
|
|
8771
8772
|
try {
|
|
8772
8773
|
if (typeof window === "undefined") return;
|
|
@@ -8811,47 +8812,41 @@ var TopicDataService = class {
|
|
|
8811
8812
|
}
|
|
8812
8813
|
const headerLine = lines.shift();
|
|
8813
8814
|
const headers = headerLine.split(" ").map((h2) => h2.trim());
|
|
8814
|
-
|
|
8815
|
-
const errorMsg = `Invalid TSV header. Expected: "${this.EXPECTED_HEADERS.join(" ")}". Received: "${headers.join(" ")}"`;
|
|
8816
|
-
return { data: [], errors: [errorMsg] };
|
|
8817
|
-
}
|
|
8815
|
+
const headerMap = headers.map((h2) => this.HEADER_MAP[h2] || null);
|
|
8818
8816
|
const data = [];
|
|
8819
8817
|
const errors2 = [];
|
|
8820
8818
|
lines.forEach((line, index3) => {
|
|
8821
|
-
const values = line.split(" ")
|
|
8822
|
-
|
|
8823
|
-
|
|
8819
|
+
const values = line.split(" ");
|
|
8820
|
+
const rowObject = {};
|
|
8821
|
+
headerMap.forEach((propName, i) => {
|
|
8822
|
+
if (propName) {
|
|
8823
|
+
const value = values[i]?.trim() || "";
|
|
8824
|
+
if (propName === "keywords" || propName === "stemElements" || propName === "bloomLevelsGuideline") {
|
|
8825
|
+
rowObject[propName] = value.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
8826
|
+
} else {
|
|
8827
|
+
rowObject[propName] = value;
|
|
8828
|
+
}
|
|
8829
|
+
}
|
|
8830
|
+
});
|
|
8831
|
+
if (!rowObject.code) {
|
|
8832
|
+
errors2.push(`Line ${index3 + 2}: Missing required value for 'LO ID'.`);
|
|
8824
8833
|
return;
|
|
8825
8834
|
}
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
name3,
|
|
8829
|
-
loDescription,
|
|
8830
|
-
subject,
|
|
8831
|
-
category,
|
|
8832
|
-
topic,
|
|
8833
|
-
keywordsStr,
|
|
8834
|
-
grade,
|
|
8835
|
-
stemElementsStr,
|
|
8836
|
-
bloomLevelsStr
|
|
8837
|
-
] = values;
|
|
8838
|
-
if (!loId || !loDescription || !subject || !category || !topic) {
|
|
8839
|
-
errors2.push(`Line ${index3 + 2}: Missing required fields (LO ID, LO Description, Subject, Category, or Topic).`);
|
|
8840
|
-
return;
|
|
8835
|
+
if (!rowObject.name) {
|
|
8836
|
+
rowObject.name = rowObject.code;
|
|
8841
8837
|
}
|
|
8842
8838
|
const learningObjective = {
|
|
8843
8839
|
id: generateUniqueId("lo_"),
|
|
8844
|
-
code:
|
|
8845
|
-
name:
|
|
8846
|
-
description:
|
|
8847
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
bloomLevelsGuideline: bloomLevelsStr.split(",").map((b) => b.trim()).filter(Boolean)
|
|
8840
|
+
code: rowObject.code,
|
|
8841
|
+
name: rowObject.name,
|
|
8842
|
+
description: rowObject.description,
|
|
8843
|
+
subject: rowObject.subject || "",
|
|
8844
|
+
category: rowObject.category || "",
|
|
8845
|
+
topic: rowObject.topic || "",
|
|
8846
|
+
grade: rowObject.grade || "",
|
|
8847
|
+
keywords: rowObject.keywords || [],
|
|
8848
|
+
stemElements: rowObject.stemElements || [],
|
|
8849
|
+
bloomLevelsGuideline: rowObject.bloomLevelsGuideline || []
|
|
8855
8850
|
};
|
|
8856
8851
|
data.push(learningObjective);
|
|
8857
8852
|
});
|
|
@@ -8879,17 +8874,20 @@ var TopicDataService = class {
|
|
|
8879
8874
|
}
|
|
8880
8875
|
};
|
|
8881
8876
|
TopicDataService.STORAGE_KEY = "interactive_quiz_kit_learning_objectives";
|
|
8882
|
-
|
|
8883
|
-
|
|
8884
|
-
"LO
|
|
8885
|
-
"
|
|
8886
|
-
|
|
8887
|
-
"
|
|
8888
|
-
"
|
|
8889
|
-
"
|
|
8890
|
-
"
|
|
8891
|
-
"
|
|
8892
|
-
|
|
8877
|
+
// Define a map for flexible header mapping
|
|
8878
|
+
TopicDataService.HEADER_MAP = {
|
|
8879
|
+
"LO ID": "code",
|
|
8880
|
+
"LO Name": "name",
|
|
8881
|
+
// Ready for future addition
|
|
8882
|
+
"LO Description": "description",
|
|
8883
|
+
"Subject": "subject",
|
|
8884
|
+
"Category": "category",
|
|
8885
|
+
"Topic": "topic",
|
|
8886
|
+
"Keywords": "keywords",
|
|
8887
|
+
"Grade": "grade",
|
|
8888
|
+
"STEM Element(s)": "stemElements",
|
|
8889
|
+
"Bloom\u2019s Level(s) Guideline": "bloomLevelsGuideline"
|
|
8890
|
+
};
|
|
8893
8891
|
|
|
8894
8892
|
// src/ai/flows/generate-questions-from-quiz-plan.ts
|
|
8895
8893
|
var MAX_ATTEMPTS = 3;
|
|
@@ -76367,11 +76365,17 @@ function MetadataImportControls({ metadataName, onImport }) {
|
|
|
76367
76365
|
const fileInputRef = useRef(null);
|
|
76368
76366
|
const { toast: toast2 } = useToast();
|
|
76369
76367
|
const processAndImportRecords = async (records, importSource) => {
|
|
76368
|
+
console.log(`[ImportControls] Processing ${records.length} records from ${importSource} for ${metadataName}.`);
|
|
76370
76369
|
if (records.length === 0) {
|
|
76371
76370
|
toast2({ title: "No Data", description: `The selected ${importSource === "file" ? "file" : "JSON string"} contains no data to import.`, variant: "destructive" });
|
|
76372
76371
|
return;
|
|
76373
76372
|
}
|
|
76374
|
-
|
|
76373
|
+
try {
|
|
76374
|
+
await onImport(records);
|
|
76375
|
+
} catch (error) {
|
|
76376
|
+
console.error(`[ImportControls] Error during onImport callback for ${metadataName}:`, error);
|
|
76377
|
+
toast2({ title: "Import Failed", description: `An error occurred while saving the data: ${error instanceof Error ? error.message : String(error)}`, variant: "destructive" });
|
|
76378
|
+
}
|
|
76375
76379
|
setIsOpen(false);
|
|
76376
76380
|
setJsonString("");
|
|
76377
76381
|
};
|
|
@@ -76403,8 +76407,10 @@ function MetadataImportControls({ metadataName, onImport }) {
|
|
|
76403
76407
|
return record;
|
|
76404
76408
|
});
|
|
76405
76409
|
}
|
|
76410
|
+
console.log(`[ImportControls] File parsed successfully. Found ${records.length} records.`);
|
|
76406
76411
|
await processAndImportRecords(records, "file");
|
|
76407
76412
|
} catch (err) {
|
|
76413
|
+
console.error("[ImportControls] Error parsing file:", err);
|
|
76408
76414
|
toast2({ title: "Import Error", description: `Failed to process file: ${err.message}`, variant: "destructive" });
|
|
76409
76415
|
}
|
|
76410
76416
|
});
|
|
@@ -77324,6 +77330,53 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
|
|
|
77324
77330
|
});
|
|
77325
77331
|
};
|
|
77326
77332
|
const handleImport = async (records) => {
|
|
77333
|
+
console.log(`[LO Manager] handleImport called with ${records.length} raw records.`);
|
|
77334
|
+
if (!onBulkAdd) {
|
|
77335
|
+
console.error("[LO Manager] onBulkAdd handler is not provided.");
|
|
77336
|
+
return;
|
|
77337
|
+
}
|
|
77338
|
+
const parseStringToArray = (input) => {
|
|
77339
|
+
if (Array.isArray(input)) return input;
|
|
77340
|
+
if (typeof input === "string") return input.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
77341
|
+
return [];
|
|
77342
|
+
};
|
|
77343
|
+
const validationResult = records.reduce((acc, rec) => {
|
|
77344
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
77345
|
+
acc.valid.push({
|
|
77346
|
+
code: rec.code,
|
|
77347
|
+
name: rec.name,
|
|
77348
|
+
description: rec.description || rec.name,
|
|
77349
|
+
subject: rec.subject || "",
|
|
77350
|
+
subjectCode: rec.subjectCode,
|
|
77351
|
+
category: rec.category || "",
|
|
77352
|
+
categoryCode: rec.categoryCode,
|
|
77353
|
+
topic: rec.topic || "",
|
|
77354
|
+
topicCode: rec.topicCode,
|
|
77355
|
+
grade: rec.grade || "",
|
|
77356
|
+
gradeCode: rec.gradeCode,
|
|
77357
|
+
keywords: parseStringToArray(rec.keywords),
|
|
77358
|
+
stemElements: parseStringToArray(rec.stemElements),
|
|
77359
|
+
bloomLevelsGuideline: parseStringToArray(rec.bloomLevelsGuideline)
|
|
77360
|
+
});
|
|
77361
|
+
} else {
|
|
77362
|
+
acc.invalidCount++;
|
|
77363
|
+
}
|
|
77364
|
+
return acc;
|
|
77365
|
+
}, { valid: [], invalidCount: 0 });
|
|
77366
|
+
console.log(`[LO Manager] Validation complete. ${validationResult.valid.length} valid records found.`);
|
|
77367
|
+
if (validationResult.invalidCount > 0) {
|
|
77368
|
+
toast2({
|
|
77369
|
+
title: "Import Warning",
|
|
77370
|
+
description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
|
|
77371
|
+
variant: "destructive"
|
|
77372
|
+
});
|
|
77373
|
+
}
|
|
77374
|
+
if (validationResult.valid.length > 0) {
|
|
77375
|
+
console.log("[LO Manager] Calling onBulkAdd prop with validated data...");
|
|
77376
|
+
await onBulkAdd(validationResult.valid);
|
|
77377
|
+
} else {
|
|
77378
|
+
console.log("[LO Manager] No valid records to import.");
|
|
77379
|
+
}
|
|
77327
77380
|
};
|
|
77328
77381
|
return /* @__PURE__ */ React119__default.createElement(Card, null, /* @__PURE__ */ React119__default.createElement(CardHeader, null, /* @__PURE__ */ React119__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React119__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React119__default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Learning Objectives"), /* @__PURE__ */ React119__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React119__default.createElement(MetadataImportControls, { metadataName: "Learning Objectives", onImport: handleImport }), /* @__PURE__ */ React119__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React119__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React119__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React119__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React119__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React119__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React119__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React119__default.createElement(Table2, null, /* @__PURE__ */ React119__default.createElement(TableHeader, null, /* @__PURE__ */ React119__default.createElement(TableRow, null, /* @__PURE__ */ React119__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React119__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React119__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React119__default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React119__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React119__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React119__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React119__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React119__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React119__default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React119__default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React119__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React119__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React119__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React119__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React119__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React119__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React119__default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React119__default.createElement(DialogHeader, null, /* @__PURE__ */ React119__default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React119__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React119__default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e2) => handleFormChange("code", e2.target.value.toUpperCase()), disabled: !!currentItem })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React119__default.createElement(Input, { id: "name", value: formState.name || "", onChange: (e2) => handleFormChange("name", e2.target.value) }))), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React119__default.createElement(Input, { id: "subject", value: formState.subject || "", onChange: (e2) => handleFormChange("subject", e2.target.value) })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React119__default.createElement(EditableCombobox, { options: subjects.map((s2) => ({ value: s2.code, label: s2.name })), value: formState.subjectCode || "", onChange: (val) => handleFormChange("subjectCode", val), placeholder: "Select a subject..." }))), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React119__default.createElement(Input, { id: "category", value: formState.category || "", onChange: (e2) => handleFormChange("category", e2.target.value) })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React119__default.createElement(Input, { id: "categoryCode", value: formState.categoryCode || "", onChange: (e2) => handleFormChange("categoryCode", e2.target.value) }))), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React119__default.createElement(Input, { id: "topic", value: formState.topic || "", onChange: (e2) => handleFormChange("topic", e2.target.value) })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React119__default.createElement(Input, { id: "topicCode", value: formState.topicCode || "", onChange: (e2) => handleFormChange("topicCode", e2.target.value) }))), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React119__default.createElement(Input, { id: "grade", value: formState.grade || "", onChange: (e2) => handleFormChange("grade", e2.target.value) })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React119__default.createElement(Input, { id: "gradeCode", value: formState.gradeCode || "", onChange: (e2) => handleFormChange("gradeCode", e2.target.value) }))), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React119__default.createElement(Textarea, { id: "keywords", value: formState.keywords?.join(", ") || "", onChange: (e2) => handleFormChange("keywords", e2.target.value.split(",").map((s2) => s2.trim())) })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React119__default.createElement(Textarea, { id: "stemElements", value: formState.stemElements?.join(", ") || "", onChange: (e2) => handleFormChange("stemElements", e2.target.value.split(",").map((s2) => s2.trim())) })), /* @__PURE__ */ React119__default.createElement("div", null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React119__default.createElement(Textarea, { id: "bloomLevelsGuideline", value: formState.bloomLevelsGuideline?.join(", ") || "", onChange: (e2) => handleFormChange("bloomLevelsGuideline", e2.target.value.split(",").map((s2) => s2.trim())) }))), /* @__PURE__ */ React119__default.createElement(DialogFooter, null, /* @__PURE__ */ React119__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React119__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !formState.name?.trim() || !formState.code?.trim() }, isPending && /* @__PURE__ */ React119__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React119__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React119__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React119__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React119__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React119__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React119__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React119__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React119__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React119__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
77329
77382
|
}
|
package/dist/react-ui.cjs
CHANGED
|
@@ -101917,6 +101917,7 @@ init_react_shim();
|
|
|
101917
101917
|
// src/services/TopicDataService.ts
|
|
101918
101918
|
init_react_shim();
|
|
101919
101919
|
var TopicDataService = class {
|
|
101920
|
+
// ... saveData, mergeData, getData, clearData methods remain the same ...
|
|
101920
101921
|
static saveData(data) {
|
|
101921
101922
|
try {
|
|
101922
101923
|
if (typeof window === "undefined") return;
|
|
@@ -101961,47 +101962,41 @@ var TopicDataService = class {
|
|
|
101961
101962
|
}
|
|
101962
101963
|
const headerLine = lines.shift();
|
|
101963
101964
|
const headers = headerLine.split(" ").map((h3) => h3.trim());
|
|
101964
|
-
|
|
101965
|
-
const errorMsg = `Invalid TSV header. Expected: "${this.EXPECTED_HEADERS.join(" ")}". Received: "${headers.join(" ")}"`;
|
|
101966
|
-
return { data: [], errors: [errorMsg] };
|
|
101967
|
-
}
|
|
101965
|
+
const headerMap = headers.map((h3) => this.HEADER_MAP[h3] || null);
|
|
101968
101966
|
const data = [];
|
|
101969
101967
|
const errors2 = [];
|
|
101970
101968
|
lines.forEach((line, index3) => {
|
|
101971
|
-
const values = line.split(" ")
|
|
101972
|
-
|
|
101973
|
-
|
|
101969
|
+
const values = line.split(" ");
|
|
101970
|
+
const rowObject = {};
|
|
101971
|
+
headerMap.forEach((propName, i2) => {
|
|
101972
|
+
if (propName) {
|
|
101973
|
+
const value = values[i2]?.trim() || "";
|
|
101974
|
+
if (propName === "keywords" || propName === "stemElements" || propName === "bloomLevelsGuideline") {
|
|
101975
|
+
rowObject[propName] = value.split(",").map((s4) => s4.trim()).filter(Boolean);
|
|
101976
|
+
} else {
|
|
101977
|
+
rowObject[propName] = value;
|
|
101978
|
+
}
|
|
101979
|
+
}
|
|
101980
|
+
});
|
|
101981
|
+
if (!rowObject.code) {
|
|
101982
|
+
errors2.push(`Line ${index3 + 2}: Missing required value for 'LO ID'.`);
|
|
101974
101983
|
return;
|
|
101975
101984
|
}
|
|
101976
|
-
|
|
101977
|
-
|
|
101978
|
-
name3,
|
|
101979
|
-
loDescription,
|
|
101980
|
-
subject,
|
|
101981
|
-
category,
|
|
101982
|
-
topic,
|
|
101983
|
-
keywordsStr,
|
|
101984
|
-
grade,
|
|
101985
|
-
stemElementsStr,
|
|
101986
|
-
bloomLevelsStr
|
|
101987
|
-
] = values;
|
|
101988
|
-
if (!loId || !loDescription || !subject || !category || !topic) {
|
|
101989
|
-
errors2.push(`Line ${index3 + 2}: Missing required fields (LO ID, LO Description, Subject, Category, or Topic).`);
|
|
101990
|
-
return;
|
|
101985
|
+
if (!rowObject.name) {
|
|
101986
|
+
rowObject.name = rowObject.code;
|
|
101991
101987
|
}
|
|
101992
101988
|
const learningObjective = {
|
|
101993
101989
|
id: generateUniqueId("lo_"),
|
|
101994
|
-
code:
|
|
101995
|
-
name:
|
|
101996
|
-
description:
|
|
101997
|
-
|
|
101998
|
-
|
|
101999
|
-
|
|
102000
|
-
|
|
102001
|
-
|
|
102002
|
-
|
|
102003
|
-
|
|
102004
|
-
bloomLevelsGuideline: bloomLevelsStr.split(",").map((b2) => b2.trim()).filter(Boolean)
|
|
101990
|
+
code: rowObject.code,
|
|
101991
|
+
name: rowObject.name,
|
|
101992
|
+
description: rowObject.description,
|
|
101993
|
+
subject: rowObject.subject || "",
|
|
101994
|
+
category: rowObject.category || "",
|
|
101995
|
+
topic: rowObject.topic || "",
|
|
101996
|
+
grade: rowObject.grade || "",
|
|
101997
|
+
keywords: rowObject.keywords || [],
|
|
101998
|
+
stemElements: rowObject.stemElements || [],
|
|
101999
|
+
bloomLevelsGuideline: rowObject.bloomLevelsGuideline || []
|
|
102005
102000
|
};
|
|
102006
102001
|
data.push(learningObjective);
|
|
102007
102002
|
});
|
|
@@ -102029,17 +102024,20 @@ var TopicDataService = class {
|
|
|
102029
102024
|
}
|
|
102030
102025
|
};
|
|
102031
102026
|
TopicDataService.STORAGE_KEY = "interactive_quiz_kit_learning_objectives";
|
|
102032
|
-
|
|
102033
|
-
|
|
102034
|
-
"LO
|
|
102035
|
-
"
|
|
102036
|
-
|
|
102037
|
-
"
|
|
102038
|
-
"
|
|
102039
|
-
"
|
|
102040
|
-
"
|
|
102041
|
-
"
|
|
102042
|
-
|
|
102027
|
+
// Define a map for flexible header mapping
|
|
102028
|
+
TopicDataService.HEADER_MAP = {
|
|
102029
|
+
"LO ID": "code",
|
|
102030
|
+
"LO Name": "name",
|
|
102031
|
+
// Ready for future addition
|
|
102032
|
+
"LO Description": "description",
|
|
102033
|
+
"Subject": "subject",
|
|
102034
|
+
"Category": "category",
|
|
102035
|
+
"Topic": "topic",
|
|
102036
|
+
"Keywords": "keywords",
|
|
102037
|
+
"Grade": "grade",
|
|
102038
|
+
"STEM Element(s)": "stemElements",
|
|
102039
|
+
"Bloom\u2019s Level(s) Guideline": "bloomLevelsGuideline"
|
|
102040
|
+
};
|
|
102043
102041
|
|
|
102044
102042
|
// src/ai/flows/question-gen/generate-coding-question.ts
|
|
102045
102043
|
init_react_shim();
|
|
@@ -138728,11 +138726,17 @@ function MetadataImportControls({ metadataName, onImport }) {
|
|
|
138728
138726
|
const fileInputRef = React169.useRef(null);
|
|
138729
138727
|
const { toast: toast2 } = useToast();
|
|
138730
138728
|
const processAndImportRecords = async (records, importSource) => {
|
|
138729
|
+
console.log(`[ImportControls] Processing ${records.length} records from ${importSource} for ${metadataName}.`);
|
|
138731
138730
|
if (records.length === 0) {
|
|
138732
138731
|
toast2({ title: "No Data", description: `The selected ${importSource === "file" ? "file" : "JSON string"} contains no data to import.`, variant: "destructive" });
|
|
138733
138732
|
return;
|
|
138734
138733
|
}
|
|
138735
|
-
|
|
138734
|
+
try {
|
|
138735
|
+
await onImport(records);
|
|
138736
|
+
} catch (error) {
|
|
138737
|
+
console.error(`[ImportControls] Error during onImport callback for ${metadataName}:`, error);
|
|
138738
|
+
toast2({ title: "Import Failed", description: `An error occurred while saving the data: ${error instanceof Error ? error.message : String(error)}`, variant: "destructive" });
|
|
138739
|
+
}
|
|
138736
138740
|
setIsOpen(false);
|
|
138737
138741
|
setJsonString("");
|
|
138738
138742
|
};
|
|
@@ -138764,8 +138768,10 @@ function MetadataImportControls({ metadataName, onImport }) {
|
|
|
138764
138768
|
return record;
|
|
138765
138769
|
});
|
|
138766
138770
|
}
|
|
138771
|
+
console.log(`[ImportControls] File parsed successfully. Found ${records.length} records.`);
|
|
138767
138772
|
await processAndImportRecords(records, "file");
|
|
138768
138773
|
} catch (err) {
|
|
138774
|
+
console.error("[ImportControls] Error parsing file:", err);
|
|
138769
138775
|
toast2({ title: "Import Error", description: `Failed to process file: ${err.message}`, variant: "destructive" });
|
|
138770
138776
|
}
|
|
138771
138777
|
});
|
|
@@ -139685,6 +139691,53 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
|
|
|
139685
139691
|
});
|
|
139686
139692
|
};
|
|
139687
139693
|
const handleImport = async (records) => {
|
|
139694
|
+
console.log(`[LO Manager] handleImport called with ${records.length} raw records.`);
|
|
139695
|
+
if (!onBulkAdd) {
|
|
139696
|
+
console.error("[LO Manager] onBulkAdd handler is not provided.");
|
|
139697
|
+
return;
|
|
139698
|
+
}
|
|
139699
|
+
const parseStringToArray = (input) => {
|
|
139700
|
+
if (Array.isArray(input)) return input;
|
|
139701
|
+
if (typeof input === "string") return input.split(",").map((s4) => s4.trim()).filter(Boolean);
|
|
139702
|
+
return [];
|
|
139703
|
+
};
|
|
139704
|
+
const validationResult = records.reduce((acc, rec) => {
|
|
139705
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
139706
|
+
acc.valid.push({
|
|
139707
|
+
code: rec.code,
|
|
139708
|
+
name: rec.name,
|
|
139709
|
+
description: rec.description || rec.name,
|
|
139710
|
+
subject: rec.subject || "",
|
|
139711
|
+
subjectCode: rec.subjectCode,
|
|
139712
|
+
category: rec.category || "",
|
|
139713
|
+
categoryCode: rec.categoryCode,
|
|
139714
|
+
topic: rec.topic || "",
|
|
139715
|
+
topicCode: rec.topicCode,
|
|
139716
|
+
grade: rec.grade || "",
|
|
139717
|
+
gradeCode: rec.gradeCode,
|
|
139718
|
+
keywords: parseStringToArray(rec.keywords),
|
|
139719
|
+
stemElements: parseStringToArray(rec.stemElements),
|
|
139720
|
+
bloomLevelsGuideline: parseStringToArray(rec.bloomLevelsGuideline)
|
|
139721
|
+
});
|
|
139722
|
+
} else {
|
|
139723
|
+
acc.invalidCount++;
|
|
139724
|
+
}
|
|
139725
|
+
return acc;
|
|
139726
|
+
}, { valid: [], invalidCount: 0 });
|
|
139727
|
+
console.log(`[LO Manager] Validation complete. ${validationResult.valid.length} valid records found.`);
|
|
139728
|
+
if (validationResult.invalidCount > 0) {
|
|
139729
|
+
toast2({
|
|
139730
|
+
title: "Import Warning",
|
|
139731
|
+
description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
|
|
139732
|
+
variant: "destructive"
|
|
139733
|
+
});
|
|
139734
|
+
}
|
|
139735
|
+
if (validationResult.valid.length > 0) {
|
|
139736
|
+
console.log("[LO Manager] Calling onBulkAdd prop with validated data...");
|
|
139737
|
+
await onBulkAdd(validationResult.valid);
|
|
139738
|
+
} else {
|
|
139739
|
+
console.log("[LO Manager] No valid records to import.");
|
|
139740
|
+
}
|
|
139688
139741
|
};
|
|
139689
139742
|
return /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Learning Objectives"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__namespace.default.createElement(MetadataImportControls, { metadataName: "Learning Objectives", onImport: handleImport }), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__namespace.default.createElement(Table3, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__namespace.default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__namespace.default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__namespace.default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__namespace.default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e3) => handleFormChange("code", e3.target.value.toUpperCase()), disabled: !!currentItem })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "name", value: formState.name || "", onChange: (e3) => handleFormChange("name", e3.target.value) }))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "subject", value: formState.subject || "", onChange: (e3) => handleFormChange("subject", e3.target.value) })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React169__namespace.default.createElement(EditableCombobox, { options: subjects.map((s4) => ({ value: s4.code, label: s4.name })), value: formState.subjectCode || "", onChange: (val) => handleFormChange("subjectCode", val), placeholder: "Select a subject..." }))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "category", value: formState.category || "", onChange: (e3) => handleFormChange("category", e3.target.value) })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "categoryCode", value: formState.categoryCode || "", onChange: (e3) => handleFormChange("categoryCode", e3.target.value) }))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "topic", value: formState.topic || "", onChange: (e3) => handleFormChange("topic", e3.target.value) })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "topicCode", value: formState.topicCode || "", onChange: (e3) => handleFormChange("topicCode", e3.target.value) }))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "grade", value: formState.grade || "", onChange: (e3) => handleFormChange("grade", e3.target.value) })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "gradeCode", value: formState.gradeCode || "", onChange: (e3) => handleFormChange("gradeCode", e3.target.value) }))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "keywords", value: formState.keywords?.join(", ") || "", onChange: (e3) => handleFormChange("keywords", e3.target.value.split(",").map((s4) => s4.trim())) })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "stemElements", value: formState.stemElements?.join(", ") || "", onChange: (e3) => handleFormChange("stemElements", e3.target.value.split(",").map((s4) => s4.trim())) })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "bloomLevelsGuideline", value: formState.bloomLevelsGuideline?.join(", ") || "", onChange: (e3) => handleFormChange("bloomLevelsGuideline", e3.target.value.split(",").map((s4) => s4.trim())) }))), /* @__PURE__ */ React169__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !formState.name?.trim() || !formState.code?.trim() }, isPending && /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
139690
139743
|
}
|
package/dist/react-ui.mjs
CHANGED
|
@@ -101851,6 +101851,7 @@ init_react_shim();
|
|
|
101851
101851
|
// src/services/TopicDataService.ts
|
|
101852
101852
|
init_react_shim();
|
|
101853
101853
|
var TopicDataService = class {
|
|
101854
|
+
// ... saveData, mergeData, getData, clearData methods remain the same ...
|
|
101854
101855
|
static saveData(data) {
|
|
101855
101856
|
try {
|
|
101856
101857
|
if (typeof window === "undefined") return;
|
|
@@ -101895,47 +101896,41 @@ var TopicDataService = class {
|
|
|
101895
101896
|
}
|
|
101896
101897
|
const headerLine = lines.shift();
|
|
101897
101898
|
const headers = headerLine.split(" ").map((h3) => h3.trim());
|
|
101898
|
-
|
|
101899
|
-
const errorMsg = `Invalid TSV header. Expected: "${this.EXPECTED_HEADERS.join(" ")}". Received: "${headers.join(" ")}"`;
|
|
101900
|
-
return { data: [], errors: [errorMsg] };
|
|
101901
|
-
}
|
|
101899
|
+
const headerMap = headers.map((h3) => this.HEADER_MAP[h3] || null);
|
|
101902
101900
|
const data = [];
|
|
101903
101901
|
const errors2 = [];
|
|
101904
101902
|
lines.forEach((line, index3) => {
|
|
101905
|
-
const values = line.split(" ")
|
|
101906
|
-
|
|
101907
|
-
|
|
101903
|
+
const values = line.split(" ");
|
|
101904
|
+
const rowObject = {};
|
|
101905
|
+
headerMap.forEach((propName, i2) => {
|
|
101906
|
+
if (propName) {
|
|
101907
|
+
const value = values[i2]?.trim() || "";
|
|
101908
|
+
if (propName === "keywords" || propName === "stemElements" || propName === "bloomLevelsGuideline") {
|
|
101909
|
+
rowObject[propName] = value.split(",").map((s4) => s4.trim()).filter(Boolean);
|
|
101910
|
+
} else {
|
|
101911
|
+
rowObject[propName] = value;
|
|
101912
|
+
}
|
|
101913
|
+
}
|
|
101914
|
+
});
|
|
101915
|
+
if (!rowObject.code) {
|
|
101916
|
+
errors2.push(`Line ${index3 + 2}: Missing required value for 'LO ID'.`);
|
|
101908
101917
|
return;
|
|
101909
101918
|
}
|
|
101910
|
-
|
|
101911
|
-
|
|
101912
|
-
name3,
|
|
101913
|
-
loDescription,
|
|
101914
|
-
subject,
|
|
101915
|
-
category,
|
|
101916
|
-
topic,
|
|
101917
|
-
keywordsStr,
|
|
101918
|
-
grade,
|
|
101919
|
-
stemElementsStr,
|
|
101920
|
-
bloomLevelsStr
|
|
101921
|
-
] = values;
|
|
101922
|
-
if (!loId || !loDescription || !subject || !category || !topic) {
|
|
101923
|
-
errors2.push(`Line ${index3 + 2}: Missing required fields (LO ID, LO Description, Subject, Category, or Topic).`);
|
|
101924
|
-
return;
|
|
101919
|
+
if (!rowObject.name) {
|
|
101920
|
+
rowObject.name = rowObject.code;
|
|
101925
101921
|
}
|
|
101926
101922
|
const learningObjective = {
|
|
101927
101923
|
id: generateUniqueId("lo_"),
|
|
101928
|
-
code:
|
|
101929
|
-
name:
|
|
101930
|
-
description:
|
|
101931
|
-
|
|
101932
|
-
|
|
101933
|
-
|
|
101934
|
-
|
|
101935
|
-
|
|
101936
|
-
|
|
101937
|
-
|
|
101938
|
-
bloomLevelsGuideline: bloomLevelsStr.split(",").map((b2) => b2.trim()).filter(Boolean)
|
|
101924
|
+
code: rowObject.code,
|
|
101925
|
+
name: rowObject.name,
|
|
101926
|
+
description: rowObject.description,
|
|
101927
|
+
subject: rowObject.subject || "",
|
|
101928
|
+
category: rowObject.category || "",
|
|
101929
|
+
topic: rowObject.topic || "",
|
|
101930
|
+
grade: rowObject.grade || "",
|
|
101931
|
+
keywords: rowObject.keywords || [],
|
|
101932
|
+
stemElements: rowObject.stemElements || [],
|
|
101933
|
+
bloomLevelsGuideline: rowObject.bloomLevelsGuideline || []
|
|
101939
101934
|
};
|
|
101940
101935
|
data.push(learningObjective);
|
|
101941
101936
|
});
|
|
@@ -101963,17 +101958,20 @@ var TopicDataService = class {
|
|
|
101963
101958
|
}
|
|
101964
101959
|
};
|
|
101965
101960
|
TopicDataService.STORAGE_KEY = "interactive_quiz_kit_learning_objectives";
|
|
101966
|
-
|
|
101967
|
-
|
|
101968
|
-
"LO
|
|
101969
|
-
"
|
|
101970
|
-
|
|
101971
|
-
"
|
|
101972
|
-
"
|
|
101973
|
-
"
|
|
101974
|
-
"
|
|
101975
|
-
"
|
|
101976
|
-
|
|
101961
|
+
// Define a map for flexible header mapping
|
|
101962
|
+
TopicDataService.HEADER_MAP = {
|
|
101963
|
+
"LO ID": "code",
|
|
101964
|
+
"LO Name": "name",
|
|
101965
|
+
// Ready for future addition
|
|
101966
|
+
"LO Description": "description",
|
|
101967
|
+
"Subject": "subject",
|
|
101968
|
+
"Category": "category",
|
|
101969
|
+
"Topic": "topic",
|
|
101970
|
+
"Keywords": "keywords",
|
|
101971
|
+
"Grade": "grade",
|
|
101972
|
+
"STEM Element(s)": "stemElements",
|
|
101973
|
+
"Bloom\u2019s Level(s) Guideline": "bloomLevelsGuideline"
|
|
101974
|
+
};
|
|
101977
101975
|
|
|
101978
101976
|
// src/ai/flows/question-gen/generate-coding-question.ts
|
|
101979
101977
|
init_react_shim();
|
|
@@ -138662,11 +138660,17 @@ function MetadataImportControls({ metadataName, onImport }) {
|
|
|
138662
138660
|
const fileInputRef = useRef(null);
|
|
138663
138661
|
const { toast: toast2 } = useToast();
|
|
138664
138662
|
const processAndImportRecords = async (records, importSource) => {
|
|
138663
|
+
console.log(`[ImportControls] Processing ${records.length} records from ${importSource} for ${metadataName}.`);
|
|
138665
138664
|
if (records.length === 0) {
|
|
138666
138665
|
toast2({ title: "No Data", description: `The selected ${importSource === "file" ? "file" : "JSON string"} contains no data to import.`, variant: "destructive" });
|
|
138667
138666
|
return;
|
|
138668
138667
|
}
|
|
138669
|
-
|
|
138668
|
+
try {
|
|
138669
|
+
await onImport(records);
|
|
138670
|
+
} catch (error) {
|
|
138671
|
+
console.error(`[ImportControls] Error during onImport callback for ${metadataName}:`, error);
|
|
138672
|
+
toast2({ title: "Import Failed", description: `An error occurred while saving the data: ${error instanceof Error ? error.message : String(error)}`, variant: "destructive" });
|
|
138673
|
+
}
|
|
138670
138674
|
setIsOpen(false);
|
|
138671
138675
|
setJsonString("");
|
|
138672
138676
|
};
|
|
@@ -138698,8 +138702,10 @@ function MetadataImportControls({ metadataName, onImport }) {
|
|
|
138698
138702
|
return record;
|
|
138699
138703
|
});
|
|
138700
138704
|
}
|
|
138705
|
+
console.log(`[ImportControls] File parsed successfully. Found ${records.length} records.`);
|
|
138701
138706
|
await processAndImportRecords(records, "file");
|
|
138702
138707
|
} catch (err) {
|
|
138708
|
+
console.error("[ImportControls] Error parsing file:", err);
|
|
138703
138709
|
toast2({ title: "Import Error", description: `Failed to process file: ${err.message}`, variant: "destructive" });
|
|
138704
138710
|
}
|
|
138705
138711
|
});
|
|
@@ -139619,6 +139625,53 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
|
|
|
139619
139625
|
});
|
|
139620
139626
|
};
|
|
139621
139627
|
const handleImport = async (records) => {
|
|
139628
|
+
console.log(`[LO Manager] handleImport called with ${records.length} raw records.`);
|
|
139629
|
+
if (!onBulkAdd) {
|
|
139630
|
+
console.error("[LO Manager] onBulkAdd handler is not provided.");
|
|
139631
|
+
return;
|
|
139632
|
+
}
|
|
139633
|
+
const parseStringToArray = (input) => {
|
|
139634
|
+
if (Array.isArray(input)) return input;
|
|
139635
|
+
if (typeof input === "string") return input.split(",").map((s4) => s4.trim()).filter(Boolean);
|
|
139636
|
+
return [];
|
|
139637
|
+
};
|
|
139638
|
+
const validationResult = records.reduce((acc, rec) => {
|
|
139639
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
139640
|
+
acc.valid.push({
|
|
139641
|
+
code: rec.code,
|
|
139642
|
+
name: rec.name,
|
|
139643
|
+
description: rec.description || rec.name,
|
|
139644
|
+
subject: rec.subject || "",
|
|
139645
|
+
subjectCode: rec.subjectCode,
|
|
139646
|
+
category: rec.category || "",
|
|
139647
|
+
categoryCode: rec.categoryCode,
|
|
139648
|
+
topic: rec.topic || "",
|
|
139649
|
+
topicCode: rec.topicCode,
|
|
139650
|
+
grade: rec.grade || "",
|
|
139651
|
+
gradeCode: rec.gradeCode,
|
|
139652
|
+
keywords: parseStringToArray(rec.keywords),
|
|
139653
|
+
stemElements: parseStringToArray(rec.stemElements),
|
|
139654
|
+
bloomLevelsGuideline: parseStringToArray(rec.bloomLevelsGuideline)
|
|
139655
|
+
});
|
|
139656
|
+
} else {
|
|
139657
|
+
acc.invalidCount++;
|
|
139658
|
+
}
|
|
139659
|
+
return acc;
|
|
139660
|
+
}, { valid: [], invalidCount: 0 });
|
|
139661
|
+
console.log(`[LO Manager] Validation complete. ${validationResult.valid.length} valid records found.`);
|
|
139662
|
+
if (validationResult.invalidCount > 0) {
|
|
139663
|
+
toast2({
|
|
139664
|
+
title: "Import Warning",
|
|
139665
|
+
description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
|
|
139666
|
+
variant: "destructive"
|
|
139667
|
+
});
|
|
139668
|
+
}
|
|
139669
|
+
if (validationResult.valid.length > 0) {
|
|
139670
|
+
console.log("[LO Manager] Calling onBulkAdd prop with validated data...");
|
|
139671
|
+
await onBulkAdd(validationResult.valid);
|
|
139672
|
+
} else {
|
|
139673
|
+
console.log("[LO Manager] No valid records to import.");
|
|
139674
|
+
}
|
|
139622
139675
|
};
|
|
139623
139676
|
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Learning Objectives"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__default.createElement(MetadataImportControls, { metadataName: "Learning Objectives", onImport: handleImport }), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e3) => handleFormChange("code", e3.target.value.toUpperCase()), disabled: !!currentItem })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React169__default.createElement(Input, { id: "name", value: formState.name || "", onChange: (e3) => handleFormChange("name", e3.target.value) }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "subject", value: formState.subject || "", onChange: (e3) => handleFormChange("subject", e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React169__default.createElement(EditableCombobox, { options: subjects.map((s4) => ({ value: s4.code, label: s4.name })), value: formState.subjectCode || "", onChange: (val) => handleFormChange("subjectCode", val), placeholder: "Select a subject..." }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "category", value: formState.category || "", onChange: (e3) => handleFormChange("category", e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "categoryCode", value: formState.categoryCode || "", onChange: (e3) => handleFormChange("categoryCode", e3.target.value) }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "topic", value: formState.topic || "", onChange: (e3) => handleFormChange("topic", e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "topicCode", value: formState.topicCode || "", onChange: (e3) => handleFormChange("topicCode", e3.target.value) }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "grade", value: formState.grade || "", onChange: (e3) => handleFormChange("grade", e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "gradeCode", value: formState.gradeCode || "", onChange: (e3) => handleFormChange("gradeCode", e3.target.value) }))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "keywords", value: formState.keywords?.join(", ") || "", onChange: (e3) => handleFormChange("keywords", e3.target.value.split(",").map((s4) => s4.trim())) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "stemElements", value: formState.stemElements?.join(", ") || "", onChange: (e3) => handleFormChange("stemElements", e3.target.value.split(",").map((s4) => s4.trim())) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "bloomLevelsGuideline", value: formState.bloomLevelsGuideline?.join(", ") || "", onChange: (e3) => handleFormChange("bloomLevelsGuideline", e3.target.value.split(",").map((s4) => s4.trim())) }))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !formState.name?.trim() || !formState.code?.trim() }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
139624
139677
|
}
|
package/package.json
CHANGED