@thanh01.pmt/interactive-quiz-kit 1.0.66 → 1.0.67
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/HEADLESS.md +1 -1
- package/README.md +2 -2
- package/dist/{ai-ecosystem-DqFRlFU3.d.cts → ai-ecosystem-DyQYZbyX.d.cts} +3 -3
- package/dist/{ai-ecosystem-DqVlSO3r.d.ts → ai-ecosystem-Qa_SdE2T.d.ts} +3 -3
- package/dist/ai.cjs +60 -96
- package/dist/ai.d.cts +127 -127
- package/dist/ai.d.ts +127 -127
- package/dist/ai.mjs +60 -96
- package/dist/authoring.cjs +1536 -1260
- package/dist/authoring.d.cts +4 -4
- package/dist/authoring.d.ts +4 -4
- package/dist/authoring.mjs +1268 -993
- package/dist/index.cjs +22 -37
- package/dist/index.d.cts +24 -27
- package/dist/index.d.ts +24 -27
- package/dist/index.mjs +22 -37
- package/dist/player.cjs +9 -9
- package/dist/player.d.cts +1 -1
- package/dist/player.d.ts +1 -1
- package/dist/player.mjs +9 -9
- package/dist/{quiz-config-o4j2dfsu.d.cts → quiz-config-CwaP-pBs.d.cts} +1 -1
- package/dist/{quiz-config-o4j2dfsu.d.ts → quiz-config-CwaP-pBs.d.ts} +1 -1
- package/dist/react-ui.cjs +504 -244
- package/dist/react-ui.d.cts +6 -6
- package/dist/react-ui.d.ts +6 -6
- package/dist/react-ui.mjs +504 -245
- package/dist/{toaster-CKS4zoRY.d.cts → toaster-BVaUJA6E.d.ts} +65 -45
- package/dist/{toaster-DLJ_2W9u.d.ts → toaster-BWaJj0l-.d.cts} +65 -45
- package/package.json +1 -1
package/dist/react-ui.cjs
CHANGED
|
@@ -9085,7 +9085,7 @@ var translation_default = {
|
|
|
9085
9085
|
subject: "Subject",
|
|
9086
9086
|
category: "Category",
|
|
9087
9087
|
topic: "Topic",
|
|
9088
|
-
|
|
9088
|
+
code: "LO ID"
|
|
9089
9089
|
},
|
|
9090
9090
|
confirmModal: {
|
|
9091
9091
|
title: "Confirm Data Import",
|
|
@@ -9500,7 +9500,7 @@ var translation_default2 = {
|
|
|
9500
9500
|
subject: "M\xF4n h\u1ECDc",
|
|
9501
9501
|
category: "Danh m\u1EE5c",
|
|
9502
9502
|
topic: "Ch\u1EE7 \u0111\u1EC1",
|
|
9503
|
-
|
|
9503
|
+
code: "M\xE3 MTH"
|
|
9504
9504
|
},
|
|
9505
9505
|
confirmModal: {
|
|
9506
9506
|
title: "X\xE1c nh\u1EADn Nh\u1EADp D\u1EEF li\u1EC7u",
|
|
@@ -37572,7 +37572,7 @@ var cva = (base3, config3) => (props) => {
|
|
|
37572
37572
|
|
|
37573
37573
|
// src/react-ui/components/elements/label.tsx
|
|
37574
37574
|
var labelVariants = cva(
|
|
37575
|
-
"text-sm font-
|
|
37575
|
+
"text-sm font-Medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
37576
37576
|
);
|
|
37577
37577
|
var Label2 = React169__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React169__namespace.createElement(
|
|
37578
37578
|
Root3,
|
|
@@ -62810,7 +62810,7 @@ var MarkdownRenderer = ({
|
|
|
62810
62810
|
},
|
|
62811
62811
|
h1: ({ node: node2, ...props }) => /* @__PURE__ */ React169__namespace.default.createElement("h1", { ...props, className: "text-3xl font-bold mb-6 mt-8 first:mt-0" }),
|
|
62812
62812
|
h2: ({ node: node2, ...props }) => /* @__PURE__ */ React169__namespace.default.createElement("h2", { ...props, className: "text-2xl font-semibold mb-4 mt-6" }),
|
|
62813
|
-
h3: ({ node: node2, ...props }) => /* @__PURE__ */ React169__namespace.default.createElement("h3", { ...props, className: "text-xl font-
|
|
62813
|
+
h3: ({ node: node2, ...props }) => /* @__PURE__ */ React169__namespace.default.createElement("h3", { ...props, className: "text-xl font-Medium mb-3 mt-5" }),
|
|
62814
62814
|
ul: ({ node: node2, ...props }) => /* @__PURE__ */ React169__namespace.default.createElement("ul", { ...props, className: "my-4 space-y-2 list-disc list-inside" }),
|
|
62815
62815
|
ol: ({ node: node2, ...props }) => /* @__PURE__ */ React169__namespace.default.createElement("ol", { ...props, className: "my-4 space-y-2 list-decimal list-inside" }),
|
|
62816
62816
|
p: ({ node: node2, ...props }) => /* @__PURE__ */ React169__namespace.default.createElement("p", { ...props, className: "mb-4 leading-7" }),
|
|
@@ -63284,7 +63284,7 @@ var Input = React169__namespace.forwardRef(
|
|
|
63284
63284
|
{
|
|
63285
63285
|
type,
|
|
63286
63286
|
className: cn(
|
|
63287
|
-
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-
|
|
63287
|
+
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-Medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
63288
63288
|
className
|
|
63289
63289
|
),
|
|
63290
63290
|
ref,
|
|
@@ -63459,7 +63459,7 @@ init_react_shim();
|
|
|
63459
63459
|
// src/react-ui/components/elements/button.tsx
|
|
63460
63460
|
init_react_shim();
|
|
63461
63461
|
var buttonVariants = cva(
|
|
63462
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-
|
|
63462
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-Medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
63463
63463
|
{
|
|
63464
63464
|
variants: {
|
|
63465
63465
|
variant: {
|
|
@@ -68412,7 +68412,7 @@ var MatchingQuestionUI = ({
|
|
|
68412
68412
|
if (showCorrectAnswer && selectedOptionId) {
|
|
68413
68413
|
borderColor = isSelectionCorrect ? "border-green-500" : "border-destructive";
|
|
68414
68414
|
}
|
|
68415
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { key: promptItem.id, className: `p-3 border rounded-md ${borderColor} transition-colors bg-background` }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `select-prompt-${promptItem.id}`, className: "font-
|
|
68415
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { key: promptItem.id, className: `p-3 border rounded-md ${borderColor} transition-colors bg-background` }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `select-prompt-${promptItem.id}`, className: "font-Medium text-base block mb-2 whitespace-normal" }, /* @__PURE__ */ React169__namespace.default.createElement(MarkdownRenderer, { content: promptItem.content })), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
68416
68416
|
Select2,
|
|
68417
68417
|
{
|
|
68418
68418
|
value: selectedOptionId,
|
|
@@ -68467,7 +68467,7 @@ var DragAndDropQuestionUI = ({
|
|
|
68467
68467
|
} else {
|
|
68468
68468
|
itemStyle += " border-muted";
|
|
68469
68469
|
}
|
|
68470
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { key: item.id, className: itemStyle }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `select-draggable-${item.id}`, className: "font-
|
|
68470
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { key: item.id, className: itemStyle }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `select-draggable-${item.id}`, className: "font-Medium text-base mb-2 sm:mb-0 sm:mr-4 flex-1" }, /* @__PURE__ */ React169__namespace.default.createElement(MarkdownRenderer, { content: item.content })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center space-x-2 w-full sm:w-auto" }, /* @__PURE__ */ React169__namespace.default.createElement(
|
|
68471
68471
|
Select2,
|
|
68472
68472
|
{
|
|
68473
68473
|
value: selectedDropZoneId,
|
|
@@ -95483,7 +95483,7 @@ var TabsTrigger2 = React169__namespace.forwardRef(({ className, ...props }, ref)
|
|
|
95483
95483
|
{
|
|
95484
95484
|
ref,
|
|
95485
95485
|
className: cn(
|
|
95486
|
-
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-
|
|
95486
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-Medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
|
95487
95487
|
className
|
|
95488
95488
|
),
|
|
95489
95489
|
...props
|
|
@@ -96183,7 +96183,7 @@ var AccordionTrigger2 = React169__namespace.forwardRef(({ className, children, .
|
|
|
96183
96183
|
{
|
|
96184
96184
|
ref,
|
|
96185
96185
|
className: cn(
|
|
96186
|
-
"flex flex-1 items-center justify-between py-4 font-
|
|
96186
|
+
"flex flex-1 items-center justify-between py-4 font-Medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
|
|
96187
96187
|
className
|
|
96188
96188
|
),
|
|
96189
96189
|
...props
|
|
@@ -96970,7 +96970,7 @@ var QuizResult = ({
|
|
|
96970
96970
|
}
|
|
96971
96971
|
return String(answer);
|
|
96972
96972
|
};
|
|
96973
|
-
return /* @__PURE__ */ React169__namespace.default.createElement(Card, { className: "w-full max-w-3xl mx-auto shadow-xl" }, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-3xl font-headline text-center" }, t4("practiceFlow.results.title", { quizTitle })), /* @__PURE__ */ React169__namespace.default.createElement(CardDescription, { className: "text-center text-lg" }, t4("practiceFlow.results.description"))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "space-y-6" }, /* @__PURE__ */ React169__namespace.default.createElement(Card, { className: "bg-secondary/50" }, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-xl flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(BarChart2, { className: "mr-2 h-5 w-5 text-primary" }), t4("practiceFlow.results.overallScore"))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "grid grid-cols-1 md:grid-cols-3 gap-4 text-center" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-3xl font-bold text-primary" }, result.score, " / ", result.maxScore), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("practiceFlow.results.points"))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-3xl font-bold text-primary" }, result.percentage.toFixed(2), "%"), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("practiceFlow.results.percentage"))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, result.passed !== void 0 && (result.passed ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex flex-col items-center text-green-600" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleCheckBig, { className: "h-10 w-10" }), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xl font-semibold mt-1" }, t4("practiceFlow.results.passed"))) : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex flex-col items-center text-destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleX, { className: "h-10 w-10" }), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xl font-semibold mt-1" }, t4("practiceFlow.results.failed"))))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center space-x-2 p-3 bg-muted rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement(Clock, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ React169__namespace.default.createElement("span", null, t4("practiceFlow.results.timeSpent")), /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-semibold" }, result.totalTimeSpentSeconds?.toFixed(0) ?? "N/A", " ", t4("practiceFlow.results.timeUnit"))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center space-x-2 p-3 bg-muted rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement(Percent, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ React169__namespace.default.createElement("span", null, t4("practiceFlow.results.avgTimePerQuestion")), /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-semibold" }, result.averageTimePerQuestionSeconds?.toFixed(1) ?? "N/A", " ", t4("practiceFlow.results.timeUnit")))), result.scormStatus && result.scormStatus !== "idle" && result.scormStatus !== "no_api" && /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-lg" }, "SCORM Sync Status")), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: `flex items-center ${result.scormStatus === "error" ? "text-destructive" : "text-muted-foreground"}` }, result.scormStatus === "error" && /* @__PURE__ */ React169__namespace.default.createElement(TriangleAlert, { className: "mr-2 h-4 w-4" }), "Status: ", /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-semibold ml-1" }, result.scormStatus)), result.scormError && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-destructive mt-1" }, "Details: ", result.scormError))), result.webhookStatus && result.webhookStatus !== "idle" && /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-lg" }, "Webhook Sync Status")), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: `flex items-center ${result.webhookStatus === "error" ? "text-destructive" : "text-muted-foreground"}` }, result.webhookStatus === "error" && /* @__PURE__ */ React169__namespace.default.createElement(TriangleAlert, { className: "mr-2 h-4 w-4" }), "Status: ", /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-semibold ml-1" }, result.webhookStatus)), result.webhookError && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-destructive mt-1" }, "Details: ", result.webhookError))), /* @__PURE__ */ React169__namespace.default.createElement(Accordion2, { type: "single", collapsible: true, className: "w-full" }, /* @__PURE__ */ React169__namespace.default.createElement(AccordionItem2, { value: "question-breakdown" }, /* @__PURE__ */ React169__namespace.default.createElement(AccordionTrigger2, { className: "text-lg font-semibold" }, t4("practiceFlow.results.questionBreakdown")), /* @__PURE__ */ React169__namespace.default.createElement(AccordionContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-[300px] pr-4" }, /* @__PURE__ */ React169__namespace.default.createElement("ul", { className: "space-y-4" }, result.questionResults.map((qResult, index3) => /* @__PURE__ */ React169__namespace.default.createElement("li", { key: qResult.questionId, className: "p-4 border rounded-md bg-background" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-semibold" }, t4("common.questions", { count: index3 + 1 })), qResult.isCorrect ? /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "text-green-600 font-
|
|
96973
|
+
return /* @__PURE__ */ React169__namespace.default.createElement(Card, { className: "w-full max-w-3xl mx-auto shadow-xl" }, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-3xl font-headline text-center" }, t4("practiceFlow.results.title", { quizTitle })), /* @__PURE__ */ React169__namespace.default.createElement(CardDescription, { className: "text-center text-lg" }, t4("practiceFlow.results.description"))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "space-y-6" }, /* @__PURE__ */ React169__namespace.default.createElement(Card, { className: "bg-secondary/50" }, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-xl flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(BarChart2, { className: "mr-2 h-5 w-5 text-primary" }), t4("practiceFlow.results.overallScore"))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "grid grid-cols-1 md:grid-cols-3 gap-4 text-center" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-3xl font-bold text-primary" }, result.score, " / ", result.maxScore), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("practiceFlow.results.points"))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-3xl font-bold text-primary" }, result.percentage.toFixed(2), "%"), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("practiceFlow.results.percentage"))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, result.passed !== void 0 && (result.passed ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex flex-col items-center text-green-600" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleCheckBig, { className: "h-10 w-10" }), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xl font-semibold mt-1" }, t4("practiceFlow.results.passed"))) : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex flex-col items-center text-destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleX, { className: "h-10 w-10" }), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xl font-semibold mt-1" }, t4("practiceFlow.results.failed"))))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center space-x-2 p-3 bg-muted rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement(Clock, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ React169__namespace.default.createElement("span", null, t4("practiceFlow.results.timeSpent")), /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-semibold" }, result.totalTimeSpentSeconds?.toFixed(0) ?? "N/A", " ", t4("practiceFlow.results.timeUnit"))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center space-x-2 p-3 bg-muted rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement(Percent, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ React169__namespace.default.createElement("span", null, t4("practiceFlow.results.avgTimePerQuestion")), /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-semibold" }, result.averageTimePerQuestionSeconds?.toFixed(1) ?? "N/A", " ", t4("practiceFlow.results.timeUnit")))), result.scormStatus && result.scormStatus !== "idle" && result.scormStatus !== "no_api" && /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-lg" }, "SCORM Sync Status")), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: `flex items-center ${result.scormStatus === "error" ? "text-destructive" : "text-muted-foreground"}` }, result.scormStatus === "error" && /* @__PURE__ */ React169__namespace.default.createElement(TriangleAlert, { className: "mr-2 h-4 w-4" }), "Status: ", /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-semibold ml-1" }, result.scormStatus)), result.scormError && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-destructive mt-1" }, "Details: ", result.scormError))), result.webhookStatus && result.webhookStatus !== "idle" && /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-lg" }, "Webhook Sync Status")), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: `flex items-center ${result.webhookStatus === "error" ? "text-destructive" : "text-muted-foreground"}` }, result.webhookStatus === "error" && /* @__PURE__ */ React169__namespace.default.createElement(TriangleAlert, { className: "mr-2 h-4 w-4" }), "Status: ", /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-semibold ml-1" }, result.webhookStatus)), result.webhookError && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-destructive mt-1" }, "Details: ", result.webhookError))), /* @__PURE__ */ React169__namespace.default.createElement(Accordion2, { type: "single", collapsible: true, className: "w-full" }, /* @__PURE__ */ React169__namespace.default.createElement(AccordionItem2, { value: "question-breakdown" }, /* @__PURE__ */ React169__namespace.default.createElement(AccordionTrigger2, { className: "text-lg font-semibold" }, t4("practiceFlow.results.questionBreakdown")), /* @__PURE__ */ React169__namespace.default.createElement(AccordionContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-[300px] pr-4" }, /* @__PURE__ */ React169__namespace.default.createElement("ul", { className: "space-y-4" }, result.questionResults.map((qResult, index3) => /* @__PURE__ */ React169__namespace.default.createElement("li", { key: qResult.questionId, className: "p-4 border rounded-md bg-background" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-semibold" }, t4("common.questions", { count: index3 + 1 })), qResult.isCorrect ? /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "text-green-600 font-Medium flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleCheckBig, { className: "mr-1 h-4 w-4" }), " ", t4("practiceFlow.results.passed")) : /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "text-destructive font-Medium flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleX, { className: "mr-1 h-4 w-4" }), " ", t4("practiceFlow.results.failed"))), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm" }, /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-Medium" }, t4("practiceFlow.results.yourAnswer")), " ", getAnswerDisplay(qResult.userAnswer)), !qResult.isCorrect && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm" }, /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-Medium" }, t4("practiceFlow.results.correctAnswer")), " ", getAnswerDisplay(qResult.correctAnswer)), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-muted-foreground" }, /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-Medium" }, t4("practiceFlow.results.pointsEarned")), " ", qResult.pointsEarned), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-muted-foreground" }, /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-Medium" }, t4("practiceFlow.results.timeSpent")), " ", qResult.timeSpentSeconds?.toFixed(0) ?? "N/A", t4("practiceFlow.results.timeUnit")))))))))), /* @__PURE__ */ React169__namespace.default.createElement(CardFooter, { className: "flex flex-col sm:flex-row justify-between gap-2" }, onExitQuiz && /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "outline", onClick: onExitQuiz, className: "w-full sm:w-auto" }, /* @__PURE__ */ React169__namespace.default.createElement(LogOut, { className: "mr-2 h-4 w-4" }), t4("common.exit")), showReviewButton && onGenerateReview && /* @__PURE__ */ React169__namespace.default.createElement(
|
|
96974
96974
|
Button,
|
|
96975
96975
|
{
|
|
96976
96976
|
onClick: onGenerateReview,
|
|
@@ -97285,7 +97285,7 @@ var QuizDataManagement = ({ onQuizLoad, currentQuiz }) => {
|
|
|
97285
97285
|
});
|
|
97286
97286
|
}
|
|
97287
97287
|
};
|
|
97288
|
-
return /* @__PURE__ */ React169__namespace.default.createElement(Card, { className: "w-full shadow-lg" }, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, null, "Quiz Data Management"), /* @__PURE__ */ React169__namespace.default.createElement(CardDescription, null, "Import a quiz from a JSON file or export the current quiz configuration.")), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "space-y-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex flex-col gap-2 mb-4" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "quiz-file-input", className: "text-sm font-
|
|
97288
|
+
return /* @__PURE__ */ React169__namespace.default.createElement(Card, { className: "w-full shadow-lg" }, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, null, "Quiz Data Management"), /* @__PURE__ */ React169__namespace.default.createElement(CardDescription, null, "Import a quiz from a JSON file or export the current quiz configuration.")), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "space-y-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex flex-col gap-2 mb-4" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "quiz-file-input", className: "text-sm font-Medium" }, "Import Quiz (JSON)"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React169__namespace.default.createElement(
|
|
97289
97289
|
Input,
|
|
97290
97290
|
{
|
|
97291
97291
|
id: "quiz-file-input",
|
|
@@ -97293,7 +97293,7 @@ var QuizDataManagement = ({ onQuizLoad, currentQuiz }) => {
|
|
|
97293
97293
|
accept: ".json",
|
|
97294
97294
|
ref: fileInputRef,
|
|
97295
97295
|
onChange: handleFileChange,
|
|
97296
|
-
className: "w-full h-10 px-3 py-2 border border-input bg-background text-sm file:border-0 file:bg-transparent file:text-sm file:font-
|
|
97296
|
+
className: "w-full h-10 px-3 py-2 border border-input bg-background text-sm file:border-0 file:bg-transparent file:text-sm file:font-Medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
97297
97297
|
}
|
|
97298
97298
|
))), error && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-destructive flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleAlert, { className: "mr-1 h-4 w-4" }), " ", error)), /* @__PURE__ */ React169__namespace.default.createElement(CardFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleExportQuiz, disabled: !currentQuiz, variant: "outline" }, /* @__PURE__ */ React169__namespace.default.createElement(Download, { className: "mr-2 h-4 w-4" }), " Export Current Quiz")));
|
|
97299
97299
|
};
|
|
@@ -97728,6 +97728,7 @@ var Close = DialogClose;
|
|
|
97728
97728
|
|
|
97729
97729
|
// src/react-ui/components/elements/dialog.tsx
|
|
97730
97730
|
var Dialog2 = Root10;
|
|
97731
|
+
var DialogTrigger2 = Trigger4;
|
|
97731
97732
|
var DialogPortal2 = Portal3;
|
|
97732
97733
|
var DialogClose2 = Close;
|
|
97733
97734
|
var DialogOverlay2 = React169__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React169__namespace.createElement(
|
|
@@ -97926,7 +97927,7 @@ var CommandGroup = React169__namespace.forwardRef(({ className, ...props }, ref)
|
|
|
97926
97927
|
{
|
|
97927
97928
|
ref,
|
|
97928
97929
|
className: cn(
|
|
97929
|
-
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-
|
|
97930
|
+
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-Medium [&_[cmdk-group-heading]]:text-muted-foreground",
|
|
97930
97931
|
className
|
|
97931
97932
|
),
|
|
97932
97933
|
...props
|
|
@@ -98327,7 +98328,7 @@ var TrueFalseQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98327
98328
|
const handleCorrectAnswerChange = (value) => {
|
|
98328
98329
|
onFormChange({ correctAnswer: value === "true" });
|
|
98329
98330
|
};
|
|
98330
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
98331
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "True/False Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Correct Answer"), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
98331
98332
|
RadioGroup2,
|
|
98332
98333
|
{
|
|
98333
98334
|
value: question2.correctAnswer ? "true" : "false",
|
|
@@ -98364,7 +98365,7 @@ var MultipleChoiceQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98364
98365
|
const handleCorrectAnswerChange = (optionId) => {
|
|
98365
98366
|
onFormChange({ correctAnswerId: optionId });
|
|
98366
98367
|
};
|
|
98367
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
98368
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "Multiple Choice Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Options"), question2.options.length === 0 && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground mt-1" }, "No options added yet."), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
98368
98369
|
RadioGroup2,
|
|
98369
98370
|
{
|
|
98370
98371
|
value: question2.correctAnswerId,
|
|
@@ -98426,7 +98427,7 @@ var MultipleResponseQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98426
98427
|
const newCorrectAnswerIds = question2.correctAnswerIds.filter((id3) => id3 !== optionIdToDelete);
|
|
98427
98428
|
onFormChange({ options: newOptions, correctAnswerIds: newCorrectAnswerIds });
|
|
98428
98429
|
};
|
|
98429
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
98430
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "Multiple Response Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Options (Select all correct answers)"), question2.options.length === 0 && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground mt-1" }, "No options added yet."), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3 mt-2" }, question2.options.map((option, index3) => (
|
|
98430
98431
|
// *** CHANGED: Adjusted layout for SimpleMarkdownEditor ***
|
|
98431
98432
|
/* @__PURE__ */ React169__namespace.default.createElement("div", { key: option.id, className: "flex items-start space-x-2 p-2 border rounded-md bg-background hover:shadow-sm" }, /* @__PURE__ */ React169__namespace.default.createElement(
|
|
98432
98433
|
Checkbox2,
|
|
@@ -98648,7 +98649,7 @@ var ShortAnswerQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98648
98649
|
const toggleCaseSensitive = (checked) => {
|
|
98649
98650
|
onFormChange({ isCaseSensitive: checked });
|
|
98650
98651
|
};
|
|
98651
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
98652
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "Short Answer Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Accepted Answers"), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-muted-foreground" }, "Enter all valid plain text answers. The system will check against these."), question2.acceptedAnswers.length === 0 && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground mt-1" }, "No accepted answers defined yet."), question2.acceptedAnswers.map((answer, index3) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: index3, className: "flex items-center space-x-2" }, /* @__PURE__ */ React169__namespace.default.createElement(
|
|
98652
98653
|
Input,
|
|
98653
98654
|
{
|
|
98654
98655
|
type: "text",
|
|
@@ -98698,7 +98699,7 @@ var NumericQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98698
98699
|
onFormChange({ tolerance: numValue });
|
|
98699
98700
|
}
|
|
98700
98701
|
};
|
|
98701
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
98702
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "Numeric Question Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `num-answer-${question2.id}` }, "Correct Numerical Answer"), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
98702
98703
|
Input,
|
|
98703
98704
|
{
|
|
98704
98705
|
id: `num-answer-${question2.id}`,
|
|
@@ -98811,7 +98812,7 @@ var FillInTheBlanksQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98811
98812
|
const toggleCaseSensitive = (checked) => {
|
|
98812
98813
|
onFormChange({ isCaseSensitive: checked });
|
|
98813
98814
|
};
|
|
98814
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
98815
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "Fill In The Blanks Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Question Segments"), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-muted-foreground" }, "Construct the question by adding text and blank segments. The prompt in the main editor will be shown above these segments."), question2.segments.map((segment, index3) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: `segment-${index3}`, className: "flex items-start space-x-2 mt-2 p-2 border rounded-md bg-background" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex-grow space-y-1" }, /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "text-xs font-Medium capitalize text-muted-foreground" }, segment.type, " Segment ", index3 + 1), segment.type === "text" ? (
|
|
98815
98816
|
// *** CHANGED: Replaced Textarea with SimpleMarkdownEditor ***
|
|
98816
98817
|
/* @__PURE__ */ React169__namespace.default.createElement(
|
|
98817
98818
|
SimpleMarkdownEditor,
|
|
@@ -98884,7 +98885,7 @@ var SequenceQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98884
98885
|
}
|
|
98885
98886
|
return htmlString.replace(/<[^>]*>?/gm, "");
|
|
98886
98887
|
};
|
|
98887
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
98888
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "Sequence Question Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Sequence Items"), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-muted-foreground" }, "Define all items that need to be put in order. Users will arrange these."), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3 mt-2" }, question2.items.map((item, index3) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: item.id, className: "flex items-start space-x-2 p-2 border rounded-md bg-background" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex-grow" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "text-xs font-Medium text-muted-foreground" }, "Item ", index3 + 1), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
98888
98889
|
SimpleMarkdownEditor,
|
|
98889
98890
|
{
|
|
98890
98891
|
value: item.content,
|
|
@@ -98987,7 +98988,7 @@ var MatchingQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98987
98988
|
}
|
|
98988
98989
|
return htmlString.replace(/<[^>]*>?/gm, "");
|
|
98989
98990
|
};
|
|
98990
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
98991
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "Matching Question Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Prompts (Items to be matched)"), question2.prompts.map((promptItem, index3) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: promptItem.id, className: "space-y-1" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "text-xs text-muted-foreground" }, "Prompt ", index3 + 1), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => handleDeletePrompt(index3), className: "h-7 w-7 text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "h-4 w-4" }))), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
98991
98992
|
SimpleMarkdownEditor,
|
|
98992
98993
|
{
|
|
98993
98994
|
value: promptItem.content,
|
|
@@ -99077,7 +99078,7 @@ var DragAndDropQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
99077
99078
|
}
|
|
99078
99079
|
return htmlString.replace(/<[^>]*>?/gm, "");
|
|
99079
99080
|
};
|
|
99080
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
99081
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "Drag and Drop Question Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `dnd-bgimage-${question2.id}` }, "Background Image URL (Optional)"), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
99081
99082
|
Input,
|
|
99082
99083
|
{
|
|
99083
99084
|
id: `dnd-bgimage-${question2.id}`,
|
|
@@ -99164,7 +99165,7 @@ var HotspotQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
99164
99165
|
}
|
|
99165
99166
|
onFormChange({ correctHotspotIds: newCorrectIds });
|
|
99166
99167
|
};
|
|
99167
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
99168
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "Hotspot Question Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `hs-imageurl-${question2.id}` }, "Image URL"), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
99168
99169
|
Input,
|
|
99169
99170
|
{
|
|
99170
99171
|
id: `hs-imageurl-${question2.id}`,
|
|
@@ -99182,7 +99183,7 @@ var HotspotQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
99182
99183
|
onChange: (e3) => onFormChange({ imageAltText: e3.target.value || void 0 }),
|
|
99183
99184
|
placeholder: "Describe the image"
|
|
99184
99185
|
}
|
|
99185
|
-
)), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Hotspot Areas"), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-muted-foreground" }, "Define clickable areas on the image. Coordinates are relative to the image's top-left corner."), question2.hotspots.map((hotspot, index3) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: hotspot.id, className: "p-3 border rounded-md bg-background space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-
|
|
99186
|
+
)), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Hotspot Areas"), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-muted-foreground" }, "Define clickable areas on the image. Coordinates are relative to the image's top-left corner."), question2.hotspots.map((hotspot, index3) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: hotspot.id, className: "p-3 border rounded-md bg-background space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-Medium" }, "Hotspot ", index3 + 1, " (ID: ", hotspot.id, ")"), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => handleDeleteHotspot(index3), className: "h-8 w-8 text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "h-4 w-4" }))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `hs-shape-${hotspot.id}`, className: "text-xs" }, "Shape"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: hotspot.shape, onValueChange: (value) => handleHotspotChange(index3, "shape", value) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: `hs-shape-${hotspot.id}` }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "rect" }, "Rectangle"), /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "circle" }, "Circle")))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `hs-coords-${hotspot.id}`, className: "text-xs" }, hotspot.shape === "rect" ? "Coords (x, y, width, height)" : "Coords (centerX, centerY, radius)"), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
99186
99187
|
Input,
|
|
99187
99188
|
{
|
|
99188
99189
|
id: `hs-coords-${hotspot.id}`,
|
|
@@ -99214,7 +99215,7 @@ var BlocklyProgrammingQuestionForm = ({ question: question2, onFormChange }) =>
|
|
|
99214
99215
|
const handleFieldChange = (field, value) => {
|
|
99215
99216
|
onFormChange({ [field]: value });
|
|
99216
99217
|
};
|
|
99217
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
99218
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "Blockly Programming Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `blockly-toolbox-${question2.id}` }, "Toolbox Definition (XML)"), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
99218
99219
|
Textarea,
|
|
99219
99220
|
{
|
|
99220
99221
|
id: `blockly-toolbox-${question2.id}`,
|
|
@@ -99263,7 +99264,7 @@ var ScratchProgrammingQuestionForm = ({ question: question2, onFormChange }) =>
|
|
|
99263
99264
|
const handleFieldChange = (field, value) => {
|
|
99264
99265
|
onFormChange({ [field]: value });
|
|
99265
99266
|
};
|
|
99266
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
99267
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "Scratch Programming Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "scratch-toolbox-" + question2.id }, "Toolbox Definition (XML for Blockly)"), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
99267
99268
|
Textarea,
|
|
99268
99269
|
{
|
|
99269
99270
|
id: "scratch-toolbox-" + question2.id,
|
|
@@ -99340,7 +99341,7 @@ var CodingQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
99340
99341
|
const newTestCases = question2.testCases.filter((_2, i2) => i2 !== index3);
|
|
99341
99342
|
onFormChange({ testCases: newTestCases });
|
|
99342
99343
|
};
|
|
99343
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-
|
|
99344
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-Medium text-md" }, "Coding Question Specifics"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `coding-lang-${question2.id}` }, "Programming Language"), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
99344
99345
|
Select2,
|
|
99345
99346
|
{
|
|
99346
99347
|
value: question2.codingLanguage,
|
|
@@ -99366,7 +99367,7 @@ var CodingQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
99366
99367
|
placeholder: "Enter the complete, correct code solution here.",
|
|
99367
99368
|
className: "min-h-[200px] font-mono text-xs"
|
|
99368
99369
|
}
|
|
99369
|
-
)), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Test Cases"), question2.testCases.map((tc, index3) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: tc.id, className: "p-3 border rounded-md bg-background space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-
|
|
99370
|
+
)), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Test Cases"), question2.testCases.map((tc, index3) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: tc.id, className: "p-3 border rounded-md bg-background space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-Medium" }, "Test Case ", index3 + 1), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => handleDeleteTestCase(index3), className: "h-8 w-8 text-destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "h-4 w-4" }))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `tc-input-${tc.id}`, className: "text-xs" }, "Input (JSON Array)"), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
99370
99371
|
Input,
|
|
99371
99372
|
{
|
|
99372
99373
|
id: `tc-input-${tc.id}`,
|
|
@@ -99534,7 +99535,7 @@ var EditQuestionModal = ({
|
|
|
99534
99535
|
if (!isOpen || !editedQuestion) return null;
|
|
99535
99536
|
return /* @__PURE__ */ React169__namespace.default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => {
|
|
99536
99537
|
if (!open) onClose();
|
|
99537
|
-
} }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-[600px] md:max-w-[800px] lg:max-w-[1000px] max-h-[90vh]" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, { className: "font-headline text-2xl" }, questionData?.id && !questionData.id.startsWith("new_") && !questionData.id.startsWith("temp_") ? "Edit Question" : "Add New Question"), /* @__PURE__ */ React169__namespace.default.createElement(DialogDescription2, null, "Configure the details for this question. Current type:", " ", /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-semibold" }, editedQuestion.questionType))), /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "max-h-[calc(80vh-150px)] p-1 pr-6" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "prompt", className: "font-semibold" }, "Question Prompt"), /* @__PURE__ */ React169__namespace.default.createElement(SimpleMarkdownEditor, { value: editedQuestion.prompt, onChange: (htmlContent) => handleSpecificFieldChange({ prompt: htmlContent }) })), renderSpecificForm(), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "points" }, "Points"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "points", type: "number", value: editedQuestion.points || 0, onChange: (e3) => handleSpecificFieldChange({ points: parseInt(e3.target.value, 10) || 0 }), min: "0" })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "difficulty" }, "Difficulty"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: editedQuestion.difficulty || "
|
|
99538
|
+
} }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-[600px] md:max-w-[800px] lg:max-w-[1000px] max-h-[90vh]" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, { className: "font-headline text-2xl" }, questionData?.id && !questionData.id.startsWith("new_") && !questionData.id.startsWith("temp_") ? "Edit Question" : "Add New Question"), /* @__PURE__ */ React169__namespace.default.createElement(DialogDescription2, null, "Configure the details for this question. Current type:", " ", /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-semibold" }, editedQuestion.questionType))), /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "max-h-[calc(80vh-150px)] p-1 pr-6" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6 p-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "prompt", className: "font-semibold" }, "Question Prompt"), /* @__PURE__ */ React169__namespace.default.createElement(SimpleMarkdownEditor, { value: editedQuestion.prompt, onChange: (htmlContent) => handleSpecificFieldChange({ prompt: htmlContent }) })), renderSpecificForm(), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "points" }, "Points"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "points", type: "number", value: editedQuestion.points || 0, onChange: (e3) => handleSpecificFieldChange({ points: parseInt(e3.target.value, 10) || 0 }), min: "0" })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "difficulty" }, "Difficulty"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: editedQuestion.difficulty || "Medium", onValueChange: (value) => handleSpecificFieldChange({ difficulty: value }) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "Easy" }, "Easy"), /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "Medium" }, "Medium"), /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "Hard" }, "Hard"))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "explanation" }, "Explanation (Optional)"), /* @__PURE__ */ React169__namespace.default.createElement(SimpleMarkdownEditor, { value: editedQuestion.explanation || "", onChange: (htmlContent) => handleSpecificFieldChange({ explanation: htmlContent }), minHeight: "100px" })), /* @__PURE__ */ React169__namespace.default.createElement("details", { className: "group", open: hasDropdownMetadata }, /* @__PURE__ */ React169__namespace.default.createElement("summary", { className: "cursor-pointer font-semibold text-primary hover:underline" }, "Advanced Metadata (Optional)"), renderMetadataFields()))), /* @__PURE__ */ React169__namespace.default.createElement(DialogFooter, { className: "pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "outline" }, "Cancel")), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", onClick: handleSaveClick }, /* @__PURE__ */ React169__namespace.default.createElement(Save, { className: "mr-2 h-4 w-4" }), " Save Question"))));
|
|
99538
99539
|
};
|
|
99539
99540
|
|
|
99540
99541
|
// src/react-ui/components/authoring/AIQuestionGeneratorModal.tsx
|
|
@@ -99684,12 +99685,12 @@ var QuizContextSchema = zod.z.object({
|
|
|
99684
99685
|
originalSubject: zod.z.string().optional(),
|
|
99685
99686
|
originalCategory: zod.z.string().optional(),
|
|
99686
99687
|
originalTopic: zod.z.string().optional(),
|
|
99687
|
-
|
|
99688
|
+
description: zod.z.string().optional().describe("The full description of the learning objective for deep context."),
|
|
99688
99689
|
gradeBand: zod.z.string().optional()
|
|
99689
99690
|
});
|
|
99690
99691
|
var BaseQuestionGenerationClientInputSchema = zod.z.object({
|
|
99691
99692
|
language: zod.z.string().optional().default("English"),
|
|
99692
|
-
difficulty: zod.z.enum(["
|
|
99693
|
+
difficulty: zod.z.enum(["Easy", "Medium", "Hard"]),
|
|
99693
99694
|
quizContext: QuizContextSchema.optional(),
|
|
99694
99695
|
imageUrl: zod.z.string().url().optional().describe("Optional URL of an image to be used as context.")
|
|
99695
99696
|
});
|
|
@@ -99698,7 +99699,7 @@ var BaseQuestionZodSchema = zod.z.object({
|
|
|
99698
99699
|
prompt: zod.z.string().min(1),
|
|
99699
99700
|
points: zod.z.number().min(0).optional(),
|
|
99700
99701
|
explanation: zod.z.string().optional(),
|
|
99701
|
-
difficulty: zod.z.enum(["
|
|
99702
|
+
difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
99702
99703
|
topic: zod.z.string().optional(),
|
|
99703
99704
|
category: zod.z.string().optional(),
|
|
99704
99705
|
subject: zod.z.string().optional(),
|
|
@@ -99794,7 +99795,7 @@ var AITrueFalseOutputFieldsSchema = zod.z.object({
|
|
|
99794
99795
|
correctAnswer: zod.z.boolean(),
|
|
99795
99796
|
explanation: zod.z.string().optional().describe("An explanation of why the statement is true or false, especially important if false."),
|
|
99796
99797
|
points: zod.z.number().optional().default(10),
|
|
99797
|
-
difficulty: zod.z.enum(["
|
|
99798
|
+
difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
99798
99799
|
topic: zod.z.string().optional(),
|
|
99799
99800
|
verifiedCategory: zod.z.string().optional()
|
|
99800
99801
|
// Thêm để xác thực
|
|
@@ -99815,7 +99816,7 @@ Previous attempts failed. Ensure the JSON is valid and 'correctAnswer' is a bool
|
|
|
99815
99816
|
const misconceptionGuidance = quizContext?.targetMisconception ? `**Target Misconception:** The statement you create MUST be FALSE and based on this common mistake: "${quizContext.targetMisconception}"` : "";
|
|
99816
99817
|
const contextStrings = [
|
|
99817
99818
|
`**Required Category:** ${category}`,
|
|
99818
|
-
quizContext?.
|
|
99819
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
99819
99820
|
imageContextInstruction,
|
|
99820
99821
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
99821
99822
|
misconceptionGuidance,
|
|
@@ -99826,7 +99827,7 @@ Previous attempts failed. Ensure the JSON is valid and 'correctAnswer' is a bool
|
|
|
99826
99827
|
correctAnswer: true,
|
|
99827
99828
|
explanation: "Optional values in Swift represent the presence or absence of a value. To access the value when it exists, you must unwrap it using methods like 'if let', 'guard let', or the force unwrap operator '!'.",
|
|
99828
99829
|
points: 10,
|
|
99829
|
-
difficulty: "
|
|
99830
|
+
difficulty: "Easy",
|
|
99830
99831
|
topic: "Swift Optionals",
|
|
99831
99832
|
verifiedCategory: category
|
|
99832
99833
|
}, null, 2);
|
|
@@ -99962,7 +99963,7 @@ var AIMCQOutputFieldsSchema = zod.z.object({
|
|
|
99962
99963
|
correctTempOptionId: zod.z.string().describe("The temporary ID of the correct option from the generated options array."),
|
|
99963
99964
|
explanation: zod.z.string().optional().describe("A brief explanation of why the answer is correct."),
|
|
99964
99965
|
points: zod.z.number().optional().default(10),
|
|
99965
|
-
difficulty: zod.z.enum(["
|
|
99966
|
+
difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
99966
99967
|
topic: zod.z.string().optional(),
|
|
99967
99968
|
verifiedCategory: zod.z.string().optional().describe("The category this question actually addresses.")
|
|
99968
99969
|
});
|
|
@@ -99981,7 +99982,7 @@ Previous attempts failed...
|
|
|
99981
99982
|
const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The question and options must be directly related to the content of this image.` : "";
|
|
99982
99983
|
const contextStrings = [
|
|
99983
99984
|
`**Required Category:** ${category}`,
|
|
99984
|
-
quizContext?.
|
|
99985
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
99985
99986
|
imageContextInstruction,
|
|
99986
99987
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
99987
99988
|
quizContext?.targetMisconception && `**Target Misconception:** Use this to create plausible incorrect answers: "${quizContext.targetMisconception}"`,
|
|
@@ -99998,7 +99999,7 @@ Previous attempts failed...
|
|
|
99998
99999
|
correctTempOptionId: "C",
|
|
99999
100000
|
explanation: `The 'guard' statement in ${category} provides an early exit from a scope (like a function) if a condition is false, enhancing code readability by handling required conditions upfront.`,
|
|
100000
100001
|
points: 10,
|
|
100001
|
-
difficulty: "
|
|
100002
|
+
difficulty: "Easy",
|
|
100002
100003
|
topic: `Control Flow in ${category}`,
|
|
100003
100004
|
verifiedCategory: category
|
|
100004
100005
|
}, null, 2);
|
|
@@ -100146,7 +100147,7 @@ var AIMRQOutputFieldsSchema = zod.z.object({
|
|
|
100146
100147
|
correctTempOptionIds: zod.z.array(zod.z.string()).min(1),
|
|
100147
100148
|
explanation: zod.z.string().optional(),
|
|
100148
100149
|
points: zod.z.number().optional().default(10),
|
|
100149
|
-
difficulty: zod.z.enum(["
|
|
100150
|
+
difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
100150
100151
|
topic: zod.z.string().optional(),
|
|
100151
100152
|
verifiedCategory: zod.z.string().optional().describe("The category this question actually addresses.")
|
|
100152
100153
|
});
|
|
@@ -100165,7 +100166,7 @@ Previous attempts failed due to validation errors. Pay close attention to the nu
|
|
|
100165
100166
|
const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The question and options must be directly related to the content of this image.` : "";
|
|
100166
100167
|
const contextStrings = [
|
|
100167
100168
|
`**Required Category:** ${category} (This is the ONLY language to be used)`,
|
|
100168
|
-
quizContext?.
|
|
100169
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
100169
100170
|
imageContextInstruction,
|
|
100170
100171
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
100171
100172
|
quizContext?.targetMisconception && `**Target Misconception:** Use this to create plausible incorrect answers (distractors). The misconception is: "${quizContext.targetMisconception}"`,
|
|
@@ -100183,7 +100184,7 @@ Previous attempts failed due to validation errors. Pay close attention to the nu
|
|
|
100183
100184
|
correctTempOptionIds: ["A", "C", "D"],
|
|
100184
100185
|
explanation: "Object-Oriented, Functional, and Procedural are all major programming paradigms. Assembly is a low-level language, and Middleware is a type of software, not a paradigm.",
|
|
100185
100186
|
points: 10,
|
|
100186
|
-
difficulty: "
|
|
100187
|
+
difficulty: "Medium",
|
|
100187
100188
|
topic: "Programming Paradigms",
|
|
100188
100189
|
verifiedCategory: category
|
|
100189
100190
|
}, null, 2);
|
|
@@ -100347,7 +100348,7 @@ var AIShortAnswerOutputFieldsSchema = zod.z.object({
|
|
|
100347
100348
|
// isCaseSensitive không cần thiết ở đây, chúng ta sẽ quản lý nó ở phía client
|
|
100348
100349
|
explanation: zod.z.string().optional(),
|
|
100349
100350
|
points: zod.z.number().optional().default(10),
|
|
100350
|
-
difficulty: zod.z.enum(["
|
|
100351
|
+
difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
100351
100352
|
topic: zod.z.string().optional(),
|
|
100352
100353
|
verifiedCategory: zod.z.string().optional()
|
|
100353
100354
|
// Thêm để xác thực
|
|
@@ -100367,7 +100368,7 @@ Previous attempts failed. Ensure 'acceptedAnswers' is a non-empty array of strin
|
|
|
100367
100368
|
const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The question and its short answer must be directly related to the content of this image.` : "";
|
|
100368
100369
|
const contextStrings = [
|
|
100369
100370
|
`**Required Category:** ${category}`,
|
|
100370
|
-
quizContext?.
|
|
100371
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
100371
100372
|
imageContextInstruction,
|
|
100372
100373
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
100373
100374
|
quizContext?.targetMisconception && `**Target Misconception:** The question should require an answer that corrects this specific misconception: "${quizContext.targetMisconception}"`
|
|
@@ -100377,7 +100378,7 @@ Previous attempts failed. Ensure 'acceptedAnswers' is a non-empty array of strin
|
|
|
100377
100378
|
acceptedAnswers: ["let"],
|
|
100378
100379
|
explanation: "The 'let' keyword is used to declare constants, which are values that cannot be changed after they are set. 'var' is used for variables.",
|
|
100379
100380
|
points: 10,
|
|
100380
|
-
difficulty: "
|
|
100381
|
+
difficulty: "Easy",
|
|
100381
100382
|
topic: "Swift Constants",
|
|
100382
100383
|
verifiedCategory: category
|
|
100383
100384
|
}, null, 2);
|
|
@@ -100510,7 +100511,7 @@ var AINumericOutputFieldsSchema = zod.z.object({
|
|
|
100510
100511
|
tolerance: zod.z.number().min(0).optional(),
|
|
100511
100512
|
explanation: zod.z.string().optional(),
|
|
100512
100513
|
points: zod.z.number().optional().default(10),
|
|
100513
|
-
difficulty: zod.z.enum(["
|
|
100514
|
+
difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
100514
100515
|
topic: zod.z.string().optional(),
|
|
100515
100516
|
verifiedCategory: zod.z.string().optional()
|
|
100516
100517
|
// Thêm để xác thực
|
|
@@ -100530,7 +100531,7 @@ Previous attempts failed. Ensure the 'answer' is a valid number and fits within
|
|
|
100530
100531
|
const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The question and its numerical answer must be directly related to the content of this image.` : "";
|
|
100531
100532
|
const contextStrings = [
|
|
100532
100533
|
`**Required Category:** ${category}`,
|
|
100533
|
-
quizContext?.
|
|
100534
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
100534
100535
|
imageContextInstruction,
|
|
100535
100536
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
100536
100537
|
quizContext?.targetMisconception && `**Target Misconception:** The question should clarify this numerical error: "${quizContext.targetMisconception}"`
|
|
@@ -100546,7 +100547,7 @@ Previous attempts failed. Ensure the 'answer' is a valid number and fits within
|
|
|
100546
100547
|
tolerance: 0,
|
|
100547
100548
|
explanation: "An Int8 uses 8 bits. One bit is for the sign, leaving 7 bits for the value. The range is from -128 to 127 (2^7 - 1).",
|
|
100548
100549
|
points: 10,
|
|
100549
|
-
difficulty: "
|
|
100550
|
+
difficulty: "Medium",
|
|
100550
100551
|
topic: "Swift Data Types",
|
|
100551
100552
|
verifiedCategory: category
|
|
100552
100553
|
}, null, 2);
|
|
@@ -100696,7 +100697,7 @@ var AIFillInTheBlanksOutputFieldsSchema = zod.z.object({
|
|
|
100696
100697
|
})).min(1).describe("An array of text and blank segments representing the question."),
|
|
100697
100698
|
explanation: zod.z.string().optional(),
|
|
100698
100699
|
points: zod.z.number().optional().default(10),
|
|
100699
|
-
difficulty: zod.z.enum(["
|
|
100700
|
+
difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
100700
100701
|
topic: zod.z.string().optional(),
|
|
100701
100702
|
verifiedCategory: zod.z.string().optional()
|
|
100702
100703
|
// Thêm để xác thực
|
|
@@ -100716,7 +100717,7 @@ Previous attempts failed. Pay strict attention to the JSON schema, especially th
|
|
|
100716
100717
|
const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The question and blanks must be directly related to the content of this image.` : "";
|
|
100717
100718
|
const contextStrings = [
|
|
100718
100719
|
`**Required Category:** ${category}`,
|
|
100719
|
-
quizContext?.
|
|
100720
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
100720
100721
|
imageContextInstruction,
|
|
100721
100722
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
100722
100723
|
quizContext?.targetMisconception && `**Target Misconception:** Design the blank to test this specific point: "${quizContext.targetMisconception}"`
|
|
@@ -100730,7 +100731,7 @@ Previous attempts failed. Pay strict attention to the JSON schema, especially th
|
|
|
100730
100731
|
],
|
|
100731
100732
|
explanation: "The 'func' keyword is used to declare a function in the Swift programming language.",
|
|
100732
100733
|
points: 10,
|
|
100733
|
-
difficulty: "
|
|
100734
|
+
difficulty: "Easy",
|
|
100734
100735
|
topic: "Swift Function Declaration",
|
|
100735
100736
|
verifiedCategory: category
|
|
100736
100737
|
}, null, 2);
|
|
@@ -100884,7 +100885,7 @@ var AISequenceOutputFieldsSchema = zod.z.object({
|
|
|
100884
100885
|
itemsInCorrectOrder: zod.z.array(zod.z.string().min(1)).min(2).describe("An array of strings, with each string representing an item to be sequenced. The array itself MUST be in the correct final order."),
|
|
100885
100886
|
explanation: zod.z.string().optional(),
|
|
100886
100887
|
points: zod.z.number().optional().default(10),
|
|
100887
|
-
difficulty: zod.z.enum(["
|
|
100888
|
+
difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
100888
100889
|
topic: zod.z.string().optional(),
|
|
100889
100890
|
verifiedCategory: zod.z.string().optional()
|
|
100890
100891
|
// Thêm để xác thực
|
|
@@ -100904,7 +100905,7 @@ Previous attempts failed. Ensure the 'itemsInCorrectOrder' array has exactly the
|
|
|
100904
100905
|
const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The sequence of items must be directly related to the process or content shown in this image.` : "";
|
|
100905
100906
|
const contextStrings = [
|
|
100906
100907
|
`**Required Category:** ${category}`,
|
|
100907
|
-
quizContext?.
|
|
100908
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
100908
100909
|
imageContextInstruction,
|
|
100909
100910
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
100910
100911
|
quizContext?.targetMisconception && `**Target Misconception:** The sequence should clarify this specific process error: "${quizContext.targetMisconception}"`
|
|
@@ -100919,7 +100920,7 @@ Previous attempts failed. Ensure the 'itemsInCorrectOrder' array has exactly the
|
|
|
100919
100920
|
],
|
|
100920
100921
|
explanation: "This is the fundamental sequence for a basic data task in URLSession.",
|
|
100921
100922
|
points: 10,
|
|
100922
|
-
difficulty: "
|
|
100923
|
+
difficulty: "Medium",
|
|
100923
100924
|
topic: "Swift Networking",
|
|
100924
100925
|
verifiedCategory: category
|
|
100925
100926
|
}, null, 2);
|
|
@@ -101061,7 +101062,7 @@ var AIMatchingOutputFieldsSchema = zod.z.object({
|
|
|
101061
101062
|
})).min(2),
|
|
101062
101063
|
explanation: zod.z.string().optional(),
|
|
101063
101064
|
points: zod.z.number().optional().default(10),
|
|
101064
|
-
difficulty: zod.z.enum(["
|
|
101065
|
+
difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
101065
101066
|
topic: zod.z.string().optional(),
|
|
101066
101067
|
verifiedCategory: zod.z.string().optional()
|
|
101067
101068
|
// Thêm để xác thực
|
|
@@ -101081,7 +101082,7 @@ Previous attempts failed. Please ensure the 'correctPairs' array has exactly the
|
|
|
101081
101082
|
const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The matching pairs must be directly related to the content of this image.` : "";
|
|
101082
101083
|
const contextStrings = [
|
|
101083
101084
|
`**Required Category:** ${category}`,
|
|
101084
|
-
quizContext?.
|
|
101085
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
101085
101086
|
imageContextInstruction,
|
|
101086
101087
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
101087
101088
|
quizContext?.targetMisconception && `**Target Misconception:** Design a pair that specifically tests this confusion: "${quizContext.targetMisconception}"`
|
|
@@ -101095,7 +101096,7 @@ Previous attempts failed. Please ensure the 'correctPairs' array has exactly the
|
|
|
101095
101096
|
],
|
|
101096
101097
|
explanation: "These are the fundamental characteristics of Swift's main collection types.",
|
|
101097
101098
|
points: 10,
|
|
101098
|
-
difficulty: "
|
|
101099
|
+
difficulty: "Easy",
|
|
101099
101100
|
topic: "Swift Collection Types",
|
|
101100
101101
|
verifiedCategory: category
|
|
101101
101102
|
}, null, 2);
|
|
@@ -101311,7 +101312,7 @@ var AIQuestionGeneratorModal = ({
|
|
|
101311
101312
|
};
|
|
101312
101313
|
const baseClientInput = {
|
|
101313
101314
|
language: language3,
|
|
101314
|
-
difficulty: "
|
|
101315
|
+
difficulty: "Medium",
|
|
101315
101316
|
quizContext
|
|
101316
101317
|
};
|
|
101317
101318
|
let generatedResult = {};
|
|
@@ -101916,10 +101917,6 @@ init_react_shim();
|
|
|
101916
101917
|
// src/services/TopicDataService.ts
|
|
101917
101918
|
init_react_shim();
|
|
101918
101919
|
var TopicDataService = class {
|
|
101919
|
-
/**
|
|
101920
|
-
* Saves an array of LearningObjective objects to Local Storage, overwriting existing data.
|
|
101921
|
-
* @param data The array of learning objectives to save.
|
|
101922
|
-
*/
|
|
101923
101920
|
static saveData(data) {
|
|
101924
101921
|
try {
|
|
101925
101922
|
if (typeof window === "undefined") return;
|
|
@@ -101929,24 +101926,15 @@ var TopicDataService = class {
|
|
|
101929
101926
|
console.error("Error saving learning objectives to Local Storage:", error);
|
|
101930
101927
|
}
|
|
101931
101928
|
}
|
|
101932
|
-
/**
|
|
101933
|
-
* Merges a new set of learning objectives with the existing data in Local Storage.
|
|
101934
|
-
* If an LO ID from newData already exists, it will be updated. Otherwise, it will be added.
|
|
101935
|
-
* @param newData The array of new or updated learning objectives.
|
|
101936
|
-
*/
|
|
101937
101929
|
static mergeData(newData) {
|
|
101938
101930
|
const existingData = this.getData();
|
|
101939
|
-
const loMap = new Map(existingData.map((lo) => [lo.
|
|
101931
|
+
const loMap = new Map(existingData.map((lo) => [lo.code, lo]));
|
|
101940
101932
|
newData.forEach((newLo) => {
|
|
101941
|
-
loMap.set(newLo.
|
|
101933
|
+
loMap.set(newLo.code, newLo);
|
|
101942
101934
|
});
|
|
101943
101935
|
const mergedData = Array.from(loMap.values());
|
|
101944
101936
|
this.saveData(mergedData);
|
|
101945
101937
|
}
|
|
101946
|
-
/**
|
|
101947
|
-
* Retrieves the array of LearningObjective objects from Local Storage.
|
|
101948
|
-
* @returns An array of learning objectives, or an empty array if none are found or an error occurs.
|
|
101949
|
-
*/
|
|
101950
101938
|
static getData() {
|
|
101951
101939
|
try {
|
|
101952
101940
|
if (typeof window === "undefined") return [];
|
|
@@ -101958,9 +101946,6 @@ var TopicDataService = class {
|
|
|
101958
101946
|
return [];
|
|
101959
101947
|
}
|
|
101960
101948
|
}
|
|
101961
|
-
/**
|
|
101962
|
-
* Removes all learning objective data from Local Storage.
|
|
101963
|
-
*/
|
|
101964
101949
|
static clearData() {
|
|
101965
101950
|
try {
|
|
101966
101951
|
if (typeof window === "undefined") return;
|
|
@@ -101969,11 +101954,6 @@ var TopicDataService = class {
|
|
|
101969
101954
|
console.error("Error clearing learning objectives from Local Storage:", error);
|
|
101970
101955
|
}
|
|
101971
101956
|
}
|
|
101972
|
-
/**
|
|
101973
|
-
* Parses TSV content into an array of LearningObjective objects.
|
|
101974
|
-
* @param tsvContent The raw string content from a .tsv file.
|
|
101975
|
-
* @returns An object containing the successfully parsed data and any errors encountered.
|
|
101976
|
-
*/
|
|
101977
101957
|
static parseTSV(tsvContent) {
|
|
101978
101958
|
const lines = tsvContent.split("\n").filter((line) => line.trim() !== "");
|
|
101979
101959
|
if (lines.length < 2) {
|
|
@@ -101995,6 +101975,7 @@ var TopicDataService = class {
|
|
|
101995
101975
|
}
|
|
101996
101976
|
const [
|
|
101997
101977
|
loId,
|
|
101978
|
+
name3,
|
|
101998
101979
|
loDescription,
|
|
101999
101980
|
subject,
|
|
102000
101981
|
category,
|
|
@@ -102004,18 +101985,21 @@ var TopicDataService = class {
|
|
|
102004
101985
|
stemElementsStr,
|
|
102005
101986
|
bloomLevelsStr
|
|
102006
101987
|
] = values;
|
|
102007
|
-
if (!loId || !subject || !category || !topic) {
|
|
102008
|
-
errors2.push(`Line ${index3 + 2}: Missing required fields (LO ID, Subject, Category, or Topic).`);
|
|
101988
|
+
if (!loId || !loDescription || !subject || !category || !topic) {
|
|
101989
|
+
errors2.push(`Line ${index3 + 2}: Missing required fields (LO ID, LO Description, Subject, Category, or Topic).`);
|
|
102009
101990
|
return;
|
|
102010
101991
|
}
|
|
102011
101992
|
const learningObjective = {
|
|
102012
|
-
|
|
102013
|
-
|
|
101993
|
+
id: generateUniqueId("lo_"),
|
|
101994
|
+
code: loId,
|
|
101995
|
+
name: name3,
|
|
101996
|
+
description: loDescription,
|
|
101997
|
+
// Can be the same as name or enhanced later
|
|
102014
101998
|
subject,
|
|
102015
101999
|
category,
|
|
102016
102000
|
topic,
|
|
102017
|
-
keywords: keywordsStr.split(",").map((k3) => k3.trim()).filter(Boolean),
|
|
102018
102001
|
grade,
|
|
102002
|
+
keywords: keywordsStr.split(",").map((k3) => k3.trim()).filter(Boolean),
|
|
102019
102003
|
stemElements: stemElementsStr.split(",").map((s4) => s4.trim()).filter(Boolean),
|
|
102020
102004
|
bloomLevelsGuideline: bloomLevelsStr.split(",").map((b2) => b2.trim()).filter(Boolean)
|
|
102021
102005
|
};
|
|
@@ -102023,40 +102007,21 @@ var TopicDataService = class {
|
|
|
102023
102007
|
});
|
|
102024
102008
|
return { data, errors: errors2 };
|
|
102025
102009
|
}
|
|
102026
|
-
/**
|
|
102027
|
-
* Gets a unique list of all subjects from the stored data.
|
|
102028
|
-
* @returns An array of subject strings.
|
|
102029
|
-
*/
|
|
102030
102010
|
static getSubjects() {
|
|
102031
102011
|
const data = this.getData();
|
|
102032
102012
|
const subjects = data.map((item) => item.subject);
|
|
102033
102013
|
return [...new Set(subjects)].sort();
|
|
102034
102014
|
}
|
|
102035
|
-
/**
|
|
102036
|
-
* Gets a unique list of categories for a given subject.
|
|
102037
|
-
* @param subject The subject to filter by.
|
|
102038
|
-
* @returns An array of category strings.
|
|
102039
|
-
*/
|
|
102040
102015
|
static getCategoriesBySubject(subject) {
|
|
102041
102016
|
const data = this.getData();
|
|
102042
102017
|
const categories = data.filter((item) => item.subject === subject).map((item) => item.category);
|
|
102043
102018
|
return [...new Set(categories)].sort();
|
|
102044
102019
|
}
|
|
102045
|
-
/**
|
|
102046
|
-
* Gets a unique list of topics for a given category.
|
|
102047
|
-
* @param category The category to filter by.
|
|
102048
|
-
* @returns An array of topic strings.
|
|
102049
|
-
*/
|
|
102050
102020
|
static getTopicsByCategory(category) {
|
|
102051
102021
|
const data = this.getData();
|
|
102052
102022
|
const topics = data.filter((item) => item.category === category).map((item) => item.topic);
|
|
102053
102023
|
return [...new Set(topics)].sort();
|
|
102054
102024
|
}
|
|
102055
|
-
/**
|
|
102056
|
-
* Retrieves all LearningObjective details for a given list of topics.
|
|
102057
|
-
* @param topics An array of topic strings to search for.
|
|
102058
|
-
* @returns An array of matching LearningObjective objects.
|
|
102059
|
-
*/
|
|
102060
102025
|
static getLearningObjectivesByTopics(topics) {
|
|
102061
102026
|
const data = this.getData();
|
|
102062
102027
|
const topicSet = new Set(topics);
|
|
@@ -102113,7 +102078,7 @@ Previous attempts failed. Pay strict attention to the JSON schema and all rules.
|
|
|
102113
102078
|
const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The coding problem must be directly related to processing or interpreting the content of this image.` : "";
|
|
102114
102079
|
const contextStrings = [
|
|
102115
102080
|
`**Subject:** ${subject}`,
|
|
102116
|
-
quizContext?.
|
|
102081
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
102117
102082
|
imageContextInstruction,
|
|
102118
102083
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
102119
102084
|
quizContext?.targetMisconception && `**Target Misconception:** The problem should test against this common error: "${quizContext.targetMisconception}"`
|
|
@@ -102270,9 +102235,9 @@ var calculateCombinedDifficulty = (plannedQ) => {
|
|
|
102270
102235
|
break;
|
|
102271
102236
|
}
|
|
102272
102237
|
const totalScore = bloomScore + contextScore + questionTypeScore;
|
|
102273
|
-
if (totalScore <= 4) return "
|
|
102274
|
-
if (totalScore <= 7) return "
|
|
102275
|
-
return "
|
|
102238
|
+
if (totalScore <= 4) return "Easy";
|
|
102239
|
+
if (totalScore <= 7) return "Medium";
|
|
102240
|
+
return "Hard";
|
|
102276
102241
|
};
|
|
102277
102242
|
async function generateQuestionsFromQuizPlan(clientInput, apiKey) {
|
|
102278
102243
|
const { quizPlan, language: language3, imageContexts } = clientInput;
|
|
@@ -102285,7 +102250,7 @@ async function generateQuestionsFromQuizPlan(clientInput, apiKey) {
|
|
|
102285
102250
|
let lastError = null;
|
|
102286
102251
|
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
102287
102252
|
try {
|
|
102288
|
-
const fullLO = plannedQ.originalLoId ? allLearningObjectives.find((lo) => lo.
|
|
102253
|
+
const fullLO = plannedQ.originalLoId ? allLearningObjectives.find((lo) => lo.code === plannedQ.originalLoId) : null;
|
|
102289
102254
|
const quizContext = {
|
|
102290
102255
|
plannedTopic: plannedQ.plannedTopic,
|
|
102291
102256
|
plannedQuestionType: plannedQ.plannedQuestionType,
|
|
@@ -102298,7 +102263,7 @@ async function generateQuestionsFromQuizPlan(clientInput, apiKey) {
|
|
|
102298
102263
|
originalSubject: plannedQ.originalSubject,
|
|
102299
102264
|
originalCategory: plannedQ.originalCategory,
|
|
102300
102265
|
originalTopic: plannedQ.originalTopic,
|
|
102301
|
-
|
|
102266
|
+
description: fullLO?.description || plannedQ.plannedTopic
|
|
102302
102267
|
};
|
|
102303
102268
|
const imageUrl = plannedQ.imageId && imageContexts ? imageContexts.find((ctx) => ctx.id === plannedQ.imageId)?.imageUrl : void 0;
|
|
102304
102269
|
const baseClientInput = {
|
|
@@ -102652,7 +102617,7 @@ var AIFullQuizGeneratorModal = ({
|
|
|
102652
102617
|
};
|
|
102653
102618
|
const renderContent3 = () => {
|
|
102654
102619
|
if (currentStage === "review") {
|
|
102655
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 py-4" }, /* @__PURE__ */ React169__namespace.default.createElement("h3", { className: "text-lg font-
|
|
102620
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 py-4" }, /* @__PURE__ */ React169__namespace.default.createElement("h3", { className: "text-lg font-Medium mb-2 text-primary flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Eye, { className: "mr-2 h-5 w-5" }), " Review & Adjust AI Generated Quiz Plan"), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground" }, "The AI has proposed the following plan. You can change question types, reorder, or remove questions before final generation. Note: 'Drag and Drop' type questions in the plan will be created as placeholders and require manual authoring of items/zones/answers."), aiGeneratedPlan && aiGeneratedPlan.length > 0 ? /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "max-h-[calc(60vh - 120px)] pr-3" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3" }, aiGeneratedPlan.map((plannedQ, index3) => /* @__PURE__ */ React169__namespace.default.createElement(Card, { key: `planned-${index3}-${plannedQ.plannedTopic.replace(/\s/g, "")}`, className: "p-3" }, /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "p-0 space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex justify-between items-start" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "font-semibold text-sm" }, "Q", index3 + 1, ": ", plannedQ.plannedTopic), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex space-x-1" }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", onClick: () => handleMovePlannedQuestion(index3, "up"), disabled: index3 === 0 }, /* @__PURE__ */ React169__namespace.default.createElement(ArrowUp, { className: "h-4 w-4" })), /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", onClick: () => handleMovePlannedQuestion(index3, "down"), disabled: index3 === aiGeneratedPlan.length - 1 }, /* @__PURE__ */ React169__namespace.default.createElement(ArrowDown, { className: "h-4 w-4" })), /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", className: "h-7 w-7 text-destructive", onClick: () => handleRemovePlannedQuestion(index3) }, /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "h-4 w-4" })))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-3 items-end" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `review-qtype-${index3}`, className: "text-xs" }, "Question Type"), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
102656
102621
|
Select2,
|
|
102657
102622
|
{
|
|
102658
102623
|
value: plannedQ.plannedQuestionType,
|
|
@@ -102681,7 +102646,7 @@ var AIFullQuizGeneratorModal = ({
|
|
|
102681
102646
|
min: "1",
|
|
102682
102647
|
max: "100"
|
|
102683
102648
|
}
|
|
102684
|
-
)), /* @__PURE__ */ React169__namespace.default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement("legend", { className: "text-sm font-
|
|
102649
|
+
)), /* @__PURE__ */ React169__namespace.default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement("legend", { className: "text-sm font-Medium px-1" }, "Topic Distribution"), topics.map((topicItem, index3) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: topicItem.id, className: "flex items-center gap-2 mb-2" }, /* @__PURE__ */ React169__namespace.default.createElement(
|
|
102685
102650
|
Input,
|
|
102686
102651
|
{
|
|
102687
102652
|
type: "text",
|
|
@@ -102701,7 +102666,7 @@ var AIFullQuizGeneratorModal = ({
|
|
|
102701
102666
|
min: "0",
|
|
102702
102667
|
max: "100"
|
|
102703
102668
|
}
|
|
102704
|
-
), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => removeTopic(topicItem.id), disabled: topics.length <= 1 }, /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "h-4 w-4 text-destructive" })))), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "outline", size: "sm", onClick: addTopic }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Topic")), /* @__PURE__ */ React169__namespace.default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement("legend", { className: "text-sm font-
|
|
102669
|
+
), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => removeTopic(topicItem.id), disabled: topics.length <= 1 }, /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "h-4 w-4 text-destructive" })))), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "outline", size: "sm", onClick: addTopic }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Topic")), /* @__PURE__ */ React169__namespace.default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement("legend", { className: "text-sm font-Medium px-1" }, "Bloom Level Distribution"), bloomLevels.map((bloomItem) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: bloomItem.id, className: "flex items-center gap-2 mb-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "w-32 capitalize flex-shrink-0" }, bloomItem.level), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
102705
102670
|
Input,
|
|
102706
102671
|
{
|
|
102707
102672
|
type: "number",
|
|
@@ -102712,7 +102677,7 @@ var AIFullQuizGeneratorModal = ({
|
|
|
102712
102677
|
min: "0",
|
|
102713
102678
|
max: "100"
|
|
102714
102679
|
}
|
|
102715
|
-
)))), /* @__PURE__ */ React169__namespace.default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement("legend", { className: "text-sm font-
|
|
102680
|
+
)))), /* @__PURE__ */ React169__namespace.default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement("legend", { className: "text-sm font-Medium px-1" }, "Relevant Contexts (Optional, Select Multiple)"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-2 mt-2 max-h-40 overflow-y-auto" }, contextOptions.filter((opt) => opt.contextId !== "__none__" && opt.contextId !== "__custom__").map((opt) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: opt.contextId, className: "flex items-center space-x-2" }, /* @__PURE__ */ React169__namespace.default.createElement(
|
|
102716
102681
|
Checkbox2,
|
|
102717
102682
|
{
|
|
102718
102683
|
id: `ctx-full-${opt.contextId}`,
|
|
@@ -102734,7 +102699,7 @@ var AIFullQuizGeneratorModal = ({
|
|
|
102734
102699
|
placeholder: "Enter your specific custom context here...",
|
|
102735
102700
|
className: "min-h-[60px] mt-2 text-sm"
|
|
102736
102701
|
}
|
|
102737
|
-
)), /* @__PURE__ */ React169__namespace.default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement("legend", { className: "text-sm font-
|
|
102702
|
+
)), /* @__PURE__ */ React169__namespace.default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement("legend", { className: "text-sm font-Medium px-1" }, "Question Types to Use (Select Multiple)"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-2 mt-2 max-h-40 overflow-y-auto" }, availableQuestionTypesForFullQuiz.map((qType) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: qType.value, className: "flex items-center space-x-2" }, /* @__PURE__ */ React169__namespace.default.createElement(
|
|
102738
102703
|
Checkbox2,
|
|
102739
102704
|
{
|
|
102740
102705
|
id: `qtype-full-${qType.value}`,
|
|
@@ -103134,7 +103099,7 @@ var AlertTitle = React169__namespace.forwardRef(({ className, ...props }, ref) =
|
|
|
103134
103099
|
"h5",
|
|
103135
103100
|
{
|
|
103136
103101
|
ref,
|
|
103137
|
-
className: cn("mb-1 font-
|
|
103102
|
+
className: cn("mb-1 font-Medium leading-none tracking-tight", className),
|
|
103138
103103
|
...props
|
|
103139
103104
|
}
|
|
103140
103105
|
));
|
|
@@ -103179,7 +103144,7 @@ var BaseRawQuestionSchema = zod.z.object({
|
|
|
103179
103144
|
points: zod.z.number().optional(),
|
|
103180
103145
|
explanation: zod.z.string().optional(),
|
|
103181
103146
|
topic: zod.z.string().optional(),
|
|
103182
|
-
difficulty: zod.z.enum(["
|
|
103147
|
+
difficulty: zod.z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
103183
103148
|
bloomLevel: zod.z.string().optional()
|
|
103184
103149
|
});
|
|
103185
103150
|
var RawMCQSchema = BaseRawQuestionSchema.extend({
|
|
@@ -103532,7 +103497,7 @@ var QuizEditorService = class {
|
|
|
103532
103497
|
questionType: type,
|
|
103533
103498
|
prompt: "",
|
|
103534
103499
|
points: 10,
|
|
103535
|
-
difficulty: "
|
|
103500
|
+
difficulty: "Medium"
|
|
103536
103501
|
};
|
|
103537
103502
|
switch (type) {
|
|
103538
103503
|
case "true_false":
|
|
@@ -103759,7 +103724,7 @@ var SelectedQuestionsPanel = ({
|
|
|
103759
103724
|
},
|
|
103760
103725
|
/* @__PURE__ */ React169__namespace.default.createElement(ArrowDown, { className: "h-3 w-3" })
|
|
103761
103726
|
)),
|
|
103762
|
-
/* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "font-
|
|
103727
|
+
/* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "font-Medium text-sm leading-5 break-words" }, index3 + 1, ".", " ", q2.prompt.replace(/<[^>]*>?/gm, "").substring(0, 100) || `(${q2.questionType} - Untitled)`), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "text-xs text-muted-foreground mt-1" }, q2.questionType, " \u2022 ", q2.points || 0, " pts")),
|
|
103763
103728
|
/* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-1 flex-shrink-0" }, /* @__PURE__ */ React169__namespace.default.createElement(
|
|
103764
103729
|
Button,
|
|
103765
103730
|
{
|
|
@@ -104146,7 +104111,7 @@ var TableFooter = React169__namespace.forwardRef(({ className, ...props }, ref)
|
|
|
104146
104111
|
{
|
|
104147
104112
|
ref,
|
|
104148
104113
|
className: cn(
|
|
104149
|
-
"border-t bg-muted/50 font-
|
|
104114
|
+
"border-t bg-muted/50 font-Medium [&>tr]:last:border-b-0",
|
|
104150
104115
|
className
|
|
104151
104116
|
),
|
|
104152
104117
|
...props
|
|
@@ -104170,7 +104135,7 @@ var TableHead = React169__namespace.forwardRef(({ className, ...props }, ref) =>
|
|
|
104170
104135
|
{
|
|
104171
104136
|
ref,
|
|
104172
104137
|
className: cn(
|
|
104173
|
-
"h-12 px-4 text-left align-middle font-
|
|
104138
|
+
"h-12 px-4 text-left align-middle font-Medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
|
104174
104139
|
className
|
|
104175
104140
|
),
|
|
104176
104141
|
...props
|
|
@@ -104260,20 +104225,6 @@ var questionTypeManager = new LocalStorageManager("question_types");
|
|
|
104260
104225
|
var learningObjectiveManager = new LocalStorageManager("learning_objectives");
|
|
104261
104226
|
var contextManager = new LocalStorageManager("contexts");
|
|
104262
104227
|
var approachManager = new LocalStorageManager("approaches");
|
|
104263
|
-
function mapRawDifficultyToStandard(rawDifficulty) {
|
|
104264
|
-
switch (rawDifficulty) {
|
|
104265
|
-
case "E":
|
|
104266
|
-
case "E~M":
|
|
104267
|
-
return "easy";
|
|
104268
|
-
case "M":
|
|
104269
|
-
case "M~H":
|
|
104270
|
-
return "medium";
|
|
104271
|
-
case "H":
|
|
104272
|
-
return "hard";
|
|
104273
|
-
default:
|
|
104274
|
-
return "medium";
|
|
104275
|
-
}
|
|
104276
|
-
}
|
|
104277
104228
|
var MetadataService = class {
|
|
104278
104229
|
};
|
|
104279
104230
|
// --- Subject Services ---
|
|
@@ -104331,15 +104282,10 @@ MetadataService.deleteContext = (code4) => contextManager.delete(code4);
|
|
|
104331
104282
|
MetadataService.getApproaches = () => approachManager.getAll().sort((a4, b2) => a4.code.localeCompare(b2.code));
|
|
104332
104283
|
MetadataService.saveApproaches = (items) => approachManager.saveAll(items);
|
|
104333
104284
|
MetadataService.addApproach = (approachData) => {
|
|
104334
|
-
|
|
104335
|
-
return approachManager.add({ ...approachData, difficulty });
|
|
104285
|
+
return approachManager.add(approachData);
|
|
104336
104286
|
};
|
|
104337
104287
|
MetadataService.updateApproach = (id3, approachData) => {
|
|
104338
|
-
|
|
104339
|
-
if (approachData.rawDifficulty) {
|
|
104340
|
-
updates.difficulty = mapRawDifficultyToStandard(approachData.rawDifficulty);
|
|
104341
|
-
}
|
|
104342
|
-
return approachManager.update(id3, updates);
|
|
104288
|
+
return approachManager.update(id3, approachData);
|
|
104343
104289
|
};
|
|
104344
104290
|
MetadataService.deleteApproach = (code4) => approachManager.delete(code4);
|
|
104345
104291
|
// --- LearningObjective Services ---
|
|
@@ -104349,8 +104295,12 @@ MetadataService.getLearningObjectives = (subjectCode) => {
|
|
|
104349
104295
|
return filtered.sort((a4, b2) => a4.name.localeCompare(b2.name));
|
|
104350
104296
|
};
|
|
104351
104297
|
MetadataService.saveLearningObjectives = (items) => learningObjectiveManager.saveAll(items);
|
|
104352
|
-
MetadataService.addLearningObjective = (
|
|
104353
|
-
|
|
104298
|
+
MetadataService.addLearningObjective = (item) => {
|
|
104299
|
+
return learningObjectiveManager.add(item);
|
|
104300
|
+
};
|
|
104301
|
+
MetadataService.updateLearningObjective = (id3, updates) => {
|
|
104302
|
+
return learningObjectiveManager.update(id3, updates);
|
|
104303
|
+
};
|
|
104354
104304
|
MetadataService.deleteLearningObjective = (code4) => learningObjectiveManager.delete(code4);
|
|
104355
104305
|
|
|
104356
104306
|
// node_modules/date-fns/addDays.mjs
|
|
@@ -106250,7 +106200,7 @@ function QuestionList({
|
|
|
106250
106200
|
if (questions.length === 0) {
|
|
106251
106201
|
return /* @__PURE__ */ React169__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.");
|
|
106252
106202
|
}
|
|
106253
|
-
return /* @__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, { className: "w-[30%]" }, "Question Text"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Type"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Grade"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Bloom's"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Last Modified"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__namespace.default.createElement(TableBody, null, questions.map((question2) => /* @__PURE__ */ React169__namespace.default.createElement(TableRow, { key: question2.id }, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-
|
|
106203
|
+
return /* @__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, { className: "w-[30%]" }, "Question Text"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Type"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Grade"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Bloom's"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Last Modified"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__namespace.default.createElement(TableBody, null, questions.map((question2) => /* @__PURE__ */ React169__namespace.default.createElement(TableRow, { key: question2.id }, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-Medium max-w-xs truncate", title: question2.text }, /* @__PURE__ */ React169__namespace.default.createElement(MarkdownRenderer, { content: question2.questionConfig.prompt })), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, question2.code), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, /* @__PURE__ */ React169__namespace.default.createElement(Badge2, { variant: "secondary" }, getLookupName(question2.questionTypeCode, metadata.questionTypes))), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, getLookupName(question2.subjectCode, metadata.subjects)), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, getLookupName(question2.topicCode, metadata.topics)), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, getLookupName(question2.gradeLevelCode, metadata.gradeLevels)), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, /* @__PURE__ */ React169__namespace.default.createElement(Badge2, { variant: "outline" }, getLookupName(question2.bloomLevelCode, metadata.bloomLevels))), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, format(new Date(question2.lastModified), "MMM d, yyyy")), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "text-right" }, onView && /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => onView(question2), className: "mr-1" }, /* @__PURE__ */ React169__namespace.default.createElement(Eye, { className: "h-4 w-4" })), /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => onEdit(question2), className: "mr-1" }, /* @__PURE__ */ React169__namespace.default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => onDelete(question2), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "h-4 w-4" }))))))));
|
|
106254
106204
|
}
|
|
106255
106205
|
|
|
106256
106206
|
// src/react-ui/components/authoring/QuestionFilters.tsx
|
|
@@ -106331,7 +106281,7 @@ function QuestionFilters({
|
|
|
106331
106281
|
onChange: (e3) => setSearchTerm(e3.target.value),
|
|
106332
106282
|
className: "lg:col-span-2 xl:col-span-1"
|
|
106333
106283
|
}
|
|
106334
|
-
), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: subjectCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setSubjectCode) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Subject" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Subjects"), subjects.map((s4) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: s4.code, value: s4.code }, s4.name)))), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: topicCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setTopicCode), disabled: !subjectCode || filteredTopics.length === 0 }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Topic" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Topics"), filteredTopics.map((t4) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: t4.code, value: t4.code }, t4.name)))), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: gradeLevelCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setGradeLevelCode) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Grade Level" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Grade Levels"), gradeLevels.map((gl) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: gl.code, value: gl.code }, gl.name)))), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: bloomLevelCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setBloomLevelCode) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Bloom's Level" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Levels"), bloomLevels.map((bl) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: bl.code, value: bl.code }, bl.name)))), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: questionTypeCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setQuestionTypeCode) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Question Type" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Types"), questionTypes.map((qt) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: qt.code, value: qt.code }, qt.name)))), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: difficulty || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setDifficulty) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Difficulty" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Difficulties"), /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "
|
|
106284
|
+
), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: subjectCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setSubjectCode) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Subject" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Subjects"), subjects.map((s4) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: s4.code, value: s4.code }, s4.name)))), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: topicCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setTopicCode), disabled: !subjectCode || filteredTopics.length === 0 }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Topic" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Topics"), filteredTopics.map((t4) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: t4.code, value: t4.code }, t4.name)))), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: gradeLevelCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setGradeLevelCode) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Grade Level" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Grade Levels"), gradeLevels.map((gl) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: gl.code, value: gl.code }, gl.name)))), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: bloomLevelCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setBloomLevelCode) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Bloom's Level" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Levels"), bloomLevels.map((bl) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: bl.code, value: bl.code }, bl.name)))), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: questionTypeCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setQuestionTypeCode) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Question Type" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Types"), questionTypes.map((qt) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: qt.code, value: qt.code }, qt.name)))), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: difficulty || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setDifficulty) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Difficulty" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Difficulties"), /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "Easy" }, "Easy"), /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "Medium" }, "Medium"), /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "Hard" }, "Hard"))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex gap-2 col-span-full sm:col-span-1 xl:col-span-2 xl:col-start-6" }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleApplyFilters, className: "w-full sm:w-auto flex-grow" }, /* @__PURE__ */ React169__namespace.default.createElement(Search, { className: "mr-2 h-4 w-4" }), " Apply"), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleClearFilters, variant: "outline", className: "w-full sm:w-auto flex-grow" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleX, { className: "mr-2 h-4 w-4" }), " Clear"))));
|
|
106335
106285
|
}
|
|
106336
106286
|
|
|
106337
106287
|
// src/react-ui/components/authoring/QuestionFormDialog.tsx
|
|
@@ -106439,7 +106389,7 @@ function QuestionFormDialog({
|
|
|
106439
106389
|
};
|
|
106440
106390
|
const dialogTitle = questionToEdit ? "Edit Question Metadata" : "Create New Question";
|
|
106441
106391
|
const dialogDescription = "First, define the metadata for the question. Then, edit the question's content and logic.";
|
|
106442
|
-
return /* @__PURE__ */ React169__namespace.default.createElement(React169__namespace.default.Fragment, null, /* @__PURE__ */ React169__namespace.default.createElement(Dialog2, { open: isOpen, onOpenChange }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-xl md:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, dialogTitle), /* @__PURE__ */ React169__namespace.default.createElement(DialogDescription2, null, dialogDescription)), /* @__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", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "code" }, "Question Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "code", value: code4, onChange: (e3) => setCode(e3.target.value.toUpperCase()), placeholder: "Unique code (e.g., MATH-ALG-001)", disabled: !!questionToEdit })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "gradeLevelCode" }, "Grade Level"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: gradeLevelCode, onValueChange: setGradeLevelCode }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "gradeLevelCode" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Select Grade Level" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, gradeLevels.map((gl) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: gl.code, value: gl.code }, gl.name)))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: subjectCode, onValueChange: setSubjectCode }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "subjectCode" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Select Subject" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, subjects.map((s4) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: s4.code, value: s4.code }, s4.name))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "topicCode" }, "Topic"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: topicCode, onValueChange: setTopicCode, disabled: !subjectCode || filteredTopics.length === 0 }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "topicCode" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Select Topic" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, filteredTopics.map((t4) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: t4.code, value: t4.code }, t4.name)))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "bloomLevelCode" }, "Bloom's Level"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: bloomLevelCode, onValueChange: setBloomLevelCode }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "bloomLevelCode" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Select Bloom's Level" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, bloomLevels.map((bl) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: bl.code, value: bl.code }, bl.name))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Question Content & Logic"), questionConfig ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-3 mt-2 border rounded-md bg-muted/30 flex justify-between items-center" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "font-
|
|
106392
|
+
return /* @__PURE__ */ React169__namespace.default.createElement(React169__namespace.default.Fragment, null, /* @__PURE__ */ React169__namespace.default.createElement(Dialog2, { open: isOpen, onOpenChange }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-xl md:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, dialogTitle), /* @__PURE__ */ React169__namespace.default.createElement(DialogDescription2, null, dialogDescription)), /* @__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", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "code" }, "Question Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "code", value: code4, onChange: (e3) => setCode(e3.target.value.toUpperCase()), placeholder: "Unique code (e.g., MATH-ALG-001)", disabled: !!questionToEdit })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "gradeLevelCode" }, "Grade Level"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: gradeLevelCode, onValueChange: setGradeLevelCode }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "gradeLevelCode" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Select Grade Level" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, gradeLevels.map((gl) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: gl.code, value: gl.code }, gl.name)))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: subjectCode, onValueChange: setSubjectCode }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "subjectCode" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Select Subject" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, subjects.map((s4) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: s4.code, value: s4.code }, s4.name))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "topicCode" }, "Topic"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: topicCode, onValueChange: setTopicCode, disabled: !subjectCode || filteredTopics.length === 0 }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "topicCode" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Select Topic" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, filteredTopics.map((t4) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: t4.code, value: t4.code }, t4.name)))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "bloomLevelCode" }, "Bloom's Level"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: bloomLevelCode, onValueChange: setBloomLevelCode }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "bloomLevelCode" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Select Bloom's Level" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, bloomLevels.map((bl) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: bl.code, value: bl.code }, bl.name))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { className: "font-semibold" }, "Question Content & Logic"), questionConfig ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-3 mt-2 border rounded-md bg-muted/30 flex justify-between items-center" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "font-Medium" }, "Type: ", /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "font-normal" }, questionConfig.questionType)), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground truncate max-w-md" }, "Prompt: ", questionConfig.prompt.replace(/<[^>]*>?/gm, "") || "Not set")), /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "outline", onClick: () => handleOpenQuestionEditor() }, /* @__PURE__ */ React169__namespace.default.createElement(SquarePen, { className: "mr-2 h-4 w-4" }), " Edit Content")) : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-3 mt-2 border-dashed border-2 rounded-md text-center" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-muted-foreground mb-2" }, "No content has been created yet."), /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "default", onClick: () => handleOpenQuestionEditor("multiple_choice") }, /* @__PURE__ */ React169__namespace.default.createElement(BookCopy, { className: "mr-2 h-4 w-4" }), " Create Question Content")))), /* @__PURE__ */ React169__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "outline", onClick: () => onOpenChange(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !questionConfig }, isPending && /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save Question")))), questionConfig && /* @__PURE__ */ React169__namespace.default.createElement(
|
|
106443
106393
|
EditQuestionModal,
|
|
106444
106394
|
{
|
|
106445
106395
|
isOpen: isQuestionEditorOpen,
|
|
@@ -110757,10 +110707,10 @@ var RoadmapService = class {
|
|
|
110757
110707
|
}
|
|
110758
110708
|
return null;
|
|
110759
110709
|
}
|
|
110760
|
-
static updateRoadmapItemStatus(
|
|
110710
|
+
static updateRoadmapItemStatus(code4, isCompleted) {
|
|
110761
110711
|
const roadmap = this.getRoadmap();
|
|
110762
110712
|
if (roadmap) {
|
|
110763
|
-
const itemIndex = roadmap.items.findIndex((item) => item.
|
|
110713
|
+
const itemIndex = roadmap.items.findIndex((item) => item.code === code4);
|
|
110764
110714
|
if (itemIndex > -1) {
|
|
110765
110715
|
roadmap.items[itemIndex].isCompleted = isCompleted;
|
|
110766
110716
|
this.saveRoadmap(roadmap);
|
|
@@ -111341,7 +111291,7 @@ zod.z.object({
|
|
|
111341
111291
|
startDate: zod.z.string().describe("The start date for the analysis period in ISO format (YYYY-MM-DD)."),
|
|
111342
111292
|
endDate: zod.z.string().describe("The end date for the analysis period in ISO format (YYYY-MM-DD)."),
|
|
111343
111293
|
allAvailableTopics: zod.z.array(zod.z.object({
|
|
111344
|
-
|
|
111294
|
+
code: zod.z.string(),
|
|
111345
111295
|
subject: zod.z.string(),
|
|
111346
111296
|
category: zod.z.string(),
|
|
111347
111297
|
topic: zod.z.string()
|
|
@@ -111352,7 +111302,7 @@ var RoadmapItemSchema = zod.z.object({
|
|
|
111352
111302
|
topicName: zod.z.string(),
|
|
111353
111303
|
reason: zod.z.string(),
|
|
111354
111304
|
suggestedDifficulty: zod.z.enum(["Very Easy", "Easy", "Medium", "Hard", "Expert"]),
|
|
111355
|
-
|
|
111305
|
+
code: zod.z.string(),
|
|
111356
111306
|
isCompleted: zod.z.boolean()
|
|
111357
111307
|
});
|
|
111358
111308
|
var WeeklyRoadmapSchema = zod.z.object({
|
|
@@ -111417,7 +111367,7 @@ All topic names and loIds in your "weeklyRoadmap" output MUST be chosen directly
|
|
|
111417
111367
|
- **gamificationRemarks**: Write an encouraging message mentioning their achievements.
|
|
111418
111368
|
2. **For "weeklyRoadmap":**
|
|
111419
111369
|
- Create a 5-item roadmap for the upcoming week.
|
|
111420
|
-
- Prioritize the "areasForImprovement" you identified. For each, find the corresponding entry in "All Available Topics" and use its "topicName" and "
|
|
111370
|
+
- Prioritize the "areasForImprovement" you identified. For each, find the corresponding entry in "All Available Topics" and use its "topicName" and "code".
|
|
111421
111371
|
- If more items are needed, select related topics from "All Available Topics".
|
|
111422
111372
|
|
|
111423
111373
|
**IF Practice History IS EMPTY:**
|
|
@@ -111428,7 +111378,7 @@ All topic names and loIds in your "weeklyRoadmap" output MUST be chosen directly
|
|
|
111428
111378
|
- **gamificationRemarks**: Write a general motivational message about starting to learn.
|
|
111429
111379
|
2. **For "weeklyRoadmap":**
|
|
111430
111380
|
- Create a 5-item "starter" roadmap.
|
|
111431
|
-
- Select 5 diverse and foundational topics directly from the "All Available Topics" list. Use their exact "topicName" and "
|
|
111381
|
+
- Select 5 diverse and foundational topics directly from the "All Available Topics" list. Use their exact "topicName" and "code".
|
|
111432
111382
|
- For the "reason", explain that this is a good starting point to explore the subject.
|
|
111433
111383
|
|
|
111434
111384
|
--- END LOGIC FLOW ---
|
|
@@ -111456,7 +111406,7 @@ The 'suggestedDifficulty' field MUST ALWAYS be one of these exact English string
|
|
|
111456
111406
|
"topicName": "Topic C",
|
|
111457
111407
|
"reason": "To strengthen your understanding of this key area.",
|
|
111458
111408
|
"suggestedDifficulty": "Easy",
|
|
111459
|
-
"
|
|
111409
|
+
"code": "lo-id-for-topic-c-from-the-list",
|
|
111460
111410
|
"isCompleted": false
|
|
111461
111411
|
}
|
|
111462
111412
|
]
|
|
@@ -111718,11 +111668,11 @@ init_react_shim();
|
|
|
111718
111668
|
// src/ai/flows/assess-and-map-document-types.ts
|
|
111719
111669
|
init_react_shim();
|
|
111720
111670
|
var LearningObjectiveContextSchema = zod.z.object({
|
|
111721
|
-
|
|
111671
|
+
code: zod.z.string(),
|
|
111722
111672
|
subject: zod.z.string(),
|
|
111723
111673
|
category: zod.z.string(),
|
|
111724
111674
|
topic: zod.z.string(),
|
|
111725
|
-
|
|
111675
|
+
description: zod.z.string()
|
|
111726
111676
|
});
|
|
111727
111677
|
zod.z.object({
|
|
111728
111678
|
language: zod.z.string().default("English"),
|
|
@@ -111730,7 +111680,7 @@ zod.z.object({
|
|
|
111730
111680
|
learningObjectives: zod.z.array(LearningObjectiveContextSchema).min(1, { message: "At least one learning objective is required for mapping." })
|
|
111731
111681
|
});
|
|
111732
111682
|
var MappedLOSchema = zod.z.object({
|
|
111733
|
-
|
|
111683
|
+
code: zod.z.string().describe("The exact code from the provided learning objectives list that matches the document content."),
|
|
111734
111684
|
confidence: zod.z.number().min(0).max(100).describe("A confidence score (0-100) of how well the document maps to this LO."),
|
|
111735
111685
|
reasoning: zod.z.string().describe("A brief explanation for why this mapping is relevant.")
|
|
111736
111686
|
});
|
|
@@ -111766,7 +111716,7 @@ You are an expert curriculum analyst. Your task is to analyze a given document a
|
|
|
111766
111716
|
1. **Overall Relevance Assessment:** Read the document content and compare it against the entire list of LOs. Assign an overall "relevanceScore" from 0 (completely unrelated) to 100 (perfectly aligned with one or more LOs).
|
|
111767
111717
|
|
|
111768
111718
|
2. **Specific Mapping:** Identify which specific LOs from the list are directly addressed by the document. For each match you find, provide:
|
|
111769
|
-
- The exact "
|
|
111719
|
+
- The exact "code" of the matched LO.
|
|
111770
111720
|
- A "confidence" score (0-100) for that specific match.
|
|
111771
111721
|
- A brief "reasoning" in ${language3} explaining why the document content maps to that LO.
|
|
111772
111722
|
|
|
@@ -111781,7 +111731,7 @@ Return a single, valid JSON object in this EXACT format. Do not include any othe
|
|
|
111781
111731
|
"isFreestyleRecommended": false,
|
|
111782
111732
|
"mappedLOs": [
|
|
111783
111733
|
{
|
|
111784
|
-
"
|
|
111734
|
+
"code": "SWIFT_FUNC_01",
|
|
111785
111735
|
"confidence": 95,
|
|
111786
111736
|
"reasoning": "The document provides a detailed explanation of function syntax and default parameters, which directly aligns with this learning objective."
|
|
111787
111737
|
}
|
|
@@ -111876,7 +111826,7 @@ Return the response as a single JSON object with a key "generatedQuestions" cont
|
|
|
111876
111826
|
"correctTempOptionId": "A",
|
|
111877
111827
|
"explanation": "The document states that mitochondria are the powerhouses of the cell, responsible for cellular respiration.",
|
|
111878
111828
|
"points": 10,
|
|
111879
|
-
"difficulty": "
|
|
111829
|
+
"difficulty": "Medium",
|
|
111880
111830
|
"topic": "Cell Biology"
|
|
111881
111831
|
},
|
|
111882
111832
|
{
|
|
@@ -111885,7 +111835,7 @@ Return the response as a single JSON object with a key "generatedQuestions" cont
|
|
|
111885
111835
|
"correctAnswer": false,
|
|
111886
111836
|
"explanation": "The text specifies that the cell wall is a feature of plant cells, not animal cells.",
|
|
111887
111837
|
"points": 10,
|
|
111888
|
-
"difficulty": "
|
|
111838
|
+
"difficulty": "Easy",
|
|
111889
111839
|
"topic": "Cell Biology"
|
|
111890
111840
|
}
|
|
111891
111841
|
]
|
|
@@ -112718,7 +112668,7 @@ var QuizReview = ({
|
|
|
112718
112668
|
};
|
|
112719
112669
|
return /* @__PURE__ */ React169__namespace.default.createElement(Card, { className: "w-full max-w-4xl mx-auto shadow-xl" }, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-3xl font-headline text-center flex items-center justify-center" }, /* @__PURE__ */ React169__namespace.default.createElement(BookOpen, { className: "mr-3 h-8 w-8 text-primary" }), "AI-Powered Quiz Review"), /* @__PURE__ */ React169__namespace.default.createElement(CardDescription, { className: "text-center text-lg" }, "Let's break down your results and reinforce your learning.")), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "space-y-6" }, /* @__PURE__ */ React169__namespace.default.createElement(Card, { className: "bg-muted/30" }, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-xl flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-yellow-500" }), "Key Concepts Summary")), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, /* @__PURE__ */ React169__namespace.default.createElement(MarkdownRenderer, { content: reviewContent.overallSummary }))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("h3", { className: "text-xl font-semibold mb-2" }, "Detailed Question Analysis"), /* @__PURE__ */ React169__namespace.default.createElement(Accordion2, { type: "single", collapsible: true, className: "w-full" }, quizResult.questionResults.map((qResult, index3) => {
|
|
112720
112670
|
const aiReview = getReviewForQuestion(qResult.questionId);
|
|
112721
|
-
return /* @__PURE__ */ React169__namespace.default.createElement(AccordionItem2, { value: `item-${index3}`, key: qResult.questionId }, /* @__PURE__ */ React169__namespace.default.createElement(AccordionTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center justify-between w-full pr-2" }, /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "text-left font-
|
|
112671
|
+
return /* @__PURE__ */ React169__namespace.default.createElement(AccordionItem2, { value: `item-${index3}`, key: qResult.questionId }, /* @__PURE__ */ React169__namespace.default.createElement(AccordionTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center justify-between w-full pr-2" }, /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "text-left font-Medium" }, "Question ", index3 + 1), qResult.isCorrect ? /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "text-sm text-green-600 font-Medium flex items-center gap-1" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleCheckBig, { className: "h-4 w-4" }), " Correct") : /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "text-sm text-destructive font-Medium flex items-center gap-1" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleX, { className: "h-4 w-4" }), " Incorrect"))), /* @__PURE__ */ React169__namespace.default.createElement(AccordionContent2, { className: "space-y-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-4 border rounded-md bg-background" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "font-semibold mb-2" }, "Original Question:"), /* @__PURE__ */ React169__namespace.default.createElement(MarkdownRenderer, { content: qResult.prompt })), qResult.questionType === "coding" ? renderCodingResult(qResult) : renderStandardResult(qResult), aiReview && /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-4 border-l-4 border-primary bg-primary/10 rounded-r-md" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "font-semibold text-primary mb-2" }, "AI Tutor Explanation:"), /* @__PURE__ */ React169__namespace.default.createElement(MarkdownRenderer, { content: aiReview.explanation }))));
|
|
112722
112672
|
}))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("h3", { className: "text-xl font-semibold mb-2" }, "Topics for Further Study"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex flex-wrap gap-2" }, reviewContent.relatedTopics.map((topic, index3) => /* @__PURE__ */ React169__namespace.default.createElement(Badge2, { key: index3, variant: "secondary", className: "text-base px-3 py-1" }, topic))))), /* @__PURE__ */ React169__namespace.default.createElement(CardFooter, { className: "flex flex-col sm:flex-row justify-between gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "outline", onClick: onBackToResults, className: "w-full sm:w-auto" }, /* @__PURE__ */ React169__namespace.default.createElement(ArrowLeft, { className: "mr-2 h-4 w-4" }), "Back to Results"), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: onExit, className: "w-full sm:w-auto" }, /* @__PURE__ */ React169__namespace.default.createElement(LogOut, { className: "mr-2 h-4 w-4" }), "Finish & Exit")));
|
|
112723
112673
|
};
|
|
112724
112674
|
|
|
@@ -112765,7 +112715,7 @@ var PracticeHistoryTable = ({ history: history2, maxHeight = "400px" }) => {
|
|
|
112765
112715
|
if (percentage >= 50) return "secondary";
|
|
112766
112716
|
return "destructive";
|
|
112767
112717
|
};
|
|
112768
|
-
return /* @__PURE__ */ React169__namespace.default.createElement(React169__namespace.default.Fragment, null, /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, null, t4("history.title")), /* @__PURE__ */ React169__namespace.default.createElement(CardDescription, null, t4("history.description"))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "w-full border rounded-md", style: { height: maxHeight } }, /* @__PURE__ */ React169__namespace.default.createElement(TooltipProvider2, { delayDuration: 100 }, /* @__PURE__ */ React169__namespace.default.createElement(Table3, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHeader, { className: "sticky top-0 bg-muted z-10" }, /* @__PURE__ */ React169__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "w-[120px]" }, t4("history.headers.date")), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, t4("history.headers.topic")), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "text-right w-[80px]" }, t4("history.headers.score")), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "text-right w-[90px]" }, t4("history.headers.percentage")))), /* @__PURE__ */ React169__namespace.default.createElement(TableBody, null, history2.length > 0 ? history2.map((session) => /* @__PURE__ */ React169__namespace.default.createElement(TableRow, { key: session.id, onClick: () => handleRowClick(session), className: "cursor-pointer" }, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-
|
|
112718
|
+
return /* @__PURE__ */ React169__namespace.default.createElement(React169__namespace.default.Fragment, null, /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, null, t4("history.title")), /* @__PURE__ */ React169__namespace.default.createElement(CardDescription, null, t4("history.description"))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "w-full border rounded-md", style: { height: maxHeight } }, /* @__PURE__ */ React169__namespace.default.createElement(TooltipProvider2, { delayDuration: 100 }, /* @__PURE__ */ React169__namespace.default.createElement(Table3, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHeader, { className: "sticky top-0 bg-muted z-10" }, /* @__PURE__ */ React169__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "w-[120px]" }, t4("history.headers.date")), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, t4("history.headers.topic")), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "text-right w-[80px]" }, t4("history.headers.score")), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "text-right w-[90px]" }, t4("history.headers.percentage")))), /* @__PURE__ */ React169__namespace.default.createElement(TableBody, null, history2.length > 0 ? history2.map((session) => /* @__PURE__ */ React169__namespace.default.createElement(TableRow, { key: session.id, onClick: () => handleRowClick(session), className: "cursor-pointer" }, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-Medium text-xs text-muted-foreground" }, formatDate(session.timestamp)), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex flex-col gap-1.5" }, session.topics.map((topicInfo, index3) => /* @__PURE__ */ React169__namespace.default.createElement(Tooltip2, { key: index3 }, /* @__PURE__ */ React169__namespace.default.createElement(TooltipTrigger2, { asChild: true }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "font-semibold text-sm truncate" }, topicInfo.topic)), /* @__PURE__ */ React169__namespace.default.createElement(TooltipContent2, null, /* @__PURE__ */ React169__namespace.default.createElement("p", null, /* @__PURE__ */ React169__namespace.default.createElement("strong", null, t4("settingsModal.topics.tableHeaders.subject"), ":"), " ", topicInfo.subject), /* @__PURE__ */ React169__namespace.default.createElement("p", null, /* @__PURE__ */ React169__namespace.default.createElement("strong", null, t4("settingsModal.topics.tableHeaders.category"), ":"), " ", topicInfo.category)))))), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "text-right font-mono text-sm" }, session.score !== null ? `${session.score}/${session.maxScore}` : "N/A"), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "text-right" }, session.percentage !== null && /* @__PURE__ */ React169__namespace.default.createElement(
|
|
112769
112719
|
Badge2,
|
|
112770
112720
|
{
|
|
112771
112721
|
variant: getPercentageBadgeVariant(session.percentage),
|
|
@@ -133580,12 +133530,12 @@ var ChartTooltipContent = React169__namespace.forwardRef(
|
|
|
133580
133530
|
const itemConfig = getPayloadConfigFromPayload(config3, item, key);
|
|
133581
133531
|
const value = !labelKey && typeof label === "string" ? config3[label]?.label || label : itemConfig?.label;
|
|
133582
133532
|
if (labelFormatter) {
|
|
133583
|
-
return /* @__PURE__ */ React169__namespace.createElement("div", { className: cn("font-
|
|
133533
|
+
return /* @__PURE__ */ React169__namespace.createElement("div", { className: cn("font-Medium", labelClassName) }, labelFormatter(value, payload));
|
|
133584
133534
|
}
|
|
133585
133535
|
if (!value) {
|
|
133586
133536
|
return null;
|
|
133587
133537
|
}
|
|
133588
|
-
return /* @__PURE__ */ React169__namespace.createElement("div", { className: cn("font-
|
|
133538
|
+
return /* @__PURE__ */ React169__namespace.createElement("div", { className: cn("font-Medium", labelClassName) }, value);
|
|
133589
133539
|
}, [
|
|
133590
133540
|
label,
|
|
133591
133541
|
labelFormatter,
|
|
@@ -133648,7 +133598,7 @@ var ChartTooltipContent = React169__namespace.forwardRef(
|
|
|
133648
133598
|
)
|
|
133649
133599
|
},
|
|
133650
133600
|
/* @__PURE__ */ React169__namespace.createElement("div", { className: "grid gap-1.5" }, nestLabel ? tooltipLabel : null, /* @__PURE__ */ React169__namespace.createElement("span", { className: "text-muted-foreground" }, itemConfig?.label || item.name)),
|
|
133651
|
-
item.value && /* @__PURE__ */ React169__namespace.createElement("span", { className: "font-mono font-
|
|
133601
|
+
item.value && /* @__PURE__ */ React169__namespace.createElement("span", { className: "font-mono font-Medium tabular-nums text-foreground" }, item.value.toLocaleString())
|
|
133652
133602
|
))
|
|
133653
133603
|
);
|
|
133654
133604
|
}))
|
|
@@ -134825,7 +134775,7 @@ var ManageTopics = () => {
|
|
|
134825
134775
|
return /* @__PURE__ */ React169__namespace.default.createElement(React169__namespace.default.Fragment, null, /* @__PURE__ */ React169__namespace.default.createElement(Card, { className: "w-full max-w-4xl mx-auto shadow-none border-none" }, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, { className: "px-1" }, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "flex items-center text-2xl font-headline" }, /* @__PURE__ */ React169__namespace.default.createElement(FileText, { className: "mr-3 h-6 w-6 text-primary" }), t4("settingsModal.topics.title")), /* @__PURE__ */ React169__namespace.default.createElement(CardDescription, null, t4("settingsModal.topics.description"))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "space-y-6 px-1" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "tsv-importer", className: "text-lg font-semibold" }, t4("settingsModal.topics.importData")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "mt-2 p-4 border border-dashed rounded-lg flex flex-col sm:flex-row items-center gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex-grow" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("settingsModal.topics.importHint")), /* @__PURE__ */ React169__namespace.default.createElement("a", { href: "#", className: "text-xs text-primary hover:underline", onClick: (e3) => {
|
|
134826
134776
|
e3.preventDefault();
|
|
134827
134777
|
alert("Header format:\nLO ID LO Description Subject Category Topic Keywords Grade STEM Element(s) Bloom\u2019s Level(s) Guideline");
|
|
134828
|
-
} }, t4("settingsModal.topics.viewHeaderFormat"))), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "tsv-importer", type: "file", ref: fileInputRef, accept: ".tsv,text/tab-separated-values", onChange: handleFileChange, className: "hidden" }), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: () => fileInputRef.current?.click() }, /* @__PURE__ */ React169__namespace.default.createElement(Upload, { className: "mr-2 h-4 w-4" }), t4("settingsModal.topics.chooseFile")))), importErrors.length > 0 && /* @__PURE__ */ React169__namespace.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleAlert, { className: "h-4 w-4" }), /* @__PURE__ */ React169__namespace.default.createElement(AlertTitle, null, t4("settingsModal.topics.importErrors")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDescription, null, /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-24 mt-2" }, /* @__PURE__ */ React169__namespace.default.createElement("ul", { className: "list-disc list-inside text-xs space-y-1" }, importErrors.map((error, index3) => /* @__PURE__ */ React169__namespace.default.createElement("li", { key: index3 }, error)))))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center sm:justify-between mb-2" }, /* @__PURE__ */ React169__namespace.default.createElement("h3", { className: "text-lg font-semibold" }, t4("settingsModal.topics.currentDataTitle")), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("settingsModal.topics.showingCount", { shown: filteredLearningObjectives.length, total: learningObjectives.length }))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "mb-4" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subject-filter" }, t4("settingsModal.topics.filterBySubject")), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: selectedSubjectFilter, onValueChange: setSelectedSubjectFilter, disabled: subjects.length === 0 }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "subject-filter", className: "w-full sm:w-[280px]" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: t4("settingsModal.topics.filterPlaceholder") })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "all" }, t4("settingsModal.topics.allSubjects")), subjects.map((subject) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: subject, value: subject }, subject))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "border rounded-lg" }, /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-72" }, /* @__PURE__ */ React169__namespace.default.createElement(Table3, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHeader, { className: "sticky top-0 bg-muted" }, /* @__PURE__ */ React169__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "w-[150px]" }, t4("settingsModal.topics.tableHeaders.subject")), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "w-[150px]" }, t4("settingsModal.topics.tableHeaders.category")), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, t4("settingsModal.topics.tableHeaders.topic")), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "w-[100px]" }, t4("settingsModal.topics.tableHeaders.
|
|
134778
|
+
} }, t4("settingsModal.topics.viewHeaderFormat"))), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "tsv-importer", type: "file", ref: fileInputRef, accept: ".tsv,text/tab-separated-values", onChange: handleFileChange, className: "hidden" }), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: () => fileInputRef.current?.click() }, /* @__PURE__ */ React169__namespace.default.createElement(Upload, { className: "mr-2 h-4 w-4" }), t4("settingsModal.topics.chooseFile")))), importErrors.length > 0 && /* @__PURE__ */ React169__namespace.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleAlert, { className: "h-4 w-4" }), /* @__PURE__ */ React169__namespace.default.createElement(AlertTitle, null, t4("settingsModal.topics.importErrors")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDescription, null, /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-24 mt-2" }, /* @__PURE__ */ React169__namespace.default.createElement("ul", { className: "list-disc list-inside text-xs space-y-1" }, importErrors.map((error, index3) => /* @__PURE__ */ React169__namespace.default.createElement("li", { key: index3 }, error)))))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center sm:justify-between mb-2" }, /* @__PURE__ */ React169__namespace.default.createElement("h3", { className: "text-lg font-semibold" }, t4("settingsModal.topics.currentDataTitle")), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("settingsModal.topics.showingCount", { shown: filteredLearningObjectives.length, total: learningObjectives.length }))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "mb-4" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subject-filter" }, t4("settingsModal.topics.filterBySubject")), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: selectedSubjectFilter, onValueChange: setSelectedSubjectFilter, disabled: subjects.length === 0 }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "subject-filter", className: "w-full sm:w-[280px]" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: t4("settingsModal.topics.filterPlaceholder") })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "all" }, t4("settingsModal.topics.allSubjects")), subjects.map((subject) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: subject, value: subject }, subject))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "border rounded-lg" }, /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-72" }, /* @__PURE__ */ React169__namespace.default.createElement(Table3, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHeader, { className: "sticky top-0 bg-muted" }, /* @__PURE__ */ React169__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "w-[150px]" }, t4("settingsModal.topics.tableHeaders.subject")), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "w-[150px]" }, t4("settingsModal.topics.tableHeaders.category")), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, t4("settingsModal.topics.tableHeaders.topic")), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "w-[100px]" }, t4("settingsModal.topics.tableHeaders.code")))), /* @__PURE__ */ React169__namespace.default.createElement(TableBody, null, isLoading ? /* @__PURE__ */ React169__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { colSpan: 4, className: "text-center" }, t4("common.loading"))) : filteredLearningObjectives.length > 0 ? filteredLearningObjectives.map((lo) => /* @__PURE__ */ React169__namespace.default.createElement(TableRow, { key: lo.code }, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, lo.subject), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, lo.category), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-Medium" }, lo.topic), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, lo.code))) : /* @__PURE__ */ React169__namespace.default.createElement(TableRow, null, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { colSpan: 4, className: "text-center h-24 text-muted-foreground" }, t4("settingsModal.topics.emptyData"))))))))), /* @__PURE__ */ React169__namespace.default.createElement(CardFooter, { className: "px-1" }, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialog2, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogTrigger2, { asChild: true }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "destructive", disabled: learningObjectives.length === 0 }, /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "mr-2 h-4 w-4" }), t4("settingsModal.topics.clearAllData"))), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogTitle2, null, t4("settingsModal.topics.clearDataConfirmationTitle")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogDescription2, null, t4("settingsModal.topics.clearDataConfirmationMessage", { count: learningObjectives.length }))), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogCancel2, null, t4("common.cancel")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogAction2, { onClick: handleClearData }, t4("settingsModal.topics.confirmDelete"))))))), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialog2, { open: isConfirmModalOpen, onOpenChange: setIsConfirmModalOpen }, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogTitle2, null, t4("settingsModal.topics.confirmModal.title")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogDescription2, null, t4("settingsModal.topics.confirmModal.description", { count: parsedImportData?.data.length || 0 }))), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogFooter, { className: "gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogCancel2, { onClick: () => setParsedImportData(null) }, t4("common.cancel")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogAction2, { onClick: handleConfirmMerge, className: "bg-blue-600 hover:bg-blue-700" }, t4("settingsModal.topics.confirmModal.mergeButton")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogAction2, { onClick: handleConfirmOverwrite, className: "bg-amber-600 hover:bg-amber-700" }, t4("settingsModal.topics.confirmModal.overwriteButton"))))));
|
|
134829
134779
|
};
|
|
134830
134780
|
|
|
134831
134781
|
// src/react-ui/components/app/ManageImageContexts.tsx
|
|
@@ -135232,7 +135182,7 @@ var SettingsModal = ({ isOpen, onClose, defaultTab = "personal" }) => {
|
|
|
135232
135182
|
return goal.id;
|
|
135233
135183
|
}
|
|
135234
135184
|
};
|
|
135235
|
-
return /* @__PURE__ */ React169__namespace.default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => !open && onClose() }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-xl md:max-w-2xl lg:max-w-3xl max-h-[85vh] flex flex-col" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, { className: "shrink-0" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, { className: "flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Settings, { className: "mr-2 h-5 w-5 text-primary" }), t4("settingsModal.title")), /* @__PURE__ */ React169__namespace.default.createElement(DialogDescription2, null, t4("settingsModal.description"))), /* @__PURE__ */ React169__namespace.default.createElement(Tabs2, { value: activeTab, onValueChange: (value) => setActiveTab(value), className: "pt-2 flex-1 flex flex-col min-h-0" }, /* @__PURE__ */ React169__namespace.default.createElement(TabsList2, { className: "grid w-full grid-cols-5 shrink-0" }, /* @__PURE__ */ React169__namespace.default.createElement(TabsTrigger2, { value: "personal" }, /* @__PURE__ */ React169__namespace.default.createElement(User, { className: "mr-1 h-4 w-4" }), t4("settingsModal.personalTab")), /* @__PURE__ */ React169__namespace.default.createElement(TabsTrigger2, { value: "topics" }, /* @__PURE__ */ React169__namespace.default.createElement(ListTodo, { className: "mr-1 h-4 w-4" }), t4("settingsModal.topicsTab")), /* @__PURE__ */ React169__namespace.default.createElement(TabsTrigger2, { value: "imageContexts" }, /* @__PURE__ */ React169__namespace.default.createElement(ImagePlus, { className: "mr-1 h-4 w-4" }), "Images"), /* @__PURE__ */ React169__namespace.default.createElement(TabsTrigger2, { value: "layout" }, /* @__PURE__ */ React169__namespace.default.createElement(LayoutDashboard, { className: "mr-1 h-4 w-4" }), t4("settingsModal.layoutTab")), /* @__PURE__ */ React169__namespace.default.createElement(TabsTrigger2, { value: "apiKeys" }, /* @__PURE__ */ React169__namespace.default.createElement(KeyRound, { className: "mr-1 h-4 w-4" }), t4("settingsModal.apiKeysTab"))), /* @__PURE__ */ React169__namespace.default.createElement(TabsContent2, { value: "personal", className: "flex-1 overflow-auto mt-4" }, /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-full pr-6" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-4 border rounded-lg" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-semibold mb-3" }, t4("settingsModal.personal.basicInfo")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "full-name" }, t4("settingsModal.personal.fullName")), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "full-name", value: fullName, onChange: (e3) => setFullName(e3.target.value), placeholder: t4("settingsModal.personal.fullNamePlaceholder") })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "weekly-goal" }, t4("settingsModal.personal.weeklyGoal")), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "weekly-goal", type: "number", value: weeklyGoal, onChange: (e3) => setWeeklyGoal(parseInt(e3.target.value, 10) || 0), min: "1" })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "language-select", className: "flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Languages, { className: "mr-2 h-4 w-4" }), t4("settingsModal.personal.languageSelectLabel")), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: language3, onValueChange: changeLanguage2 }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "language-select" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Select a language..." })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "en" }, "English"), /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "vi" }, "Ti\u1EBFng Vi\u1EC7t")))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-4 border rounded-lg" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-semibold mb-3 flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Target, { className: "mr-2 h-4 w-4" }), t4("settingsModal.personal.advancedGoals")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2 mb-4" }, advancedGoals.map((goal) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: goal.id, className: "flex items-center justify-between p-2 bg-muted/50 rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm flex-1" }, renderGoalDescription(goal)), /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", onClick: () => handleDeleteGoal(goal.id) }, /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "h-4 w-4 text-destructive" })))), advancedGoals.length === 0 && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("settingsModal.personal.noGoals"))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement("h5", { className: "font-medium" }, t4("settingsModal.personal.addNewGoal")), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: newGoalType, onValueChange: (v) => setNewGoalType(v) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.goalTypePlaceholder") })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "average_score_subject" }, t4("settingsModal.personal.goalType.avgScoreSubject")), /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "mastery_topic" }, t4("settingsModal.personal.goalType.masteryTopic")))), newGoalType === "average_score_subject" && /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-2 animate-in fade-in" }, /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: newGoalSubject, onValueChange: setNewGoalSubject }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.subjectPlaceholder") })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, allSubjects.map((s4) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: s4, value: s4 }, s4)))), /* @__PURE__ */ React169__namespace.default.createElement(Input, { type: "number", value: newGoalTargetValue, onChange: (e3) => setNewGoalTargetValue(parseInt(e3.target.value)), placeholder: t4("settingsModal.personal.targetScorePlaceholder") })), newGoalType === "mastery_topic" && /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-2 animate-in fade-in" }, /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: newGoalSubject, onValueChange: setNewGoalSubject }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.subjectPlaceholder") })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, allSubjects.map((s4) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: s4, value: s4 }, s4)))), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: newGoalTopic, onValueChange: setNewGoalTopic, disabled: !newGoalSubject }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.topicPlaceholder") })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, topicsForSelectedSubject.map((t5) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: t5, value: t5 }, t5)))), /* @__PURE__ */ React169__namespace.default.createElement(Input, { type: "number", value: newGoalTargetValue, onChange: (e3) => setNewGoalTargetValue(parseInt(e3.target.value)), placeholder: t4("settingsModal.personal.targetScorePlaceholder") }), /* @__PURE__ */ React169__namespace.default.createElement(Input, { type: "number", value: newGoalConsecutive, onChange: (e3) => setNewGoalConsecutive(parseInt(e3.target.value)), placeholder: t4("settingsModal.personal.consecutiveSessionsPlaceholder") })), newGoalType && /* @__PURE__ */ React169__namespace.default.createElement(Button, { size: "sm", onClick: handleAddNewGoal }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), t4("settingsModal.personal.addGoalButton"))))))), /* @__PURE__ */ React169__namespace.default.createElement(TabsContent2, { value: "topics", className: "flex-1 overflow-auto mt-4" }, /* @__PURE__ */ React169__namespace.default.createElement(ManageTopics, null)), /* @__PURE__ */ React169__namespace.default.createElement(TabsContent2, { value: "imageContexts", className: "flex-1 overflow-auto mt-4" }, /* @__PURE__ */ React169__namespace.default.createElement(ManageImageContexts, null)), /* @__PURE__ */ React169__namespace.default.createElement(TabsContent2, { value: "layout", className: "space-y-4 pt-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-4 border rounded-lg" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-semibold" }, t4("settingsModal.layout.title")), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground mt-1 mb-3" }, t4("settingsModal.layout.description")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialog2, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogTrigger2, { asChild: true }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(RefreshCw, { className: "mr-2 h-4 w-4" }), t4("settingsModal.layout.resetButton"))), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogTitle2, null, t4("settingsModal.layout.resetConfirmationTitle")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogDescription2, null, t4("settingsModal.layout.resetConfirmationMessage"))), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogCancel2, null, t4("common.cancel")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogAction2, { onClick: handleResetLayout }, t4("settingsModal.layout.confirmReset"))))))), /* @__PURE__ */ React169__namespace.default.createElement(TabsContent2, { value: "apiKeys", className: "space-y-4 pt-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "gemini-api-key" }, t4("settingsModal.apiKeys.geminiKey")), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "gemini-api-key", type: "password", value: geminiApiKey, onChange: (e3) => setGeminiApiKey(e3.target.value), placeholder: t4("settingsModal.apiKeys.geminiKeyPlaceholder") }), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-muted-foreground" }, t4("settingsModal.apiKeys.storageHint"))))), /* @__PURE__ */ React169__namespace.default.createElement(DialogFooter, { className: "gap-2 sm:justify-end pt-4 shrink-0" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "outline" }, t4("common.close"))), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", onClick: handleSave }, /* @__PURE__ */ React169__namespace.default.createElement(Save, { className: "mr-2 h-4 w-4" }), t4("settingsModal.saveChanges")))));
|
|
135185
|
+
return /* @__PURE__ */ React169__namespace.default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => !open && onClose() }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-xl md:max-w-2xl lg:max-w-3xl max-h-[85vh] flex flex-col" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, { className: "shrink-0" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, { className: "flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Settings, { className: "mr-2 h-5 w-5 text-primary" }), t4("settingsModal.title")), /* @__PURE__ */ React169__namespace.default.createElement(DialogDescription2, null, t4("settingsModal.description"))), /* @__PURE__ */ React169__namespace.default.createElement(Tabs2, { value: activeTab, onValueChange: (value) => setActiveTab(value), className: "pt-2 flex-1 flex flex-col min-h-0" }, /* @__PURE__ */ React169__namespace.default.createElement(TabsList2, { className: "grid w-full grid-cols-5 shrink-0" }, /* @__PURE__ */ React169__namespace.default.createElement(TabsTrigger2, { value: "personal" }, /* @__PURE__ */ React169__namespace.default.createElement(User, { className: "mr-1 h-4 w-4" }), t4("settingsModal.personalTab")), /* @__PURE__ */ React169__namespace.default.createElement(TabsTrigger2, { value: "topics" }, /* @__PURE__ */ React169__namespace.default.createElement(ListTodo, { className: "mr-1 h-4 w-4" }), t4("settingsModal.topicsTab")), /* @__PURE__ */ React169__namespace.default.createElement(TabsTrigger2, { value: "imageContexts" }, /* @__PURE__ */ React169__namespace.default.createElement(ImagePlus, { className: "mr-1 h-4 w-4" }), "Images"), /* @__PURE__ */ React169__namespace.default.createElement(TabsTrigger2, { value: "layout" }, /* @__PURE__ */ React169__namespace.default.createElement(LayoutDashboard, { className: "mr-1 h-4 w-4" }), t4("settingsModal.layoutTab")), /* @__PURE__ */ React169__namespace.default.createElement(TabsTrigger2, { value: "apiKeys" }, /* @__PURE__ */ React169__namespace.default.createElement(KeyRound, { className: "mr-1 h-4 w-4" }), t4("settingsModal.apiKeysTab"))), /* @__PURE__ */ React169__namespace.default.createElement(TabsContent2, { value: "personal", className: "flex-1 overflow-auto mt-4" }, /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-full pr-6" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-4 border rounded-lg" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-semibold mb-3" }, t4("settingsModal.personal.basicInfo")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "full-name" }, t4("settingsModal.personal.fullName")), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "full-name", value: fullName, onChange: (e3) => setFullName(e3.target.value), placeholder: t4("settingsModal.personal.fullNamePlaceholder") })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "weekly-goal" }, t4("settingsModal.personal.weeklyGoal")), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "weekly-goal", type: "number", value: weeklyGoal, onChange: (e3) => setWeeklyGoal(parseInt(e3.target.value, 10) || 0), min: "1" })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "language-select", className: "flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Languages, { className: "mr-2 h-4 w-4" }), t4("settingsModal.personal.languageSelectLabel")), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: language3, onValueChange: changeLanguage2 }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "language-select" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Select a language..." })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "en" }, "English"), /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "vi" }, "Ti\u1EBFng Vi\u1EC7t")))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-4 border rounded-lg" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-semibold mb-3 flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(Target, { className: "mr-2 h-4 w-4" }), t4("settingsModal.personal.advancedGoals")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2 mb-4" }, advancedGoals.map((goal) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: goal.id, className: "flex items-center justify-between p-2 bg-muted/50 rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm flex-1" }, renderGoalDescription(goal)), /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", onClick: () => handleDeleteGoal(goal.id) }, /* @__PURE__ */ React169__namespace.default.createElement(Trash2, { className: "h-4 w-4 text-destructive" })))), advancedGoals.length === 0 && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("settingsModal.personal.noGoals"))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement("h5", { className: "font-Medium" }, t4("settingsModal.personal.addNewGoal")), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: newGoalType, onValueChange: (v) => setNewGoalType(v) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.goalTypePlaceholder") })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "average_score_subject" }, t4("settingsModal.personal.goalType.avgScoreSubject")), /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { value: "mastery_topic" }, t4("settingsModal.personal.goalType.masteryTopic")))), newGoalType === "average_score_subject" && /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-2 animate-in fade-in" }, /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: newGoalSubject, onValueChange: setNewGoalSubject }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.subjectPlaceholder") })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, allSubjects.map((s4) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: s4, value: s4 }, s4)))), /* @__PURE__ */ React169__namespace.default.createElement(Input, { type: "number", value: newGoalTargetValue, onChange: (e3) => setNewGoalTargetValue(parseInt(e3.target.value)), placeholder: t4("settingsModal.personal.targetScorePlaceholder") })), newGoalType === "mastery_topic" && /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-2 animate-in fade-in" }, /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: newGoalSubject, onValueChange: setNewGoalSubject }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.subjectPlaceholder") })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, allSubjects.map((s4) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: s4, value: s4 }, s4)))), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: newGoalTopic, onValueChange: setNewGoalTopic, disabled: !newGoalSubject }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.topicPlaceholder") })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, topicsForSelectedSubject.map((t5) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: t5, value: t5 }, t5)))), /* @__PURE__ */ React169__namespace.default.createElement(Input, { type: "number", value: newGoalTargetValue, onChange: (e3) => setNewGoalTargetValue(parseInt(e3.target.value)), placeholder: t4("settingsModal.personal.targetScorePlaceholder") }), /* @__PURE__ */ React169__namespace.default.createElement(Input, { type: "number", value: newGoalConsecutive, onChange: (e3) => setNewGoalConsecutive(parseInt(e3.target.value)), placeholder: t4("settingsModal.personal.consecutiveSessionsPlaceholder") })), newGoalType && /* @__PURE__ */ React169__namespace.default.createElement(Button, { size: "sm", onClick: handleAddNewGoal }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), t4("settingsModal.personal.addGoalButton"))))))), /* @__PURE__ */ React169__namespace.default.createElement(TabsContent2, { value: "topics", className: "flex-1 overflow-auto mt-4" }, /* @__PURE__ */ React169__namespace.default.createElement(ManageTopics, null)), /* @__PURE__ */ React169__namespace.default.createElement(TabsContent2, { value: "imageContexts", className: "flex-1 overflow-auto mt-4" }, /* @__PURE__ */ React169__namespace.default.createElement(ManageImageContexts, null)), /* @__PURE__ */ React169__namespace.default.createElement(TabsContent2, { value: "layout", className: "space-y-4 pt-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-4 border rounded-lg" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-semibold" }, t4("settingsModal.layout.title")), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground mt-1 mb-3" }, t4("settingsModal.layout.description")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialog2, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogTrigger2, { asChild: true }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(RefreshCw, { className: "mr-2 h-4 w-4" }), t4("settingsModal.layout.resetButton"))), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogTitle2, null, t4("settingsModal.layout.resetConfirmationTitle")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogDescription2, null, t4("settingsModal.layout.resetConfirmationMessage"))), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogCancel2, null, t4("common.cancel")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDialogAction2, { onClick: handleResetLayout }, t4("settingsModal.layout.confirmReset"))))))), /* @__PURE__ */ React169__namespace.default.createElement(TabsContent2, { value: "apiKeys", className: "space-y-4 pt-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "gemini-api-key" }, t4("settingsModal.apiKeys.geminiKey")), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "gemini-api-key", type: "password", value: geminiApiKey, onChange: (e3) => setGeminiApiKey(e3.target.value), placeholder: t4("settingsModal.apiKeys.geminiKeyPlaceholder") }), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-muted-foreground" }, t4("settingsModal.apiKeys.storageHint"))))), /* @__PURE__ */ React169__namespace.default.createElement(DialogFooter, { className: "gap-2 sm:justify-end pt-4 shrink-0" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "outline" }, t4("common.close"))), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", onClick: handleSave }, /* @__PURE__ */ React169__namespace.default.createElement(Save, { className: "mr-2 h-4 w-4" }), t4("settingsModal.saveChanges")))));
|
|
135236
135186
|
};
|
|
135237
135187
|
|
|
135238
135188
|
// src/react-ui/components/dashboard/Cheatsheet.tsx
|
|
@@ -135331,7 +135281,7 @@ var Cheatsheet = () => {
|
|
|
135331
135281
|
}
|
|
135332
135282
|
return null;
|
|
135333
135283
|
};
|
|
135334
|
-
return /* @__PURE__ */ React169__namespace.default.createElement(React169__namespace.default.Fragment, null, /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(BookCopy, { className: "mr-2 h-5 w-5 text-primary" }), t4("knowledgeCards.title")), /* @__PURE__ */ React169__namespace.default.createElement(CardDescription, null, t4("knowledgeCards.description"))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "space-y-4" }, /* @__PURE__ */ React169__namespace.default.createElement(Input, { type: "search", placeholder: t4("knowledgeCards.searchPlaceholder"), value: searchQuery, onChange: (e3) => setSearchQuery2(e3.target.value), disabled: allCards.length === 0 }), /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-[180px] w-full rounded-md border p-2" }, allCards.length > 0 ? filteredCards.length > 0 ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-1" }, filteredCards.map((card) => /* @__PURE__ */ React169__namespace.default.createElement("button", { key: card.id, onClick: () => handleCardClick(card.id), className: "w-full text-left p-2 rounded-md hover:bg-accent text-sm font-
|
|
135284
|
+
return /* @__PURE__ */ React169__namespace.default.createElement(React169__namespace.default.Fragment, null, /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(BookCopy, { className: "mr-2 h-5 w-5 text-primary" }), t4("knowledgeCards.title")), /* @__PURE__ */ React169__namespace.default.createElement(CardDescription, null, t4("knowledgeCards.description"))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "space-y-4" }, /* @__PURE__ */ React169__namespace.default.createElement(Input, { type: "search", placeholder: t4("knowledgeCards.searchPlaceholder"), value: searchQuery, onChange: (e3) => setSearchQuery2(e3.target.value), disabled: allCards.length === 0 }), /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-[180px] w-full rounded-md border p-2" }, allCards.length > 0 ? filteredCards.length > 0 ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-1" }, filteredCards.map((card) => /* @__PURE__ */ React169__namespace.default.createElement("button", { key: card.id, onClick: () => handleCardClick(card.id), className: "w-full text-left p-2 rounded-md hover:bg-accent text-sm font-Medium" }, card.concept))) : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center justify-center h-full" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-muted-foreground" }, t4("knowledgeCards.noMatch"))) : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center justify-center h-full" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-muted-foreground" }, t4("knowledgeCards.empty")))), renderActionArea())), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
135335
135285
|
CardViewerDialog,
|
|
135336
135286
|
{
|
|
135337
135287
|
isOpen: isDialogOpen,
|
|
@@ -135358,9 +135308,9 @@ var StatCard = ({
|
|
|
135358
135308
|
isLoading = false
|
|
135359
135309
|
}) => {
|
|
135360
135310
|
if (isLoading) {
|
|
135361
|
-
return /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2" }, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-sm font-
|
|
135311
|
+
return /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2" }, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-sm font-Medium" }, title), /* @__PURE__ */ React169__namespace.default.createElement(Skeleton, { className: "h-4 w-4" })), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, /* @__PURE__ */ React169__namespace.default.createElement(Skeleton, { className: "h-8 w-3/4 mb-2" }), /* @__PURE__ */ React169__namespace.default.createElement(Skeleton, { className: "h-4 w-1/2" })));
|
|
135362
135312
|
}
|
|
135363
|
-
return /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2" }, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-sm font-
|
|
135313
|
+
return /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2" }, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "text-sm font-Medium" }, title), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "text-muted-foreground" }, icon)), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "text-2xl font-bold" }, value, unit2 && /* @__PURE__ */ React169__namespace.default.createElement("span", { className: "text-xl font-Medium text-muted-foreground ml-1" }, unit2)), context && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs text-muted-foreground" }, context)));
|
|
135364
135314
|
};
|
|
135365
135315
|
|
|
135366
135316
|
// src/react-ui/components/dashboard/PerformanceSnapshot.tsx
|
|
@@ -135459,7 +135409,7 @@ var RoadmapChecklist = () => {
|
|
|
135459
135409
|
}, []);
|
|
135460
135410
|
const handleStartPractice = React169.useCallback((item) => {
|
|
135461
135411
|
const practiceConfig = {
|
|
135462
|
-
loIds: [item.
|
|
135412
|
+
loIds: [item.code],
|
|
135463
135413
|
difficulty: item.suggestedDifficulty,
|
|
135464
135414
|
language: "Vietnamese"
|
|
135465
135415
|
};
|
|
@@ -135469,7 +135419,7 @@ var RoadmapChecklist = () => {
|
|
|
135469
135419
|
return /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(CardTitle, { className: "flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(CalendarCheck, { className: "mr-2 h-5 w-5 text-primary" }), t4("roadmap.title")), /* @__PURE__ */ React169__namespace.default.createElement(CardDescription, null, t4("roadmap.description"))), /* @__PURE__ */ React169__namespace.default.createElement(CardContent, null, !roadmap || !roadmap.items || roadmap.items.length === 0 ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "text-center text-muted-foreground py-8" }, /* @__PURE__ */ React169__namespace.default.createElement("p", null, t4("roadmap.emptyState")), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm" }, t4("roadmap.emptyStateSuggestion"))) : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3" }, roadmap.items.map((item, index3) => /* @__PURE__ */ React169__namespace.default.createElement(
|
|
135470
135420
|
"div",
|
|
135471
135421
|
{
|
|
135472
|
-
key: `${item.
|
|
135422
|
+
key: `${item.code}-${index3}`,
|
|
135473
135423
|
className: "flex items-center justify-between p-3 border rounded-md bg-background hover:bg-muted/50 transition-colors"
|
|
135474
135424
|
},
|
|
135475
135425
|
/* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-start gap-3" }, /* @__PURE__ */ React169__namespace.default.createElement(
|
|
@@ -137012,7 +136962,7 @@ function Calendar2({
|
|
|
137012
136962
|
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
|
|
137013
136963
|
month: "space-y-4",
|
|
137014
136964
|
caption: "flex justify-center pt-1 relative items-center",
|
|
137015
|
-
caption_label: "text-sm font-
|
|
136965
|
+
caption_label: "text-sm font-Medium",
|
|
137016
136966
|
nav: "space-x-1 flex items-center",
|
|
137017
136967
|
nav_button: cn(
|
|
137018
136968
|
buttonVariants({ variant: "outline" }),
|
|
@@ -137134,7 +137084,7 @@ var AnalysisDialog = ({ isOpen, onClose }) => {
|
|
|
137134
137084
|
}
|
|
137135
137085
|
try {
|
|
137136
137086
|
const allAvailableTopics = TopicDataService.getData().map((lo) => ({
|
|
137137
|
-
|
|
137087
|
+
code: lo.code,
|
|
137138
137088
|
subject: lo.subject,
|
|
137139
137089
|
category: lo.category,
|
|
137140
137090
|
topic: lo.topic
|
|
@@ -137587,7 +137537,7 @@ var GeneratedQuizzesCard = () => {
|
|
|
137587
137537
|
onChange: (e3) => setSearchQuery2(e3.target.value),
|
|
137588
137538
|
disabled: uniqueQuizzes.length === 0
|
|
137589
137539
|
}
|
|
137590
|
-
), /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-[180px] w-full rounded-md border p-2" }, uniqueQuizzes.length > 0 ? filteredQuizzes.length > 0 ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-1" }, filteredQuizzes.map((quiz) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: quiz.id, className: "flex items-center justify-between p-2 rounded-md hover:bg-accent" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm font-
|
|
137540
|
+
), /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-[180px] w-full rounded-md border p-2" }, uniqueQuizzes.length > 0 ? filteredQuizzes.length > 0 ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-1" }, filteredQuizzes.map((quiz) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: quiz.id, className: "flex items-center justify-between p-2 rounded-md hover:bg-accent" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm font-Medium truncate pr-2", title: quiz.title }, quiz.title), /* @__PURE__ */ React169__namespace.default.createElement(Button, { size: "sm", variant: "ghost", onClick: () => handleRetake(quiz) }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlay, { className: "mr-2 h-4 w-4" }), t4("common.retake"))))) : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center justify-center h-full" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-muted-foreground" }, t4("quizLists.generated.noMatch"))) : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center justify-center h-full" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-muted-foreground" }, t4("quizLists.generated.empty"))))));
|
|
137591
137541
|
};
|
|
137592
137542
|
|
|
137593
137543
|
// src/react-ui/components/app/UploadResourceModal.tsx
|
|
@@ -137667,11 +137617,12 @@ var UploadResourceModal = ({ isOpen, onClose }) => {
|
|
|
137667
137617
|
language: i18n.language === "vi" ? "Vietnamese" : "English",
|
|
137668
137618
|
documentContent: textContent,
|
|
137669
137619
|
learningObjectives: learningObjectives.map((lo) => ({
|
|
137670
|
-
|
|
137620
|
+
name: lo.name,
|
|
137621
|
+
code: lo.code,
|
|
137671
137622
|
subject: lo.subject,
|
|
137672
137623
|
category: lo.category,
|
|
137673
137624
|
topic: lo.topic,
|
|
137674
|
-
|
|
137625
|
+
description: lo.description || ""
|
|
137675
137626
|
}))
|
|
137676
137627
|
}, apiKey);
|
|
137677
137628
|
setAnalysisResult(result);
|
|
@@ -137704,12 +137655,12 @@ var UploadResourceModal = ({ isOpen, onClose }) => {
|
|
|
137704
137655
|
generatedQuestions = result.generatedQuestions;
|
|
137705
137656
|
} else {
|
|
137706
137657
|
const plan = analysisResult.mappedLOs.map((lo) => {
|
|
137707
|
-
const sourceLO = TopicDataService.getData().find((orig) => orig.
|
|
137658
|
+
const sourceLO = TopicDataService.getData().find((orig) => orig.code === lo.code);
|
|
137708
137659
|
return {
|
|
137709
137660
|
plannedTopic: lo.reasoning,
|
|
137710
137661
|
plannedQuestionType: "multiple_choice",
|
|
137711
137662
|
plannedBloomLevel: "understanding",
|
|
137712
|
-
originalLoId: lo.
|
|
137663
|
+
originalLoId: lo.code,
|
|
137713
137664
|
originalTopic: sourceLO?.topic,
|
|
137714
137665
|
originalCategory: sourceLO?.category,
|
|
137715
137666
|
originalSubject: sourceLO?.subject
|
|
@@ -137754,7 +137705,7 @@ var UploadResourceModal = ({ isOpen, onClose }) => {
|
|
|
137754
137705
|
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex flex-col items-center justify-center h-48" }, /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "h-12 w-12 animate-spin text-primary" }), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "mt-4 text-muted-foreground font-semibold" }, stage === "analyzing" && t4("dialogs.uploadResource.analyzing"), stage === "generating" && t4("dialogs.uploadResource.generating")));
|
|
137755
137706
|
case "result":
|
|
137756
137707
|
if (!analysisResult) return null;
|
|
137757
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "py-4 space-y-4" }, /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "p-4" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-semibold mb-2" }, "AI Analysis Complete"), analysisResult.isFreestyleRecommended ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-start gap-3 text-amber-700" }, /* @__PURE__ */ React169__namespace.default.createElement(BrainCircuit, { className: "h-5 w-5 mt-1 flex-shrink-0" }), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "font-
|
|
137708
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "py-4 space-y-4" }, /* @__PURE__ */ React169__namespace.default.createElement(Card, null, /* @__PURE__ */ React169__namespace.default.createElement(CardContent, { className: "p-4" }, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-semibold mb-2" }, "AI Analysis Complete"), analysisResult.isFreestyleRecommended ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-start gap-3 text-amber-700" }, /* @__PURE__ */ React169__namespace.default.createElement(BrainCircuit, { className: "h-5 w-5 mt-1 flex-shrink-0" }), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "font-Medium" }, t4("dialogs.uploadResource.freestyleRecommended")), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm" }, t4("dialogs.uploadResource.freestyleDescription")))) : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-start gap-3 text-green-700" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleCheckBig, { className: "h-5 w-5 mt-1 flex-shrink-0" }), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "font-Medium" }, t4("dialogs.uploadResource.curriculumMatch")), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm" }, t4("dialogs.uploadResource.curriculumDescription")), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-xs mt-2 font-semibold" }, t4("dialogs.uploadResource.mappedTopics")), /* @__PURE__ */ React169__namespace.default.createElement("ul", { className: "list-disc list-inside text-xs" }, analysisResult.mappedLOs.map((lo) => /* @__PURE__ */ React169__namespace.default.createElement("li", { key: lo.code }, TopicDataService.getData().find((orig) => orig.code === lo.code)?.topic || lo.code))))))), error && /* @__PURE__ */ React169__namespace.default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(CircleAlert, { className: "h-4 w-4" }), /* @__PURE__ */ React169__namespace.default.createElement(AlertTitle, null, t4("common.error")), /* @__PURE__ */ React169__namespace.default.createElement(AlertDescription, null, error)));
|
|
137758
137709
|
}
|
|
137759
137710
|
};
|
|
137760
137711
|
return /* @__PURE__ */ React169__namespace.default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => !open && onClose() }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-lg" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, { className: "flex items-center" }, /* @__PURE__ */ React169__namespace.default.createElement(FileText, { className: "mr-2 h-5 w-5" }), t4("dialogs.uploadResource.title")), /* @__PURE__ */ React169__namespace.default.createElement(DialogDescription2, null, t4("dialogs.uploadResource.description"))), renderContent3(), /* @__PURE__ */ React169__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "outline" }, t4("common.cancel"))), stage === "result" && /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleGenerateQuiz }, /* @__PURE__ */ React169__namespace.default.createElement(Sparkles, { className: "mr-2 h-4 w-4" }), t4("dialogs.uploadResource.generateButton")))));
|
|
@@ -137875,7 +137826,7 @@ var FreestyleQuizzesCard = () => {
|
|
|
137875
137826
|
onChange: (e3) => setSearchQuery2(e3.target.value),
|
|
137876
137827
|
disabled: uniqueQuizzes.length === 0
|
|
137877
137828
|
}
|
|
137878
|
-
), /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-[180px] w-full rounded-md border p-2" }, uniqueQuizzes.length > 0 ? filteredQuizzes.length > 0 ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-1" }, filteredQuizzes.map((quiz) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: quiz.id, className: "flex items-center justify-between p-2 rounded-md hover:bg-accent" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm font-
|
|
137829
|
+
), /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "h-[180px] w-full rounded-md border p-2" }, uniqueQuizzes.length > 0 ? filteredQuizzes.length > 0 ? /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-1" }, filteredQuizzes.map((quiz) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: quiz.id, className: "flex items-center justify-between p-2 rounded-md hover:bg-accent" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm font-Medium truncate pr-2", title: quiz.title }, quiz.title), /* @__PURE__ */ React169__namespace.default.createElement(Button, { size: "sm", variant: "ghost", onClick: () => handleRetake(quiz) }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlay, { className: "mr-2 h-4 w-4" }), t4("common.retake"))))) : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center justify-center h-full" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-muted-foreground" }, t4("quizLists.freestyle.noMatch"))) : /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center justify-center h-full" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-muted-foreground" }, t4("quizLists.freestyle.empty"))))));
|
|
137879
137830
|
};
|
|
137880
137831
|
|
|
137881
137832
|
// src/react-ui/components/common/ClientTranslation.tsx
|
|
@@ -138025,7 +137976,7 @@ var PersonalPracticeDashboard = ({ settingsPath, initialHistory, initialStats, i
|
|
|
138025
137976
|
}
|
|
138026
137977
|
try {
|
|
138027
137978
|
const allAvailableTopics = TopicDataService.getData().map((lo) => ({
|
|
138028
|
-
|
|
137979
|
+
code: lo.code,
|
|
138029
137980
|
subject: lo.subject,
|
|
138030
137981
|
category: lo.category,
|
|
138031
137982
|
topic: lo.topic
|
|
@@ -138519,7 +138470,7 @@ var PracticeModeController = () => {
|
|
|
138519
138470
|
try {
|
|
138520
138471
|
const config3 = JSON.parse(suggestedConfigString);
|
|
138521
138472
|
const allLOs = TopicDataService.getData();
|
|
138522
|
-
const suggestedLOs = allLOs.filter((lo) => config3.loIds?.includes(lo.
|
|
138473
|
+
const suggestedLOs = allLOs.filter((lo) => config3.loIds?.includes(lo.code));
|
|
138523
138474
|
if (suggestedLOs.length > 0) {
|
|
138524
138475
|
setInitialSuggestedLOs(suggestedLOs);
|
|
138525
138476
|
setInitialSuggestedDifficulty(config3.difficulty || "Medium");
|
|
@@ -138562,9 +138513,10 @@ var PracticeModeController = () => {
|
|
|
138562
138513
|
totalQuestions,
|
|
138563
138514
|
numCodingQuestions,
|
|
138564
138515
|
topics: selectedLOs.map((lo) => ({
|
|
138565
|
-
topic: lo.
|
|
138516
|
+
topic: lo.name || lo.code,
|
|
138517
|
+
// FIX: Provide fallback for name
|
|
138566
138518
|
ratio: 100 / selectedLOs.length,
|
|
138567
|
-
originalLoId: lo.
|
|
138519
|
+
originalLoId: lo.code,
|
|
138568
138520
|
originalSubject: lo.subject,
|
|
138569
138521
|
originalCategory: lo.category,
|
|
138570
138522
|
originalTopic: lo.topic
|
|
@@ -138756,7 +138708,7 @@ var SuggestionDialog = ({
|
|
|
138756
138708
|
if (!suggestion) {
|
|
138757
138709
|
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex flex-col items-center justify-center h-64 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-muted-foreground text-center" }, "Kh\xF4ng th\u1EC3 t\u1EA1o g\u1EE3i \xFD v\xE0o l\xFAc n\xE0y. Vui l\xF2ng th\u1EED l\u1EA1i."));
|
|
138758
138710
|
}
|
|
138759
|
-
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-4 bg-muted/50 rounded-lg" }, /* @__PURE__ */ React169__namespace.default.createElement(MarkdownRenderer, { content: suggestion.suggestionText })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-semibold mb-3" }, "K\u1EBF ho\u1EA1ch Luy\u1EC7n t\u1EADp \u0111\u01B0\u1EE3c G\u1EE3i \xFD:"), /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "max-h-[200px] pr-3" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3" }, suggestion.suggestedTopics.map((topic) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: topic.
|
|
138711
|
+
return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-4 bg-muted/50 rounded-lg" }, /* @__PURE__ */ React169__namespace.default.createElement(MarkdownRenderer, { content: suggestion.suggestionText })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement("h4", { className: "font-semibold mb-3" }, "K\u1EBF ho\u1EA1ch Luy\u1EC7n t\u1EADp \u0111\u01B0\u1EE3c G\u1EE3i \xFD:"), /* @__PURE__ */ React169__namespace.default.createElement(ScrollArea2, { className: "max-h-[200px] pr-3" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3" }, suggestion.suggestedTopics.map((topic) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: topic.code, className: "flex items-center justify-between p-3 border rounded-md" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex-1 mr-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-2 mb-1" }, topic.reason === "review" ? /* @__PURE__ */ React169__namespace.default.createElement(Badge2, { variant: "destructive" }, /* @__PURE__ */ React169__namespace.default.createElement(RefreshCw, { className: "h-3 w-3 mr-1.5" }), "\xD4n t\u1EADp") : /* @__PURE__ */ React169__namespace.default.createElement(Badge2, { variant: "secondary" }, /* @__PURE__ */ React169__namespace.default.createElement(Search, { className: "h-3 w-3 mr-1.5" }), "Kh\xE1m ph\xE1")), /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "font-Medium" }, topic.topicName)), /* @__PURE__ */ React169__namespace.default.createElement(Button, { size: "sm", onClick: () => onStartSuggestedPractice(topic) }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlay, { className: "h-4 w-4 mr-2" }), "B\u1EAFt \u0111\u1EA7u")))))));
|
|
138760
138712
|
};
|
|
138761
138713
|
return /* @__PURE__ */ React169__namespace.default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => !open && onClose() }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-lg md:max-w-xl" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, { className: "flex items-center text-2xl" }, /* @__PURE__ */ React169__namespace.default.createElement(Lightbulb, { className: "h-6 w-6 mr-2 text-yellow-500" }), "G\u1EE3i \xFD Luy\u1EC7n t\u1EADp t\u1EEB AI"), /* @__PURE__ */ React169__namespace.default.createElement(DialogDescription2, null, "D\u1EF1a tr\xEAn k\u1EBFt qu\u1EA3 g\u1EA7n \u0111\xE2y, \u0111\xE2y l\xE0 nh\u1EEFng g\xEC gia s\u01B0 AI \u0111\u1EC1 xu\u1EA5t cho b\u1EA1n.")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "py-4" }, renderContent3()), /* @__PURE__ */ React169__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "outline" }, "\u0110\xF3ng")))));
|
|
138762
138714
|
};
|
|
@@ -138766,12 +138718,96 @@ init_react_shim();
|
|
|
138766
138718
|
|
|
138767
138719
|
// src/react-ui/components/metadata/SubjectManager.tsx
|
|
138768
138720
|
init_react_shim();
|
|
138721
|
+
|
|
138722
|
+
// src/react-ui/components/metadata/MetadataImportControls.tsx
|
|
138723
|
+
init_react_shim();
|
|
138724
|
+
function MetadataImportControls({ metadataName, onImport }) {
|
|
138725
|
+
const [isOpen, setIsOpen] = React169.useState(false);
|
|
138726
|
+
const [jsonString, setJsonString] = React169.useState("");
|
|
138727
|
+
const [isImporting, startImportTransition] = React169.useTransition();
|
|
138728
|
+
const fileInputRef = React169.useRef(null);
|
|
138729
|
+
const { toast: toast2 } = useToast();
|
|
138730
|
+
const processAndImportRecords = async (records, importSource) => {
|
|
138731
|
+
if (records.length === 0) {
|
|
138732
|
+
toast2({ title: "No Data", description: `The selected ${importSource === "file" ? "file" : "JSON string"} contains no data to import.`, variant: "destructive" });
|
|
138733
|
+
return;
|
|
138734
|
+
}
|
|
138735
|
+
await onImport(records);
|
|
138736
|
+
setIsOpen(false);
|
|
138737
|
+
setJsonString("");
|
|
138738
|
+
};
|
|
138739
|
+
const handleFileSelected = (event) => {
|
|
138740
|
+
const file = event.target.files?.[0];
|
|
138741
|
+
if (!file) return;
|
|
138742
|
+
if (file.type !== "application/json" && !file.name.endsWith(".csv")) {
|
|
138743
|
+
toast2({ title: "Invalid File Type", description: "Please select a JSON or CSV file.", variant: "destructive" });
|
|
138744
|
+
if (event.target) event.target.value = "";
|
|
138745
|
+
return;
|
|
138746
|
+
}
|
|
138747
|
+
startImportTransition(async () => {
|
|
138748
|
+
try {
|
|
138749
|
+
const fileContent = await file.text();
|
|
138750
|
+
let records = [];
|
|
138751
|
+
if (file.type === "application/json") {
|
|
138752
|
+
records = JSON.parse(fileContent);
|
|
138753
|
+
if (!Array.isArray(records)) throw new Error("JSON file must contain an array of objects.");
|
|
138754
|
+
} else if (file.name.endsWith(".csv")) {
|
|
138755
|
+
const lines = fileContent.split(/\r\n|\n/).filter((line) => line.trim() !== "");
|
|
138756
|
+
if (lines.length < 2) throw new Error("CSV must have a header and at least one data row.");
|
|
138757
|
+
const headers = lines[0].split(",").map((h3) => h3.trim());
|
|
138758
|
+
records = lines.slice(1).map((line) => {
|
|
138759
|
+
const values = line.split(",").map((v) => v.trim());
|
|
138760
|
+
const record = {};
|
|
138761
|
+
headers.forEach((header, index3) => {
|
|
138762
|
+
record[header] = values[index3];
|
|
138763
|
+
});
|
|
138764
|
+
return record;
|
|
138765
|
+
});
|
|
138766
|
+
}
|
|
138767
|
+
await processAndImportRecords(records, "file");
|
|
138768
|
+
} catch (err) {
|
|
138769
|
+
toast2({ title: "Import Error", description: `Failed to process file: ${err.message}`, variant: "destructive" });
|
|
138770
|
+
}
|
|
138771
|
+
});
|
|
138772
|
+
if (event.target) event.target.value = "";
|
|
138773
|
+
};
|
|
138774
|
+
const handleJsonStringImport = () => {
|
|
138775
|
+
if (!jsonString.trim()) {
|
|
138776
|
+
toast2({ title: "Missing Data", description: "JSON string cannot be empty.", variant: "destructive" });
|
|
138777
|
+
return;
|
|
138778
|
+
}
|
|
138779
|
+
startImportTransition(async () => {
|
|
138780
|
+
try {
|
|
138781
|
+
const records = JSON.parse(jsonString);
|
|
138782
|
+
if (!Array.isArray(records)) throw new Error("JSON string must represent an array of objects.");
|
|
138783
|
+
await processAndImportRecords(records, "text");
|
|
138784
|
+
} catch (err) {
|
|
138785
|
+
toast2({ title: "Import Error", description: `Failed to process JSON string: ${err.message}`, variant: "destructive" });
|
|
138786
|
+
}
|
|
138787
|
+
});
|
|
138788
|
+
};
|
|
138789
|
+
return /* @__PURE__ */ React169__namespace.default.createElement(Dialog2, { open: isOpen, onOpenChange: setIsOpen }, /* @__PURE__ */ React169__namespace.default.createElement(DialogTrigger2, { asChild: true }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { size: "sm", variant: "outline" }, /* @__PURE__ */ React169__namespace.default.createElement(Upload, { className: "mr-2 h-4 w-4" }), " Import ", metadataName)), /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, "Bulk Import ", metadataName), /* @__PURE__ */ React169__namespace.default.createElement(DialogDescription2, null, "Import multiple records from a file or by pasting JSON data.")), /* @__PURE__ */ React169__namespace.default.createElement(Tabs2, { defaultValue: "file" }, /* @__PURE__ */ React169__namespace.default.createElement(TabsList2, { className: "grid w-full grid-cols-2" }, /* @__PURE__ */ React169__namespace.default.createElement(TabsTrigger2, { value: "file" }, /* @__PURE__ */ React169__namespace.default.createElement(FileJson, { className: "mr-2 h-4 w-4" }), " From File"), /* @__PURE__ */ React169__namespace.default.createElement(TabsTrigger2, { value: "text" }, /* @__PURE__ */ React169__namespace.default.createElement(ClipboardPaste, { className: "mr-2 h-4 w-4" }), " From Text")), /* @__PURE__ */ React169__namespace.default.createElement(TabsContent2, { value: "file", className: "pt-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-muted-foreground" }, "Select a JSON or CSV file. Ensure column names in the file match the table schema (e.g., 'code', 'name', 'subject_code')."), /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "outline", onClick: () => fileInputRef.current?.click(), disabled: isImporting }, isImporting ? /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React169__namespace.default.createElement(Upload, { className: "mr-2 h-4 w-4" }), isImporting ? "Importing..." : "Select File"), /* @__PURE__ */ React169__namespace.default.createElement("input", { type: "file", ref: fileInputRef, onChange: handleFileSelected, accept: ".json,.csv", className: "hidden" }))), /* @__PURE__ */ React169__namespace.default.createElement(TabsContent2, { value: "text", className: "pt-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "jsonInput" }, "JSON Data (Array of Objects)"), /* @__PURE__ */ React169__namespace.default.createElement(
|
|
138790
|
+
Textarea,
|
|
138791
|
+
{
|
|
138792
|
+
id: "jsonInput",
|
|
138793
|
+
value: jsonString,
|
|
138794
|
+
onChange: (e3) => setJsonString(e3.target.value),
|
|
138795
|
+
placeholder: '[{"code": "SUB1", "name": "Subject 1"}, ...]',
|
|
138796
|
+
rows: 8,
|
|
138797
|
+
className: "font-mono text-xs",
|
|
138798
|
+
disabled: isImporting
|
|
138799
|
+
}
|
|
138800
|
+
), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleJsonStringImport, disabled: isImporting || !jsonString.trim() }, isImporting ? /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React169__namespace.default.createElement(ClipboardPaste, { className: "mr-2 h-4 w-4" }), "Import from Text"))))));
|
|
138801
|
+
}
|
|
138802
|
+
|
|
138803
|
+
// src/react-ui/components/metadata/SubjectManager.tsx
|
|
138769
138804
|
function SubjectManager({
|
|
138770
138805
|
initialData,
|
|
138771
138806
|
isLoading: isLoadingProp,
|
|
138772
138807
|
onAdd,
|
|
138773
138808
|
onUpdate,
|
|
138774
|
-
onDelete
|
|
138809
|
+
onDelete,
|
|
138810
|
+
onBulkAdd
|
|
138775
138811
|
}) {
|
|
138776
138812
|
const [subjects, setSubjects] = React169.useState([]);
|
|
138777
138813
|
const [isLoading, setIsLoading] = React169.useState(true);
|
|
@@ -138869,12 +138905,37 @@ function SubjectManager({
|
|
|
138869
138905
|
}
|
|
138870
138906
|
});
|
|
138871
138907
|
};
|
|
138872
|
-
|
|
138908
|
+
const handleImport = async (records) => {
|
|
138909
|
+
if (!onBulkAdd) return;
|
|
138910
|
+
const validatedRecords = records.map((rec) => {
|
|
138911
|
+
if (typeof rec.code === "string" && typeof rec.name === "string") {
|
|
138912
|
+
return { code: rec.code, name: rec.name };
|
|
138913
|
+
}
|
|
138914
|
+
return null;
|
|
138915
|
+
}).filter((rec) => rec !== null);
|
|
138916
|
+
if (validatedRecords.length !== records.length) {
|
|
138917
|
+
toast2({
|
|
138918
|
+
title: "Import Warning",
|
|
138919
|
+
description: "Some records had invalid or missing 'code' or 'name' fields and were ignored.",
|
|
138920
|
+
variant: "destructive"
|
|
138921
|
+
});
|
|
138922
|
+
}
|
|
138923
|
+
if (validatedRecords.length > 0) {
|
|
138924
|
+
await onBulkAdd(validatedRecords);
|
|
138925
|
+
}
|
|
138926
|
+
};
|
|
138927
|
+
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(BookCopy, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Subjects"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__namespace.default.createElement(
|
|
138928
|
+
MetadataImportControls,
|
|
138929
|
+
{
|
|
138930
|
+
metadataName: "Subjects",
|
|
138931
|
+
onImport: handleImport
|
|
138932
|
+
}
|
|
138933
|
+
), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Subject")))), /* @__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" })) : subjects.length === 0 ? /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No subjects found. Add one to get started!") : /* @__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, "Created At"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Updated At"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__namespace.default.createElement(TableBody, null, subjects.map((subject) => /* @__PURE__ */ React169__namespace.default.createElement(TableRow, { key: subject.id }, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, subject.code), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-Medium" }, subject.name), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, format(new Date(subject.createdAt), "dd/MM/yyyy HH:mm")), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, format(new Date(subject.updatedAt), "dd/MM/yyyy HH:mm")), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(subject), 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(subject), 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-md" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, currentSubject ? "Edit Subject" : "Add New Subject"), /* @__PURE__ */ React169__namespace.default.createElement(DialogDescription2, null, currentSubject ? "Update the details of the subject." : "Enter details for the new subject.")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "subjectCode", value: subjectCode, onChange: (e3) => setSubjectCode(e3.target.value.toUpperCase()), placeholder: "e.g., MATH", disabled: !!currentSubject })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subjectName" }, "Subject Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "subjectName", value: subjectName, onChange: (e3) => setSubjectName(e3.target.value), placeholder: "e.g., Mathematics" }))), /* @__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 || !subjectName.trim() || !subjectCode.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 action cannot be undone. This will permanently delete the subject "', 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"))))));
|
|
138873
138934
|
}
|
|
138874
138935
|
|
|
138875
138936
|
// src/react-ui/components/metadata/GradeLevelManager.tsx
|
|
138876
138937
|
init_react_shim();
|
|
138877
|
-
function GradeLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
|
|
138938
|
+
function GradeLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
|
|
138878
138939
|
const [items, setItems] = React169.useState([]);
|
|
138879
138940
|
const [isLoading, setIsLoading] = React169.useState(true);
|
|
138880
138941
|
const [isDialogOpen, setIsDialogOpen] = React169.useState(false);
|
|
@@ -138971,7 +139032,26 @@ function GradeLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpd
|
|
|
138971
139032
|
}
|
|
138972
139033
|
});
|
|
138973
139034
|
};
|
|
138974
|
-
|
|
139035
|
+
const handleImport = async (records) => {
|
|
139036
|
+
if (!onBulkAdd) return;
|
|
139037
|
+
const validatedRecords = records.map((rec) => {
|
|
139038
|
+
if (typeof rec.code === "string" && typeof rec.name === "string") {
|
|
139039
|
+
return { code: rec.code, name: rec.name };
|
|
139040
|
+
}
|
|
139041
|
+
return null;
|
|
139042
|
+
}).filter((rec) => rec !== null);
|
|
139043
|
+
if (validatedRecords.length !== records.length) {
|
|
139044
|
+
toast2({
|
|
139045
|
+
title: "Import Warning",
|
|
139046
|
+
description: "Some records had invalid or missing 'code' or 'name' fields and were ignored.",
|
|
139047
|
+
variant: "destructive"
|
|
139048
|
+
});
|
|
139049
|
+
}
|
|
139050
|
+
if (validatedRecords.length > 0) {
|
|
139051
|
+
await onBulkAdd(validatedRecords);
|
|
139052
|
+
}
|
|
139053
|
+
};
|
|
139054
|
+
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(Award, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Grade Levels"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__namespace.default.createElement(MetadataImportControls, { metadataName: "Grade Levels", 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 Grade Level")))), /* @__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 grade levels 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, { 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, { 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-md" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, currentItem ? "Edit Grade Level" : "Add New Grade Level")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., G9", disabled: !!currentItem })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Grade 9" }))), /* @__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 || !itemName.trim() || !itemCode.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"))))));
|
|
138975
139055
|
}
|
|
138976
139056
|
|
|
138977
139057
|
// src/react-ui/components/metadata/TopicManager.tsx
|
|
@@ -138982,7 +139062,8 @@ function TopicManager({
|
|
|
138982
139062
|
isLoading: isLoadingProp,
|
|
138983
139063
|
onAdd,
|
|
138984
139064
|
onUpdate,
|
|
138985
|
-
onDelete
|
|
139065
|
+
onDelete,
|
|
139066
|
+
onBulkAdd
|
|
138986
139067
|
}) {
|
|
138987
139068
|
const [topics, setTopics] = React169.useState([]);
|
|
138988
139069
|
const [subjects, setSubjects] = React169.useState([]);
|
|
@@ -139086,15 +139167,34 @@ function TopicManager({
|
|
|
139086
139167
|
}
|
|
139087
139168
|
});
|
|
139088
139169
|
};
|
|
139170
|
+
const handleImport = async (records) => {
|
|
139171
|
+
if (!onBulkAdd) return;
|
|
139172
|
+
const validatedRecords = records.map((rec) => {
|
|
139173
|
+
if (typeof rec.code === "string" && typeof rec.name === "string" && typeof rec.subjectCode === "string") {
|
|
139174
|
+
return { code: rec.code, name: rec.name, subjectCode: rec.subjectCode };
|
|
139175
|
+
}
|
|
139176
|
+
return null;
|
|
139177
|
+
}).filter((rec) => rec !== null);
|
|
139178
|
+
if (validatedRecords.length !== records.length) {
|
|
139179
|
+
toast2({
|
|
139180
|
+
title: "Import Warning",
|
|
139181
|
+
description: "Some records had invalid or missing 'code', 'name', or 'subjectCode' fields and were ignored.",
|
|
139182
|
+
variant: "destructive"
|
|
139183
|
+
});
|
|
139184
|
+
}
|
|
139185
|
+
if (validatedRecords.length > 0) {
|
|
139186
|
+
await onBulkAdd(validatedRecords);
|
|
139187
|
+
}
|
|
139188
|
+
};
|
|
139089
139189
|
const getSubjectName = (subjectCode) => {
|
|
139090
139190
|
return subjects.find((s4) => s4.code === subjectCode)?.name || "N/A";
|
|
139091
139191
|
};
|
|
139092
|
-
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(Tag, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Topics"), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm", disabled: subjects.length === 0 }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Topic")), subjects.length === 0 && !isLoading && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-destructive" }, "Please add subjects before adding topics.")), /* @__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" })) : topics.length === 0 ? /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No topics found. Add one to get started!") : /* @__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, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__namespace.default.createElement(TableBody, null, topics.map((topic) => /* @__PURE__ */ React169__namespace.default.createElement(TableRow, { key: topic.id }, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, topic.code), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-
|
|
139192
|
+
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(Tag, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Topics"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__namespace.default.createElement(MetadataImportControls, { metadataName: "Topics", onImport: handleImport }), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm", disabled: subjects.length === 0 }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Topic"))), subjects.length === 0 && !isLoading && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-destructive" }, "Please add subjects before adding topics.")), /* @__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" })) : topics.length === 0 ? /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No topics found. Add one to get started!") : /* @__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, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__namespace.default.createElement(TableBody, null, topics.map((topic) => /* @__PURE__ */ React169__namespace.default.createElement(TableRow, { key: topic.id }, /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-mono text-xs" }, topic.code), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "font-Medium" }, topic.name), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, getSubjectName(topic.subjectCode), " (", topic.subjectCode, ")"), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(topic), 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(topic), 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-md" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, currentItem ? "Edit Topic" : "Add New Topic")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemCode" }, "Topic Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., ALG-BASICS", disabled: !!currentItem })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemName" }, "Topic Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Algebra Basics" })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: selectedSubjectCode, onValueChange: setSelectedSubjectCode, disabled: subjects.length === 0 }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "subjectCode" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Select a subject" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, subjects.map((subject) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: subject.code, value: subject.code }, subject.name, " (", subject.code, ")")))))), /* @__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 || !itemName.trim() || !itemCode.trim() || !selectedSubjectCode }, 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 topic "', 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"))))));
|
|
139093
139193
|
}
|
|
139094
139194
|
|
|
139095
139195
|
// src/react-ui/components/metadata/CategoryManager.tsx
|
|
139096
139196
|
init_react_shim();
|
|
139097
|
-
function CategoryManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
|
|
139197
|
+
function CategoryManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
|
|
139098
139198
|
const [items, setItems] = React169.useState([]);
|
|
139099
139199
|
const [isLoading, setIsLoading] = React169.useState(true);
|
|
139100
139200
|
const [isDialogOpen, setIsDialogOpen] = React169.useState(false);
|
|
@@ -139194,12 +139294,37 @@ function CategoryManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdat
|
|
|
139194
139294
|
}
|
|
139195
139295
|
});
|
|
139196
139296
|
};
|
|
139197
|
-
|
|
139297
|
+
const handleImport = async (records) => {
|
|
139298
|
+
if (!onBulkAdd) return;
|
|
139299
|
+
const validationResult = records.reduce((acc, rec) => {
|
|
139300
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
139301
|
+
acc.valid.push({
|
|
139302
|
+
code: rec.code,
|
|
139303
|
+
name: rec.name,
|
|
139304
|
+
description: typeof rec.description === "string" ? rec.description : void 0
|
|
139305
|
+
});
|
|
139306
|
+
} else {
|
|
139307
|
+
acc.invalidCount++;
|
|
139308
|
+
}
|
|
139309
|
+
return acc;
|
|
139310
|
+
}, { valid: [], invalidCount: 0 });
|
|
139311
|
+
if (validationResult.invalidCount > 0) {
|
|
139312
|
+
toast2({
|
|
139313
|
+
title: "Import Warning",
|
|
139314
|
+
description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
|
|
139315
|
+
variant: "destructive"
|
|
139316
|
+
});
|
|
139317
|
+
}
|
|
139318
|
+
if (validationResult.valid.length > 0) {
|
|
139319
|
+
await onBulkAdd(validationResult.valid);
|
|
139320
|
+
}
|
|
139321
|
+
};
|
|
139322
|
+
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(Layers, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Categories"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__namespace.default.createElement(MetadataImportControls, { metadataName: "Categories", 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 Category")))), /* @__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 categories 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, "Description"), /* @__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.description), /* @__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-md" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, currentItem ? "Edit Category" : "Add New Category")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., CORE_CONCEPT", disabled: !!currentItem })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Core Concept" })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Fundamental ideas within a subject." }))), /* @__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 || !itemName.trim() || !itemCode.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"))))));
|
|
139198
139323
|
}
|
|
139199
139324
|
|
|
139200
139325
|
// src/react-ui/components/metadata/BloomLevelManager.tsx
|
|
139201
139326
|
init_react_shim();
|
|
139202
|
-
function BloomLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
|
|
139327
|
+
function BloomLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
|
|
139203
139328
|
const [items, setItems] = React169.useState([]);
|
|
139204
139329
|
const [isLoading, setIsLoading] = React169.useState(true);
|
|
139205
139330
|
const [isDialogOpen, setIsDialogOpen] = React169.useState(false);
|
|
@@ -139299,12 +139424,37 @@ function BloomLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpd
|
|
|
139299
139424
|
}
|
|
139300
139425
|
});
|
|
139301
139426
|
};
|
|
139302
|
-
|
|
139427
|
+
const handleImport = async (records) => {
|
|
139428
|
+
if (!onBulkAdd) return;
|
|
139429
|
+
const validationResult = records.reduce((acc, rec) => {
|
|
139430
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
139431
|
+
acc.valid.push({
|
|
139432
|
+
code: rec.code,
|
|
139433
|
+
name: rec.name,
|
|
139434
|
+
description: typeof rec.description === "string" ? rec.description : void 0
|
|
139435
|
+
});
|
|
139436
|
+
} else {
|
|
139437
|
+
acc.invalidCount++;
|
|
139438
|
+
}
|
|
139439
|
+
return acc;
|
|
139440
|
+
}, { valid: [], invalidCount: 0 });
|
|
139441
|
+
if (validationResult.invalidCount > 0) {
|
|
139442
|
+
toast2({
|
|
139443
|
+
title: "Import Warning",
|
|
139444
|
+
description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
|
|
139445
|
+
variant: "destructive"
|
|
139446
|
+
});
|
|
139447
|
+
}
|
|
139448
|
+
if (validationResult.valid.length > 0) {
|
|
139449
|
+
await onBulkAdd(validationResult.valid);
|
|
139450
|
+
}
|
|
139451
|
+
};
|
|
139452
|
+
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(Brain, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Bloom's Levels"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__namespace.default.createElement(MetadataImportControls, { metadataName: "Bloom's Levels", 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 Bloom's Level")))), /* @__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 Bloom's Levels 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, "Description"), /* @__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.description), /* @__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-md" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, currentItem ? "Edit Bloom's Level" : "Add New Bloom's Level")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., REMEMBER", disabled: !!currentItem })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Remembering" })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Recall facts and basic concepts." }))), /* @__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 || !itemCode.trim() || !itemName.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"))))));
|
|
139303
139453
|
}
|
|
139304
139454
|
|
|
139305
139455
|
// src/react-ui/components/metadata/QuestionTypeManager.tsx
|
|
139306
139456
|
init_react_shim();
|
|
139307
|
-
function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
|
|
139457
|
+
function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
|
|
139308
139458
|
const [items, setItems] = React169.useState([]);
|
|
139309
139459
|
const [isLoading, setIsLoading] = React169.useState(true);
|
|
139310
139460
|
const [isDialogOpen, setIsDialogOpen] = React169.useState(false);
|
|
@@ -139374,6 +139524,31 @@ function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onU
|
|
|
139374
139524
|
}
|
|
139375
139525
|
});
|
|
139376
139526
|
};
|
|
139527
|
+
const handleImport = async (records) => {
|
|
139528
|
+
if (!onBulkAdd) return;
|
|
139529
|
+
const validationResult = records.reduce((acc, rec) => {
|
|
139530
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
139531
|
+
acc.valid.push({
|
|
139532
|
+
code: rec.code,
|
|
139533
|
+
name: rec.name,
|
|
139534
|
+
description: typeof rec.description === "string" ? rec.description : void 0
|
|
139535
|
+
});
|
|
139536
|
+
} else {
|
|
139537
|
+
acc.invalidCount++;
|
|
139538
|
+
}
|
|
139539
|
+
return acc;
|
|
139540
|
+
}, { valid: [], invalidCount: 0 });
|
|
139541
|
+
if (validationResult.invalidCount > 0) {
|
|
139542
|
+
toast2({
|
|
139543
|
+
title: "Import Warning",
|
|
139544
|
+
description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
|
|
139545
|
+
variant: "destructive"
|
|
139546
|
+
});
|
|
139547
|
+
}
|
|
139548
|
+
if (validationResult.valid.length > 0) {
|
|
139549
|
+
await onBulkAdd(validationResult.valid);
|
|
139550
|
+
}
|
|
139551
|
+
};
|
|
139377
139552
|
const handleSubmit = () => {
|
|
139378
139553
|
if (!itemName.trim() || !itemCode.trim()) {
|
|
139379
139554
|
toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
|
|
@@ -139404,22 +139579,19 @@ function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onU
|
|
|
139404
139579
|
}
|
|
139405
139580
|
});
|
|
139406
139581
|
};
|
|
139407
|
-
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(CircleHelp, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Question Types"), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Question Type"))), /* @__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 Question Types 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, "Description"), /* @__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-
|
|
139582
|
+
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(CircleHelp, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Question Types"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__namespace.default.createElement(MetadataImportControls, { metadataName: "Question Types", 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 Question Type")))), /* @__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 Question Types 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, "Description"), /* @__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.description), /* @__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-md" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, currentItem ? "Edit Question Type" : "Add New Question Type")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toLowerCase().replace(/ /g, "_")), placeholder: "e.g., multiple_choice", disabled: !!currentItem })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Multiple Choice" })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Select one answer from a list of options." }))), /* @__PURE__ */ 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 || !itemCode.trim() || !itemName.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"))))));
|
|
139408
139583
|
}
|
|
139409
139584
|
|
|
139410
139585
|
// src/react-ui/components/metadata/LearningObjectiveManager.tsx
|
|
139411
139586
|
init_react_shim();
|
|
139412
|
-
function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
|
|
139587
|
+
function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
|
|
139413
139588
|
const [items, setItems] = React169.useState([]);
|
|
139414
139589
|
const [subjects, setSubjects] = React169.useState([]);
|
|
139415
139590
|
const [isLoading, setIsLoading] = React169.useState(true);
|
|
139416
139591
|
const [isDialogOpen, setIsDialogOpen] = React169.useState(false);
|
|
139417
139592
|
const [isAlertOpen, setIsAlertOpen] = React169.useState(false);
|
|
139418
139593
|
const [currentItem, setCurrentItem] = React169.useState(null);
|
|
139419
|
-
const [
|
|
139420
|
-
const [itemCode, setItemCode] = React169.useState("");
|
|
139421
|
-
const [itemDescription, setItemDescription] = React169.useState("");
|
|
139422
|
-
const [selectedSubjectCode, setSelectedSubjectCode] = React169.useState(void 0);
|
|
139594
|
+
const [formState, setFormState] = React169.useState({});
|
|
139423
139595
|
const [itemToDelete, setItemToDelete] = React169.useState(null);
|
|
139424
139596
|
const [isPending, startTransition] = React169.useTransition();
|
|
139425
139597
|
const { toast: toast2 } = useToast();
|
|
@@ -139446,20 +139618,17 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
|
|
|
139446
139618
|
refreshData();
|
|
139447
139619
|
}
|
|
139448
139620
|
}, [isControlled, initialData, subjectsProp, isLoadingProp]);
|
|
139621
|
+
const handleFormChange = (field, value) => {
|
|
139622
|
+
setFormState((prev) => ({ ...prev, [field]: value }));
|
|
139623
|
+
};
|
|
139449
139624
|
const handleAddItem = () => {
|
|
139450
139625
|
setCurrentItem(null);
|
|
139451
|
-
|
|
139452
|
-
setItemCode("");
|
|
139453
|
-
setItemDescription("");
|
|
139454
|
-
setSelectedSubjectCode(subjects.length > 0 ? subjects[0].code : void 0);
|
|
139626
|
+
setFormState({ subjectCode: subjects.length > 0 ? subjects[0].code : "" });
|
|
139455
139627
|
setIsDialogOpen(true);
|
|
139456
139628
|
};
|
|
139457
139629
|
const handleEditItem = (item) => {
|
|
139458
139630
|
setCurrentItem(item);
|
|
139459
|
-
|
|
139460
|
-
setItemCode(item.code);
|
|
139461
|
-
setItemDescription(item.description || "");
|
|
139462
|
-
setSelectedSubjectCode(item.subjectCode);
|
|
139631
|
+
setFormState(item);
|
|
139463
139632
|
setIsDialogOpen(true);
|
|
139464
139633
|
};
|
|
139465
139634
|
const handleDeleteItem = (item) => {
|
|
@@ -139486,7 +139655,7 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
|
|
|
139486
139655
|
});
|
|
139487
139656
|
};
|
|
139488
139657
|
const handleSubmit = () => {
|
|
139489
|
-
if (!
|
|
139658
|
+
if (!formState.name?.trim() || !formState.code?.trim()) {
|
|
139490
139659
|
toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
|
|
139491
139660
|
return;
|
|
139492
139661
|
}
|
|
@@ -139494,17 +139663,17 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
|
|
|
139494
139663
|
try {
|
|
139495
139664
|
if (currentItem) {
|
|
139496
139665
|
if (isControlled && onUpdate) {
|
|
139497
|
-
await onUpdate({
|
|
139666
|
+
await onUpdate({ ...currentItem, ...formState });
|
|
139498
139667
|
} else {
|
|
139499
|
-
MetadataService.updateLearningObjective(currentItem.id,
|
|
139668
|
+
MetadataService.updateLearningObjective(currentItem.id, formState);
|
|
139500
139669
|
refreshData();
|
|
139501
139670
|
}
|
|
139502
139671
|
toast2({ title: "Success", description: "Learning Objective updated." });
|
|
139503
139672
|
} else {
|
|
139504
139673
|
if (isControlled && onAdd) {
|
|
139505
|
-
await onAdd(
|
|
139674
|
+
await onAdd(formState);
|
|
139506
139675
|
} else {
|
|
139507
|
-
MetadataService.addLearningObjective(
|
|
139676
|
+
MetadataService.addLearningObjective(formState);
|
|
139508
139677
|
refreshData();
|
|
139509
139678
|
}
|
|
139510
139679
|
toast2({ title: "Success", description: "Learning Objective added." });
|
|
@@ -139515,16 +139684,51 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
|
|
|
139515
139684
|
}
|
|
139516
139685
|
});
|
|
139517
139686
|
};
|
|
139518
|
-
const
|
|
139519
|
-
if (!
|
|
139520
|
-
|
|
139687
|
+
const handleImport = async (records) => {
|
|
139688
|
+
if (!onBulkAdd) return;
|
|
139689
|
+
const parseStringToArray = (input) => {
|
|
139690
|
+
if (Array.isArray(input)) return input;
|
|
139691
|
+
if (typeof input === "string") return input.split(",").map((s4) => s4.trim()).filter(Boolean);
|
|
139692
|
+
return [];
|
|
139693
|
+
};
|
|
139694
|
+
const validatedRecords = records.reduce((acc, rec) => {
|
|
139695
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
139696
|
+
acc.push({
|
|
139697
|
+
code: rec.code,
|
|
139698
|
+
name: rec.name,
|
|
139699
|
+
description: rec.description,
|
|
139700
|
+
subject: rec.subject,
|
|
139701
|
+
subjectCode: rec.subjectCode,
|
|
139702
|
+
category: rec.category,
|
|
139703
|
+
categoryCode: rec.categoryCode,
|
|
139704
|
+
topic: rec.topic,
|
|
139705
|
+
topicCode: rec.topicCode,
|
|
139706
|
+
grade: rec.grade,
|
|
139707
|
+
gradeCode: rec.gradeCode,
|
|
139708
|
+
keywords: parseStringToArray(rec.keywords),
|
|
139709
|
+
stemElements: parseStringToArray(rec.stemElements),
|
|
139710
|
+
bloomLevelsGuideline: parseStringToArray(rec.bloomLevelsGuideline)
|
|
139711
|
+
});
|
|
139712
|
+
}
|
|
139713
|
+
return acc;
|
|
139714
|
+
}, []);
|
|
139715
|
+
if (validatedRecords.length !== records.length) {
|
|
139716
|
+
toast2({
|
|
139717
|
+
title: "Import Warning",
|
|
139718
|
+
description: `${records.length - validatedRecords.length} records had invalid or missing required fields ('code', 'name') and were ignored.`,
|
|
139719
|
+
variant: "destructive"
|
|
139720
|
+
});
|
|
139721
|
+
}
|
|
139722
|
+
if (validatedRecords.length > 0) {
|
|
139723
|
+
await onBulkAdd(validatedRecords);
|
|
139724
|
+
}
|
|
139521
139725
|
};
|
|
139522
|
-
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(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, "
|
|
139726
|
+
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: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: formState.subjectCode || "", onValueChange: (value) => handleFormChange("subjectCode", value) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, { placeholder: "Select a subject" })), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, subjects.map((subject) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: subject.id, value: subject.code }, subject.name))))), /* @__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: "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", 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(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"))))));
|
|
139523
139727
|
}
|
|
139524
139728
|
|
|
139525
139729
|
// src/react-ui/components/metadata/ContextManager.tsx
|
|
139526
139730
|
init_react_shim();
|
|
139527
|
-
function ContextManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
|
|
139731
|
+
function ContextManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
|
|
139528
139732
|
const [items, setItems] = React169.useState([]);
|
|
139529
139733
|
const [isLoading, setIsLoading] = React169.useState(true);
|
|
139530
139734
|
const [isDialogOpen, setIsDialogOpen] = React169.useState(false);
|
|
@@ -139594,6 +139798,31 @@ function ContextManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate
|
|
|
139594
139798
|
}
|
|
139595
139799
|
});
|
|
139596
139800
|
};
|
|
139801
|
+
const handleImport = async (records) => {
|
|
139802
|
+
if (!onBulkAdd) return;
|
|
139803
|
+
const validationResult = records.reduce((acc, rec) => {
|
|
139804
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
139805
|
+
acc.valid.push({
|
|
139806
|
+
code: rec.code,
|
|
139807
|
+
name: rec.name,
|
|
139808
|
+
description: typeof rec.description === "string" ? rec.description : void 0
|
|
139809
|
+
});
|
|
139810
|
+
} else {
|
|
139811
|
+
acc.invalidCount++;
|
|
139812
|
+
}
|
|
139813
|
+
return acc;
|
|
139814
|
+
}, { valid: [], invalidCount: 0 });
|
|
139815
|
+
if (validationResult.invalidCount > 0) {
|
|
139816
|
+
toast2({
|
|
139817
|
+
title: "Import Warning",
|
|
139818
|
+
description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
|
|
139819
|
+
variant: "destructive"
|
|
139820
|
+
});
|
|
139821
|
+
}
|
|
139822
|
+
if (validationResult.valid.length > 0) {
|
|
139823
|
+
await onBulkAdd(validationResult.valid);
|
|
139824
|
+
}
|
|
139825
|
+
};
|
|
139597
139826
|
const handleSubmit = () => {
|
|
139598
139827
|
if (!itemName.trim() || !itemCode.trim()) {
|
|
139599
139828
|
toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
|
|
@@ -139624,13 +139853,13 @@ function ContextManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate
|
|
|
139624
139853
|
}
|
|
139625
139854
|
});
|
|
139626
139855
|
};
|
|
139627
|
-
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(ScanText, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Contexts"), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Context"))), /* @__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 Contexts 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, "Description"), /* @__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-
|
|
139856
|
+
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(ScanText, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Contexts"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__namespace.default.createElement(MetadataImportControls, { metadataName: "Categories", 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 Context")))), /* @__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 Contexts 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, "Description"), /* @__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.description), /* @__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-md" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, null, currentItem ? "Edit Context" : "Add New Context")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., HIST_INQ", disabled: !!currentItem })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Historical Inquiry" })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Analyzing primary and secondary sources." }))), /* @__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 || !itemCode.trim() || !itemName.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"))))));
|
|
139628
139857
|
}
|
|
139629
139858
|
|
|
139630
139859
|
// src/react-ui/components/metadata/ApproachManager.tsx
|
|
139631
139860
|
init_react_shim();
|
|
139632
139861
|
var knowledgeDimensions = ["Factual", "Conceptual", "Procedural"];
|
|
139633
|
-
var
|
|
139862
|
+
var standardDifficulties = ["Easy", "Medium", "Hard"];
|
|
139634
139863
|
function ApproachManager({
|
|
139635
139864
|
initialData,
|
|
139636
139865
|
bloomLevels: bloomLevelsProp,
|
|
@@ -139638,7 +139867,8 @@ function ApproachManager({
|
|
|
139638
139867
|
isLoading: isLoadingProp,
|
|
139639
139868
|
onAdd,
|
|
139640
139869
|
onUpdate,
|
|
139641
|
-
onDelete
|
|
139870
|
+
onDelete,
|
|
139871
|
+
onBulkAdd
|
|
139642
139872
|
}) {
|
|
139643
139873
|
const [items, setItems] = React169.useState([]);
|
|
139644
139874
|
const [bloomLevels, setBloomLevels] = React169.useState([]);
|
|
@@ -139679,7 +139909,7 @@ function ApproachManager({
|
|
|
139679
139909
|
const resetForm = () => {
|
|
139680
139910
|
setFormState({
|
|
139681
139911
|
knowledgeDimension: "Factual",
|
|
139682
|
-
|
|
139912
|
+
difficulty: ["Medium"],
|
|
139683
139913
|
bloomLevelCode: bloomLevels.length > 0 ? bloomLevels[0].code : "",
|
|
139684
139914
|
iSpringQuizType: questionTypes.length > 0 ? questionTypes[0].code : "multiple_choice"
|
|
139685
139915
|
});
|
|
@@ -139691,18 +139921,7 @@ function ApproachManager({
|
|
|
139691
139921
|
};
|
|
139692
139922
|
const handleEditItem = (item) => {
|
|
139693
139923
|
setCurrentItem(item);
|
|
139694
|
-
setFormState(
|
|
139695
|
-
code: item.code,
|
|
139696
|
-
verbEn: item.verbEn,
|
|
139697
|
-
verbVi: item.verbVi,
|
|
139698
|
-
bloomLevelCode: item.bloomLevelCode,
|
|
139699
|
-
knowledgeDimension: item.knowledgeDimension,
|
|
139700
|
-
iSpringQuizType: item.iSpringQuizType,
|
|
139701
|
-
rawDifficulty: item.rawDifficulty,
|
|
139702
|
-
suggestContext: item.suggestContext,
|
|
139703
|
-
exampleEn: item.exampleEn,
|
|
139704
|
-
exampleVi: item.exampleVi
|
|
139705
|
-
});
|
|
139924
|
+
setFormState(item);
|
|
139706
139925
|
setIsDialogOpen(true);
|
|
139707
139926
|
};
|
|
139708
139927
|
const handleDeleteItem = (item) => {
|
|
@@ -139729,9 +139948,9 @@ function ApproachManager({
|
|
|
139729
139948
|
});
|
|
139730
139949
|
};
|
|
139731
139950
|
const handleSubmit = () => {
|
|
139732
|
-
const { code: code4, verbEn, verbVi, bloomLevelCode, iSpringQuizType, knowledgeDimension,
|
|
139733
|
-
if (!code4?.trim() || !verbEn?.trim() || !verbVi?.trim() || !bloomLevelCode || !iSpringQuizType || !knowledgeDimension || !
|
|
139734
|
-
toast2({ title: "Validation Error", description: "All fields except examples and context are required.", variant: "destructive" });
|
|
139951
|
+
const { code: code4, name: name3, verbEn, verbVi, bloomLevelCode, iSpringQuizType, knowledgeDimension, difficulty } = formState;
|
|
139952
|
+
if (!code4?.trim() || !name3?.trim() || !verbEn?.trim() || !verbVi?.trim() || !bloomLevelCode || !iSpringQuizType || !knowledgeDimension || !difficulty || difficulty.length === 0) {
|
|
139953
|
+
toast2({ title: "Validation Error", description: "All fields except examples and context are required, and at least one difficulty must be selected.", variant: "destructive" });
|
|
139735
139954
|
return;
|
|
139736
139955
|
}
|
|
139737
139956
|
startTransition(async () => {
|
|
@@ -139759,7 +139978,47 @@ function ApproachManager({
|
|
|
139759
139978
|
}
|
|
139760
139979
|
});
|
|
139761
139980
|
};
|
|
139762
|
-
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(Settings2, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Approaches"), /* @__PURE__ */ React169__namespace.default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__namespace.default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Approach"))), /* @__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 Approaches 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, "Approach ID"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Verb (VI)"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Cognitive Level"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "iSpring Type"), /* @__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-medium" }, item.code), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, item.verbVi), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, item.bloomLevelCode), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, item.iSpringQuizType), /* @__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 Approach" : "Add New Approach")), /* @__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" }, "Approach Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e3) => setFormState((s4) => ({ ...s4, code: e3.target.value.toUpperCase() })), placeholder: "e.g., REM-FAC-IDT-MCQ", disabled: !!currentItem })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "verbEn" }, "Verb (English)"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "verbEn", value: formState.verbEn || "", onChange: (e3) => setFormState((s4) => ({ ...s4, verbEn: e3.target.value })), placeholder: "e.g., Identify" }))), /* @__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: "verbVi" }, "Verb (Vietnamese)"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "verbVi", value: formState.verbVi || "", onChange: (e3) => setFormState((s4) => ({ ...s4, verbVi: e3.target.value })), placeholder: "e.g., Nh\u1EADn d\u1EA1ng" })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "bloomLevelCode" }, "Cognitive Level"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: formState.bloomLevelCode, onValueChange: (v) => setFormState((s4) => ({ ...s4, bloomLevelCode: v })) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, bloomLevels.map((level) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: level.code, value: level.code }, level.name)))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "knowledgeDimension" }, "Knowledge Dimension"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: formState.knowledgeDimension, onValueChange: (v) => setFormState((s4) => ({ ...s4, knowledgeDimension: v })) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, knowledgeDimensions.map((kd) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: kd, value: kd }, kd))))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "iSpringQuizType" }, "iSpring Quiz Type"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: formState.iSpringQuizType, onValueChange: (v) => setFormState((s4) => ({ ...s4, iSpringQuizType: v })) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, questionTypes.map((qt) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: qt.code, value: qt.code }, qt.name))))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "rawDifficulty" }, "Raw Difficulty"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: formState.rawDifficulty, onValueChange: (v) => setFormState((s4) => ({ ...s4, rawDifficulty: v })) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, rawDifficultyLevels.map((rd) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: rd, value: rd }, rd)))))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "suggestContext" }, "Suggest Context (comma-separated codes)"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "suggestContext", value: formState.suggestContext || "", onChange: (e3) => setFormState((s4) => ({ ...s4, suggestContext: e3.target.value })), placeholder: "e.g., A, B, D, G, H" })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "exampleEn" }, "Example (English)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "exampleEn", value: formState.exampleEn || "", onChange: (e3) => setFormState((s4) => ({ ...s4, exampleEn: e3.target.value })), placeholder: "English example prompt..." })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "exampleVi" }, "Example (Vietnamese)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "exampleVi", value: formState.exampleVi || "", onChange: (e3) => setFormState((s4) => ({ ...s4, exampleVi: e3.target.value })), placeholder: "Vietnamese example prompt..." }))), /* @__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 }, 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?.code, '".')), /* @__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"))))));
|
|
139981
|
+
const handleImport = async (records) => {
|
|
139982
|
+
if (!onBulkAdd) return;
|
|
139983
|
+
const parseStringToArray = (input) => {
|
|
139984
|
+
if (Array.isArray(input)) return input;
|
|
139985
|
+
if (typeof input === "string") return input.split(",").map((s4) => s4.trim()).filter(Boolean);
|
|
139986
|
+
return [];
|
|
139987
|
+
};
|
|
139988
|
+
const validatedRecords = records.reduce((acc, rec) => {
|
|
139989
|
+
if (rec.code && rec.name && rec.verbEn && rec.verbVi && rec.knowledgeDimension && rec.iSpringQuizType && rec.difficulty && rec.bloomLevelCode) {
|
|
139990
|
+
acc.push({
|
|
139991
|
+
code: rec.code,
|
|
139992
|
+
name: rec.name,
|
|
139993
|
+
verbEn: rec.verbEn,
|
|
139994
|
+
verbVi: rec.verbVi,
|
|
139995
|
+
knowledgeDimension: rec.knowledgeDimension,
|
|
139996
|
+
iSpringQuizType: rec.iSpringQuizType,
|
|
139997
|
+
difficulty: parseStringToArray(rec.difficulty),
|
|
139998
|
+
bloomLevelCode: rec.bloomLevelCode,
|
|
139999
|
+
suggestContext: rec.suggestContext,
|
|
140000
|
+
exampleEn: rec.exampleEn,
|
|
140001
|
+
exampleVi: rec.exampleVi
|
|
140002
|
+
});
|
|
140003
|
+
}
|
|
140004
|
+
return acc;
|
|
140005
|
+
}, []);
|
|
140006
|
+
if (validatedRecords.length !== records.length) {
|
|
140007
|
+
toast2({
|
|
140008
|
+
title: "Import Warning",
|
|
140009
|
+
description: `${records.length - validatedRecords.length} records had missing required fields and were ignored.`,
|
|
140010
|
+
variant: "destructive"
|
|
140011
|
+
});
|
|
140012
|
+
}
|
|
140013
|
+
if (validatedRecords.length > 0) {
|
|
140014
|
+
await onBulkAdd(validatedRecords);
|
|
140015
|
+
}
|
|
140016
|
+
};
|
|
140017
|
+
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(Settings2, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Approaches"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__namespace.default.createElement(MetadataImportControls, { metadataName: "Approaches", 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 Approach")))), /* @__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 Approaches 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, "Approach ID"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Verb (VI)"), /* @__PURE__ */ React169__namespace.default.createElement(TableHead, null, "Cognitive Level"), /* @__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-Medium" }, item.code), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, item.name), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, item.verbVi), /* @__PURE__ */ React169__namespace.default.createElement(TableCell, null, item.bloomLevelCode), /* @__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 Approach" : "Add New Approach")), /* @__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" }, "Approach Code"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e3) => setFormState((s4) => ({ ...s4, code: e3.target.value.toUpperCase() })), placeholder: "e.g., REM-FAC-IDT-MCQ", disabled: !!currentItem })), /* @__PURE__ */ 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) => setFormState((s4) => ({ ...s4, name: e3.target.value })), placeholder: "e.g., Identify a Fact" }))), /* @__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: "verbEn" }, "Verb (English)"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "verbEn", value: formState.verbEn || "", onChange: (e3) => setFormState((s4) => ({ ...s4, verbEn: e3.target.value })), placeholder: "e.g., Identify" })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "verbVi" }, "Verb (Vietnamese)"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "verbVi", value: formState.verbVi || "", onChange: (e3) => setFormState((s4) => ({ ...s4, verbVi: e3.target.value })), placeholder: "e.g., Nh\u1EADn d\u1EA1ng" }))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "bloomLevelCode" }, "Cognitive Level"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: formState.bloomLevelCode, onValueChange: (v) => setFormState((s4) => ({ ...s4, bloomLevelCode: v })) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, bloomLevels.map((level) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: level.code, value: level.code }, level.name))))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "knowledgeDimension" }, "Knowledge Dimension"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: formState.knowledgeDimension, onValueChange: (v) => setFormState((s4) => ({ ...s4, knowledgeDimension: v })) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, knowledgeDimensions.map((kd) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: kd, value: kd }, kd))))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "iSpringQuizType" }, "iSpring Quiz Type"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: formState.iSpringQuizType, onValueChange: (v) => setFormState((s4) => ({ ...s4, iSpringQuizType: v })) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, questionTypes.map((qt) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: qt.code, value: qt.code }, qt.name)))))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, null, "Difficulty"), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center space-x-4 pt-2" }, standardDifficulties.map((diff2) => /* @__PURE__ */ React169__namespace.default.createElement("div", { key: diff2, className: "flex items-center space-x-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Checkbox2, { id: `diff-${diff2}`, checked: (formState.difficulty || []).includes(diff2), onCheckedChange: (checked) => {
|
|
140018
|
+
const current = formState.difficulty || [];
|
|
140019
|
+
const newDiff = checked ? [...current, diff2] : current.filter((d) => d !== diff2);
|
|
140020
|
+
setFormState((s4) => ({ ...s4, difficulty: newDiff }));
|
|
140021
|
+
} }), /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: `diff-${diff2}` }, diff2))))), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "suggestContext" }, "Suggest Context (comma-separated codes)"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "suggestContext", value: formState.suggestContext || "", onChange: (e3) => setFormState((s4) => ({ ...s4, suggestContext: e3.target.value })), placeholder: "e.g., A, B, D, G, H" })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "exampleEn" }, "Example (English)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "exampleEn", value: formState.exampleEn || "", onChange: (e3) => setFormState((s4) => ({ ...s4, exampleEn: e3.target.value })), placeholder: "English example prompt..." })), /* @__PURE__ */ React169__namespace.default.createElement("div", null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "exampleVi" }, "Example (Vietnamese)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "exampleVi", value: formState.exampleVi || "", onChange: (e3) => setFormState((s4) => ({ ...s4, exampleVi: e3.target.value })), placeholder: "Vietnamese example prompt..." }))), /* @__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 }, 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?.code, '".')), /* @__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"))))));
|
|
139763
140022
|
}
|
|
139764
140023
|
|
|
139765
140024
|
// src/react-ui/components/metadata/MetadataTabs.tsx
|
|
@@ -140435,7 +140694,7 @@ var ToastAction2 = React169__namespace.forwardRef(({ className, ...props }, ref)
|
|
|
140435
140694
|
{
|
|
140436
140695
|
ref,
|
|
140437
140696
|
className: cn(
|
|
140438
|
-
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-
|
|
140697
|
+
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-Medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
|
|
140439
140698
|
className
|
|
140440
140699
|
),
|
|
140441
140700
|
...props
|
|
@@ -142073,6 +142332,7 @@ exports.Label = Label2;
|
|
|
142073
142332
|
exports.LanguageProvider = LanguageProvider;
|
|
142074
142333
|
exports.LearningObjectiveManager = LearningObjectiveManager;
|
|
142075
142334
|
exports.ManageTopics = ManageTopics;
|
|
142335
|
+
exports.MetadataImportControls = MetadataImportControls;
|
|
142076
142336
|
exports.MetadataTabs = MetadataTabs;
|
|
142077
142337
|
exports.PerformanceCharts = PerformanceCharts;
|
|
142078
142338
|
exports.PersonalPracticeDashboard = PersonalPracticeDashboard;
|