@thanh01.pmt/interactive-quiz-kit 1.0.66 → 1.0.68
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 +1499 -1260
- package/dist/authoring.d.cts +4 -4
- package/dist/authoring.d.ts +4 -4
- package/dist/authoring.mjs +1231 -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 +467 -244
- package/dist/react-ui.d.cts +6 -6
- package/dist/react-ui.d.ts +6 -6
- package/dist/react-ui.mjs +467 -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.mjs
CHANGED
|
@@ -9019,7 +9019,7 @@ var translation_default = {
|
|
|
9019
9019
|
subject: "Subject",
|
|
9020
9020
|
category: "Category",
|
|
9021
9021
|
topic: "Topic",
|
|
9022
|
-
|
|
9022
|
+
code: "LO ID"
|
|
9023
9023
|
},
|
|
9024
9024
|
confirmModal: {
|
|
9025
9025
|
title: "Confirm Data Import",
|
|
@@ -9434,7 +9434,7 @@ var translation_default2 = {
|
|
|
9434
9434
|
subject: "M\xF4n h\u1ECDc",
|
|
9435
9435
|
category: "Danh m\u1EE5c",
|
|
9436
9436
|
topic: "Ch\u1EE7 \u0111\u1EC1",
|
|
9437
|
-
|
|
9437
|
+
code: "M\xE3 MTH"
|
|
9438
9438
|
},
|
|
9439
9439
|
confirmModal: {
|
|
9440
9440
|
title: "X\xE1c nh\u1EADn Nh\u1EADp D\u1EEF li\u1EC7u",
|
|
@@ -37506,7 +37506,7 @@ var cva = (base3, config3) => (props) => {
|
|
|
37506
37506
|
|
|
37507
37507
|
// src/react-ui/components/elements/label.tsx
|
|
37508
37508
|
var labelVariants = cva(
|
|
37509
|
-
"text-sm font-
|
|
37509
|
+
"text-sm font-Medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
37510
37510
|
);
|
|
37511
37511
|
var Label2 = React169.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React169.createElement(
|
|
37512
37512
|
Root3,
|
|
@@ -62744,7 +62744,7 @@ var MarkdownRenderer = ({
|
|
|
62744
62744
|
},
|
|
62745
62745
|
h1: ({ node: node2, ...props }) => /* @__PURE__ */ React169__default.createElement("h1", { ...props, className: "text-3xl font-bold mb-6 mt-8 first:mt-0" }),
|
|
62746
62746
|
h2: ({ node: node2, ...props }) => /* @__PURE__ */ React169__default.createElement("h2", { ...props, className: "text-2xl font-semibold mb-4 mt-6" }),
|
|
62747
|
-
h3: ({ node: node2, ...props }) => /* @__PURE__ */ React169__default.createElement("h3", { ...props, className: "text-xl font-
|
|
62747
|
+
h3: ({ node: node2, ...props }) => /* @__PURE__ */ React169__default.createElement("h3", { ...props, className: "text-xl font-Medium mb-3 mt-5" }),
|
|
62748
62748
|
ul: ({ node: node2, ...props }) => /* @__PURE__ */ React169__default.createElement("ul", { ...props, className: "my-4 space-y-2 list-disc list-inside" }),
|
|
62749
62749
|
ol: ({ node: node2, ...props }) => /* @__PURE__ */ React169__default.createElement("ol", { ...props, className: "my-4 space-y-2 list-decimal list-inside" }),
|
|
62750
62750
|
p: ({ node: node2, ...props }) => /* @__PURE__ */ React169__default.createElement("p", { ...props, className: "mb-4 leading-7" }),
|
|
@@ -63218,7 +63218,7 @@ var Input = React169.forwardRef(
|
|
|
63218
63218
|
{
|
|
63219
63219
|
type,
|
|
63220
63220
|
className: cn(
|
|
63221
|
-
"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-
|
|
63221
|
+
"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",
|
|
63222
63222
|
className
|
|
63223
63223
|
),
|
|
63224
63224
|
ref,
|
|
@@ -63393,7 +63393,7 @@ init_react_shim();
|
|
|
63393
63393
|
// src/react-ui/components/elements/button.tsx
|
|
63394
63394
|
init_react_shim();
|
|
63395
63395
|
var buttonVariants = cva(
|
|
63396
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-
|
|
63396
|
+
"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",
|
|
63397
63397
|
{
|
|
63398
63398
|
variants: {
|
|
63399
63399
|
variant: {
|
|
@@ -68346,7 +68346,7 @@ var MatchingQuestionUI = ({
|
|
|
68346
68346
|
if (showCorrectAnswer && selectedOptionId) {
|
|
68347
68347
|
borderColor = isSelectionCorrect ? "border-green-500" : "border-destructive";
|
|
68348
68348
|
}
|
|
68349
|
-
return /* @__PURE__ */ React169__default.createElement("div", { key: promptItem.id, className: `p-3 border rounded-md ${borderColor} transition-colors bg-background` }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: `select-prompt-${promptItem.id}`, className: "font-
|
|
68349
|
+
return /* @__PURE__ */ React169__default.createElement("div", { key: promptItem.id, className: `p-3 border rounded-md ${borderColor} transition-colors bg-background` }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: `select-prompt-${promptItem.id}`, className: "font-Medium text-base block mb-2 whitespace-normal" }, /* @__PURE__ */ React169__default.createElement(MarkdownRenderer, { content: promptItem.content })), /* @__PURE__ */ React169__default.createElement(
|
|
68350
68350
|
Select2,
|
|
68351
68351
|
{
|
|
68352
68352
|
value: selectedOptionId,
|
|
@@ -68401,7 +68401,7 @@ var DragAndDropQuestionUI = ({
|
|
|
68401
68401
|
} else {
|
|
68402
68402
|
itemStyle += " border-muted";
|
|
68403
68403
|
}
|
|
68404
|
-
return /* @__PURE__ */ React169__default.createElement("div", { key: item.id, className: itemStyle }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: `select-draggable-${item.id}`, className: "font-
|
|
68404
|
+
return /* @__PURE__ */ React169__default.createElement("div", { key: item.id, className: itemStyle }, /* @__PURE__ */ React169__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__default.createElement(MarkdownRenderer, { content: item.content })), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center space-x-2 w-full sm:w-auto" }, /* @__PURE__ */ React169__default.createElement(
|
|
68405
68405
|
Select2,
|
|
68406
68406
|
{
|
|
68407
68407
|
value: selectedDropZoneId,
|
|
@@ -95417,7 +95417,7 @@ var TabsTrigger2 = React169.forwardRef(({ className, ...props }, ref) => /* @__P
|
|
|
95417
95417
|
{
|
|
95418
95418
|
ref,
|
|
95419
95419
|
className: cn(
|
|
95420
|
-
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-
|
|
95420
|
+
"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",
|
|
95421
95421
|
className
|
|
95422
95422
|
),
|
|
95423
95423
|
...props
|
|
@@ -96117,7 +96117,7 @@ var AccordionTrigger2 = React169.forwardRef(({ className, children, ...props },
|
|
|
96117
96117
|
{
|
|
96118
96118
|
ref,
|
|
96119
96119
|
className: cn(
|
|
96120
|
-
"flex flex-1 items-center justify-between py-4 font-
|
|
96120
|
+
"flex flex-1 items-center justify-between py-4 font-Medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
|
|
96121
96121
|
className
|
|
96122
96122
|
),
|
|
96123
96123
|
...props
|
|
@@ -96904,7 +96904,7 @@ var QuizResult = ({
|
|
|
96904
96904
|
}
|
|
96905
96905
|
return String(answer);
|
|
96906
96906
|
};
|
|
96907
|
-
return /* @__PURE__ */ React169__default.createElement(Card, { className: "w-full max-w-3xl mx-auto shadow-xl" }, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-3xl font-headline text-center" }, t4("practiceFlow.results.title", { quizTitle })), /* @__PURE__ */ React169__default.createElement(CardDescription, { className: "text-center text-lg" }, t4("practiceFlow.results.description"))), /* @__PURE__ */ React169__default.createElement(CardContent, { className: "space-y-6" }, /* @__PURE__ */ React169__default.createElement(Card, { className: "bg-secondary/50" }, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-xl flex items-center" }, /* @__PURE__ */ React169__default.createElement(BarChart2, { className: "mr-2 h-5 w-5 text-primary" }), t4("practiceFlow.results.overallScore"))), /* @__PURE__ */ React169__default.createElement(CardContent, { className: "grid grid-cols-1 md:grid-cols-3 gap-4 text-center" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("p", { className: "text-3xl font-bold text-primary" }, result.score, " / ", result.maxScore), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("practiceFlow.results.points"))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("p", { className: "text-3xl font-bold text-primary" }, result.percentage.toFixed(2), "%"), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("practiceFlow.results.percentage"))), /* @__PURE__ */ React169__default.createElement("div", null, result.passed !== void 0 && (result.passed ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex flex-col items-center text-green-600" }, /* @__PURE__ */ React169__default.createElement(CircleCheckBig, { className: "h-10 w-10" }), /* @__PURE__ */ React169__default.createElement("p", { className: "text-xl font-semibold mt-1" }, t4("practiceFlow.results.passed"))) : /* @__PURE__ */ React169__default.createElement("div", { className: "flex flex-col items-center text-destructive" }, /* @__PURE__ */ React169__default.createElement(CircleX, { className: "h-10 w-10" }), /* @__PURE__ */ React169__default.createElement("p", { className: "text-xl font-semibold mt-1" }, t4("practiceFlow.results.failed"))))))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center space-x-2 p-3 bg-muted rounded-md" }, /* @__PURE__ */ React169__default.createElement(Clock, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ React169__default.createElement("span", null, t4("practiceFlow.results.timeSpent")), /* @__PURE__ */ React169__default.createElement("span", { className: "font-semibold" }, result.totalTimeSpentSeconds?.toFixed(0) ?? "N/A", " ", t4("practiceFlow.results.timeUnit"))), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center space-x-2 p-3 bg-muted rounded-md" }, /* @__PURE__ */ React169__default.createElement(Percent, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ React169__default.createElement("span", null, t4("practiceFlow.results.avgTimePerQuestion")), /* @__PURE__ */ React169__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__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-lg" }, "SCORM Sync Status")), /* @__PURE__ */ React169__default.createElement(CardContent, null, /* @__PURE__ */ React169__default.createElement("p", { className: `flex items-center ${result.scormStatus === "error" ? "text-destructive" : "text-muted-foreground"}` }, result.scormStatus === "error" && /* @__PURE__ */ React169__default.createElement(TriangleAlert, { className: "mr-2 h-4 w-4" }), "Status: ", /* @__PURE__ */ React169__default.createElement("span", { className: "font-semibold ml-1" }, result.scormStatus)), result.scormError && /* @__PURE__ */ React169__default.createElement("p", { className: "text-xs text-destructive mt-1" }, "Details: ", result.scormError))), result.webhookStatus && result.webhookStatus !== "idle" && /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-lg" }, "Webhook Sync Status")), /* @__PURE__ */ React169__default.createElement(CardContent, null, /* @__PURE__ */ React169__default.createElement("p", { className: `flex items-center ${result.webhookStatus === "error" ? "text-destructive" : "text-muted-foreground"}` }, result.webhookStatus === "error" && /* @__PURE__ */ React169__default.createElement(TriangleAlert, { className: "mr-2 h-4 w-4" }), "Status: ", /* @__PURE__ */ React169__default.createElement("span", { className: "font-semibold ml-1" }, result.webhookStatus)), result.webhookError && /* @__PURE__ */ React169__default.createElement("p", { className: "text-xs text-destructive mt-1" }, "Details: ", result.webhookError))), /* @__PURE__ */ React169__default.createElement(Accordion2, { type: "single", collapsible: true, className: "w-full" }, /* @__PURE__ */ React169__default.createElement(AccordionItem2, { value: "question-breakdown" }, /* @__PURE__ */ React169__default.createElement(AccordionTrigger2, { className: "text-lg font-semibold" }, t4("practiceFlow.results.questionBreakdown")), /* @__PURE__ */ React169__default.createElement(AccordionContent2, null, /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-[300px] pr-4" }, /* @__PURE__ */ React169__default.createElement("ul", { className: "space-y-4" }, result.questionResults.map((qResult, index3) => /* @__PURE__ */ React169__default.createElement("li", { key: qResult.questionId, className: "p-4 border rounded-md bg-background" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-semibold" }, t4("common.questions", { count: index3 + 1 })), qResult.isCorrect ? /* @__PURE__ */ React169__default.createElement("span", { className: "text-green-600 font-
|
|
96907
|
+
return /* @__PURE__ */ React169__default.createElement(Card, { className: "w-full max-w-3xl mx-auto shadow-xl" }, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-3xl font-headline text-center" }, t4("practiceFlow.results.title", { quizTitle })), /* @__PURE__ */ React169__default.createElement(CardDescription, { className: "text-center text-lg" }, t4("practiceFlow.results.description"))), /* @__PURE__ */ React169__default.createElement(CardContent, { className: "space-y-6" }, /* @__PURE__ */ React169__default.createElement(Card, { className: "bg-secondary/50" }, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-xl flex items-center" }, /* @__PURE__ */ React169__default.createElement(BarChart2, { className: "mr-2 h-5 w-5 text-primary" }), t4("practiceFlow.results.overallScore"))), /* @__PURE__ */ React169__default.createElement(CardContent, { className: "grid grid-cols-1 md:grid-cols-3 gap-4 text-center" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("p", { className: "text-3xl font-bold text-primary" }, result.score, " / ", result.maxScore), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("practiceFlow.results.points"))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("p", { className: "text-3xl font-bold text-primary" }, result.percentage.toFixed(2), "%"), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("practiceFlow.results.percentage"))), /* @__PURE__ */ React169__default.createElement("div", null, result.passed !== void 0 && (result.passed ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex flex-col items-center text-green-600" }, /* @__PURE__ */ React169__default.createElement(CircleCheckBig, { className: "h-10 w-10" }), /* @__PURE__ */ React169__default.createElement("p", { className: "text-xl font-semibold mt-1" }, t4("practiceFlow.results.passed"))) : /* @__PURE__ */ React169__default.createElement("div", { className: "flex flex-col items-center text-destructive" }, /* @__PURE__ */ React169__default.createElement(CircleX, { className: "h-10 w-10" }), /* @__PURE__ */ React169__default.createElement("p", { className: "text-xl font-semibold mt-1" }, t4("practiceFlow.results.failed"))))))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 text-sm" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center space-x-2 p-3 bg-muted rounded-md" }, /* @__PURE__ */ React169__default.createElement(Clock, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ React169__default.createElement("span", null, t4("practiceFlow.results.timeSpent")), /* @__PURE__ */ React169__default.createElement("span", { className: "font-semibold" }, result.totalTimeSpentSeconds?.toFixed(0) ?? "N/A", " ", t4("practiceFlow.results.timeUnit"))), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center space-x-2 p-3 bg-muted rounded-md" }, /* @__PURE__ */ React169__default.createElement(Percent, { className: "h-5 w-5 text-primary" }), /* @__PURE__ */ React169__default.createElement("span", null, t4("practiceFlow.results.avgTimePerQuestion")), /* @__PURE__ */ React169__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__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-lg" }, "SCORM Sync Status")), /* @__PURE__ */ React169__default.createElement(CardContent, null, /* @__PURE__ */ React169__default.createElement("p", { className: `flex items-center ${result.scormStatus === "error" ? "text-destructive" : "text-muted-foreground"}` }, result.scormStatus === "error" && /* @__PURE__ */ React169__default.createElement(TriangleAlert, { className: "mr-2 h-4 w-4" }), "Status: ", /* @__PURE__ */ React169__default.createElement("span", { className: "font-semibold ml-1" }, result.scormStatus)), result.scormError && /* @__PURE__ */ React169__default.createElement("p", { className: "text-xs text-destructive mt-1" }, "Details: ", result.scormError))), result.webhookStatus && result.webhookStatus !== "idle" && /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-lg" }, "Webhook Sync Status")), /* @__PURE__ */ React169__default.createElement(CardContent, null, /* @__PURE__ */ React169__default.createElement("p", { className: `flex items-center ${result.webhookStatus === "error" ? "text-destructive" : "text-muted-foreground"}` }, result.webhookStatus === "error" && /* @__PURE__ */ React169__default.createElement(TriangleAlert, { className: "mr-2 h-4 w-4" }), "Status: ", /* @__PURE__ */ React169__default.createElement("span", { className: "font-semibold ml-1" }, result.webhookStatus)), result.webhookError && /* @__PURE__ */ React169__default.createElement("p", { className: "text-xs text-destructive mt-1" }, "Details: ", result.webhookError))), /* @__PURE__ */ React169__default.createElement(Accordion2, { type: "single", collapsible: true, className: "w-full" }, /* @__PURE__ */ React169__default.createElement(AccordionItem2, { value: "question-breakdown" }, /* @__PURE__ */ React169__default.createElement(AccordionTrigger2, { className: "text-lg font-semibold" }, t4("practiceFlow.results.questionBreakdown")), /* @__PURE__ */ React169__default.createElement(AccordionContent2, null, /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-[300px] pr-4" }, /* @__PURE__ */ React169__default.createElement("ul", { className: "space-y-4" }, result.questionResults.map((qResult, index3) => /* @__PURE__ */ React169__default.createElement("li", { key: qResult.questionId, className: "p-4 border rounded-md bg-background" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-between items-center mb-2" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-semibold" }, t4("common.questions", { count: index3 + 1 })), qResult.isCorrect ? /* @__PURE__ */ React169__default.createElement("span", { className: "text-green-600 font-Medium flex items-center" }, /* @__PURE__ */ React169__default.createElement(CircleCheckBig, { className: "mr-1 h-4 w-4" }), " ", t4("practiceFlow.results.passed")) : /* @__PURE__ */ React169__default.createElement("span", { className: "text-destructive font-Medium flex items-center" }, /* @__PURE__ */ React169__default.createElement(CircleX, { className: "mr-1 h-4 w-4" }), " ", t4("practiceFlow.results.failed"))), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm" }, /* @__PURE__ */ React169__default.createElement("span", { className: "font-Medium" }, t4("practiceFlow.results.yourAnswer")), " ", getAnswerDisplay(qResult.userAnswer)), !qResult.isCorrect && /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm" }, /* @__PURE__ */ React169__default.createElement("span", { className: "font-Medium" }, t4("practiceFlow.results.correctAnswer")), " ", getAnswerDisplay(qResult.correctAnswer)), /* @__PURE__ */ React169__default.createElement("p", { className: "text-xs text-muted-foreground" }, /* @__PURE__ */ React169__default.createElement("span", { className: "font-Medium" }, t4("practiceFlow.results.pointsEarned")), " ", qResult.pointsEarned), /* @__PURE__ */ React169__default.createElement("p", { className: "text-xs text-muted-foreground" }, /* @__PURE__ */ React169__default.createElement("span", { className: "font-Medium" }, t4("practiceFlow.results.timeSpent")), " ", qResult.timeSpentSeconds?.toFixed(0) ?? "N/A", t4("practiceFlow.results.timeUnit")))))))))), /* @__PURE__ */ React169__default.createElement(CardFooter, { className: "flex flex-col sm:flex-row justify-between gap-2" }, onExitQuiz && /* @__PURE__ */ React169__default.createElement(Button, { variant: "outline", onClick: onExitQuiz, className: "w-full sm:w-auto" }, /* @__PURE__ */ React169__default.createElement(LogOut, { className: "mr-2 h-4 w-4" }), t4("common.exit")), showReviewButton && onGenerateReview && /* @__PURE__ */ React169__default.createElement(
|
|
96908
96908
|
Button,
|
|
96909
96909
|
{
|
|
96910
96910
|
onClick: onGenerateReview,
|
|
@@ -97219,7 +97219,7 @@ var QuizDataManagement = ({ onQuizLoad, currentQuiz }) => {
|
|
|
97219
97219
|
});
|
|
97220
97220
|
}
|
|
97221
97221
|
};
|
|
97222
|
-
return /* @__PURE__ */ React169__default.createElement(Card, { className: "w-full shadow-lg" }, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, null, "Quiz Data Management"), /* @__PURE__ */ React169__default.createElement(CardDescription, null, "Import a quiz from a JSON file or export the current quiz configuration.")), /* @__PURE__ */ React169__default.createElement(CardContent, { className: "space-y-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex flex-col gap-2 mb-4" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "quiz-file-input", className: "text-sm font-
|
|
97222
|
+
return /* @__PURE__ */ React169__default.createElement(Card, { className: "w-full shadow-lg" }, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, null, "Quiz Data Management"), /* @__PURE__ */ React169__default.createElement(CardDescription, null, "Import a quiz from a JSON file or export the current quiz configuration.")), /* @__PURE__ */ React169__default.createElement(CardContent, { className: "space-y-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex flex-col gap-2 mb-4" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "quiz-file-input", className: "text-sm font-Medium" }, "Import Quiz (JSON)"), /* @__PURE__ */ React169__default.createElement("div", { className: "relative" }, /* @__PURE__ */ React169__default.createElement(
|
|
97223
97223
|
Input,
|
|
97224
97224
|
{
|
|
97225
97225
|
id: "quiz-file-input",
|
|
@@ -97227,7 +97227,7 @@ var QuizDataManagement = ({ onQuizLoad, currentQuiz }) => {
|
|
|
97227
97227
|
accept: ".json",
|
|
97228
97228
|
ref: fileInputRef,
|
|
97229
97229
|
onChange: handleFileChange,
|
|
97230
|
-
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-
|
|
97230
|
+
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"
|
|
97231
97231
|
}
|
|
97232
97232
|
))), error && /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-destructive flex items-center" }, /* @__PURE__ */ React169__default.createElement(CircleAlert, { className: "mr-1 h-4 w-4" }), " ", error)), /* @__PURE__ */ React169__default.createElement(CardFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleExportQuiz, disabled: !currentQuiz, variant: "outline" }, /* @__PURE__ */ React169__default.createElement(Download, { className: "mr-2 h-4 w-4" }), " Export Current Quiz")));
|
|
97233
97233
|
};
|
|
@@ -97662,6 +97662,7 @@ var Close = DialogClose;
|
|
|
97662
97662
|
|
|
97663
97663
|
// src/react-ui/components/elements/dialog.tsx
|
|
97664
97664
|
var Dialog2 = Root10;
|
|
97665
|
+
var DialogTrigger2 = Trigger4;
|
|
97665
97666
|
var DialogPortal2 = Portal3;
|
|
97666
97667
|
var DialogClose2 = Close;
|
|
97667
97668
|
var DialogOverlay2 = React169.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ React169.createElement(
|
|
@@ -97860,7 +97861,7 @@ var CommandGroup = React169.forwardRef(({ className, ...props }, ref) => /* @__P
|
|
|
97860
97861
|
{
|
|
97861
97862
|
ref,
|
|
97862
97863
|
className: cn(
|
|
97863
|
-
"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-
|
|
97864
|
+
"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",
|
|
97864
97865
|
className
|
|
97865
97866
|
),
|
|
97866
97867
|
...props
|
|
@@ -98261,7 +98262,7 @@ var TrueFalseQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98261
98262
|
const handleCorrectAnswerChange = (value) => {
|
|
98262
98263
|
onFormChange({ correctAnswer: value === "true" });
|
|
98263
98264
|
};
|
|
98264
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
98265
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "True/False Specifics"), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Correct Answer"), /* @__PURE__ */ React169__default.createElement(
|
|
98265
98266
|
RadioGroup2,
|
|
98266
98267
|
{
|
|
98267
98268
|
value: question2.correctAnswer ? "true" : "false",
|
|
@@ -98298,7 +98299,7 @@ var MultipleChoiceQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98298
98299
|
const handleCorrectAnswerChange = (optionId) => {
|
|
98299
98300
|
onFormChange({ correctAnswerId: optionId });
|
|
98300
98301
|
};
|
|
98301
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
98302
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "Multiple Choice Specifics"), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Options"), question2.options.length === 0 && /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground mt-1" }, "No options added yet."), /* @__PURE__ */ React169__default.createElement(
|
|
98302
98303
|
RadioGroup2,
|
|
98303
98304
|
{
|
|
98304
98305
|
value: question2.correctAnswerId,
|
|
@@ -98360,7 +98361,7 @@ var MultipleResponseQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98360
98361
|
const newCorrectAnswerIds = question2.correctAnswerIds.filter((id3) => id3 !== optionIdToDelete);
|
|
98361
98362
|
onFormChange({ options: newOptions, correctAnswerIds: newCorrectAnswerIds });
|
|
98362
98363
|
};
|
|
98363
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
98364
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "Multiple Response Specifics"), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Options (Select all correct answers)"), question2.options.length === 0 && /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground mt-1" }, "No options added yet."), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3 mt-2" }, question2.options.map((option, index3) => (
|
|
98364
98365
|
// *** CHANGED: Adjusted layout for SimpleMarkdownEditor ***
|
|
98365
98366
|
/* @__PURE__ */ React169__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__default.createElement(
|
|
98366
98367
|
Checkbox2,
|
|
@@ -98582,7 +98583,7 @@ var ShortAnswerQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98582
98583
|
const toggleCaseSensitive = (checked) => {
|
|
98583
98584
|
onFormChange({ isCaseSensitive: checked });
|
|
98584
98585
|
};
|
|
98585
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
98586
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "Short Answer Specifics"), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Accepted Answers"), /* @__PURE__ */ React169__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__default.createElement("p", { className: "text-sm text-muted-foreground mt-1" }, "No accepted answers defined yet."), question2.acceptedAnswers.map((answer, index3) => /* @__PURE__ */ React169__default.createElement("div", { key: index3, className: "flex items-center space-x-2" }, /* @__PURE__ */ React169__default.createElement(
|
|
98586
98587
|
Input,
|
|
98587
98588
|
{
|
|
98588
98589
|
type: "text",
|
|
@@ -98632,7 +98633,7 @@ var NumericQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98632
98633
|
onFormChange({ tolerance: numValue });
|
|
98633
98634
|
}
|
|
98634
98635
|
};
|
|
98635
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
98636
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "Numeric Question Specifics"), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: `num-answer-${question2.id}` }, "Correct Numerical Answer"), /* @__PURE__ */ React169__default.createElement(
|
|
98636
98637
|
Input,
|
|
98637
98638
|
{
|
|
98638
98639
|
id: `num-answer-${question2.id}`,
|
|
@@ -98745,7 +98746,7 @@ var FillInTheBlanksQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98745
98746
|
const toggleCaseSensitive = (checked) => {
|
|
98746
98747
|
onFormChange({ isCaseSensitive: checked });
|
|
98747
98748
|
};
|
|
98748
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
98749
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "Fill In The Blanks Specifics"), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Question Segments"), /* @__PURE__ */ React169__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__default.createElement("div", { key: `segment-${index3}`, className: "flex items-start space-x-2 mt-2 p-2 border rounded-md bg-background" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex-grow space-y-1" }, /* @__PURE__ */ React169__default.createElement("span", { className: "text-xs font-Medium capitalize text-muted-foreground" }, segment.type, " Segment ", index3 + 1), segment.type === "text" ? (
|
|
98749
98750
|
// *** CHANGED: Replaced Textarea with SimpleMarkdownEditor ***
|
|
98750
98751
|
/* @__PURE__ */ React169__default.createElement(
|
|
98751
98752
|
SimpleMarkdownEditor,
|
|
@@ -98818,7 +98819,7 @@ var SequenceQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98818
98819
|
}
|
|
98819
98820
|
return htmlString.replace(/<[^>]*>?/gm, "");
|
|
98820
98821
|
};
|
|
98821
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
98822
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "Sequence Question Specifics"), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Sequence Items"), /* @__PURE__ */ React169__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__default.createElement("div", { className: "space-y-3 mt-2" }, question2.items.map((item, index3) => /* @__PURE__ */ React169__default.createElement("div", { key: item.id, className: "flex items-start space-x-2 p-2 border rounded-md bg-background" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex-grow" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "text-xs font-Medium text-muted-foreground" }, "Item ", index3 + 1), /* @__PURE__ */ React169__default.createElement(
|
|
98822
98823
|
SimpleMarkdownEditor,
|
|
98823
98824
|
{
|
|
98824
98825
|
value: item.content,
|
|
@@ -98921,7 +98922,7 @@ var MatchingQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
98921
98922
|
}
|
|
98922
98923
|
return htmlString.replace(/<[^>]*>?/gm, "");
|
|
98923
98924
|
};
|
|
98924
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
98925
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "Matching Question Specifics"), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Prompts (Items to be matched)"), question2.prompts.map((promptItem, index3) => /* @__PURE__ */ React169__default.createElement("div", { key: promptItem.id, className: "space-y-1" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "text-xs text-muted-foreground" }, "Prompt ", index3 + 1), /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => handleDeletePrompt(index3), className: "h-7 w-7 text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" }))), /* @__PURE__ */ React169__default.createElement(
|
|
98925
98926
|
SimpleMarkdownEditor,
|
|
98926
98927
|
{
|
|
98927
98928
|
value: promptItem.content,
|
|
@@ -99011,7 +99012,7 @@ var DragAndDropQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
99011
99012
|
}
|
|
99012
99013
|
return htmlString.replace(/<[^>]*>?/gm, "");
|
|
99013
99014
|
};
|
|
99014
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
99015
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "Drag and Drop Question Specifics"), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: `dnd-bgimage-${question2.id}` }, "Background Image URL (Optional)"), /* @__PURE__ */ React169__default.createElement(
|
|
99015
99016
|
Input,
|
|
99016
99017
|
{
|
|
99017
99018
|
id: `dnd-bgimage-${question2.id}`,
|
|
@@ -99098,7 +99099,7 @@ var HotspotQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
99098
99099
|
}
|
|
99099
99100
|
onFormChange({ correctHotspotIds: newCorrectIds });
|
|
99100
99101
|
};
|
|
99101
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
99102
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "Hotspot Question Specifics"), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: `hs-imageurl-${question2.id}` }, "Image URL"), /* @__PURE__ */ React169__default.createElement(
|
|
99102
99103
|
Input,
|
|
99103
99104
|
{
|
|
99104
99105
|
id: `hs-imageurl-${question2.id}`,
|
|
@@ -99116,7 +99117,7 @@ var HotspotQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
99116
99117
|
onChange: (e3) => onFormChange({ imageAltText: e3.target.value || void 0 }),
|
|
99117
99118
|
placeholder: "Describe the image"
|
|
99118
99119
|
}
|
|
99119
|
-
)), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Hotspot Areas"), /* @__PURE__ */ React169__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__default.createElement("div", { key: hotspot.id, className: "p-3 border rounded-md bg-background space-y-2" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-
|
|
99120
|
+
)), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Hotspot Areas"), /* @__PURE__ */ React169__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__default.createElement("div", { key: hotspot.id, className: "p-3 border rounded-md bg-background space-y-2" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-Medium" }, "Hotspot ", index3 + 1, " (ID: ", hotspot.id, ")"), /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => handleDeleteHotspot(index3), className: "h-8 w-8 text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: `hs-shape-${hotspot.id}`, className: "text-xs" }, "Shape"), /* @__PURE__ */ React169__default.createElement(Select2, { value: hotspot.shape, onValueChange: (value) => handleHotspotChange(index3, "shape", value) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: `hs-shape-${hotspot.id}` }, /* @__PURE__ */ React169__default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "rect" }, "Rectangle"), /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "circle" }, "Circle")))), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React169__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__default.createElement(
|
|
99120
99121
|
Input,
|
|
99121
99122
|
{
|
|
99122
99123
|
id: `hs-coords-${hotspot.id}`,
|
|
@@ -99148,7 +99149,7 @@ var BlocklyProgrammingQuestionForm = ({ question: question2, onFormChange }) =>
|
|
|
99148
99149
|
const handleFieldChange = (field, value) => {
|
|
99149
99150
|
onFormChange({ [field]: value });
|
|
99150
99151
|
};
|
|
99151
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
99152
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "Blockly Programming Specifics"), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: `blockly-toolbox-${question2.id}` }, "Toolbox Definition (XML)"), /* @__PURE__ */ React169__default.createElement(
|
|
99152
99153
|
Textarea,
|
|
99153
99154
|
{
|
|
99154
99155
|
id: `blockly-toolbox-${question2.id}`,
|
|
@@ -99197,7 +99198,7 @@ var ScratchProgrammingQuestionForm = ({ question: question2, onFormChange }) =>
|
|
|
99197
99198
|
const handleFieldChange = (field, value) => {
|
|
99198
99199
|
onFormChange({ [field]: value });
|
|
99199
99200
|
};
|
|
99200
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
99201
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "Scratch Programming Specifics"), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "scratch-toolbox-" + question2.id }, "Toolbox Definition (XML for Blockly)"), /* @__PURE__ */ React169__default.createElement(
|
|
99201
99202
|
Textarea,
|
|
99202
99203
|
{
|
|
99203
99204
|
id: "scratch-toolbox-" + question2.id,
|
|
@@ -99274,7 +99275,7 @@ var CodingQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
99274
99275
|
const newTestCases = question2.testCases.filter((_2, i2) => i2 !== index3);
|
|
99275
99276
|
onFormChange({ testCases: newTestCases });
|
|
99276
99277
|
};
|
|
99277
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-
|
|
99278
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4 border rounded-md bg-muted/30" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-Medium text-md" }, "Coding Question Specifics"), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: `coding-lang-${question2.id}` }, "Programming Language"), /* @__PURE__ */ React169__default.createElement(
|
|
99278
99279
|
Select2,
|
|
99279
99280
|
{
|
|
99280
99281
|
value: question2.codingLanguage,
|
|
@@ -99300,7 +99301,7 @@ var CodingQuestionForm = ({ question: question2, onFormChange }) => {
|
|
|
99300
99301
|
placeholder: "Enter the complete, correct code solution here.",
|
|
99301
99302
|
className: "min-h-[200px] font-mono text-xs"
|
|
99302
99303
|
}
|
|
99303
|
-
)), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Test Cases"), question2.testCases.map((tc, index3) => /* @__PURE__ */ React169__default.createElement("div", { key: tc.id, className: "p-3 border rounded-md bg-background space-y-2" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-
|
|
99304
|
+
)), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Test Cases"), question2.testCases.map((tc, index3) => /* @__PURE__ */ React169__default.createElement("div", { key: tc.id, className: "p-3 border rounded-md bg-background space-y-2" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-Medium" }, "Test Case ", index3 + 1), /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => handleDeleteTestCase(index3), className: "h-8 w-8 text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-1" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: `tc-input-${tc.id}`, className: "text-xs" }, "Input (JSON Array)"), /* @__PURE__ */ React169__default.createElement(
|
|
99304
99305
|
Input,
|
|
99305
99306
|
{
|
|
99306
99307
|
id: `tc-input-${tc.id}`,
|
|
@@ -99468,7 +99469,7 @@ var EditQuestionModal = ({
|
|
|
99468
99469
|
if (!isOpen || !editedQuestion) return null;
|
|
99469
99470
|
return /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => {
|
|
99470
99471
|
if (!open) onClose();
|
|
99471
|
-
} }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-[600px] md:max-w-[800px] lg:max-w-[1000px] max-h-[90vh]" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__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__default.createElement(DialogDescription2, null, "Configure the details for this question. Current type:", " ", /* @__PURE__ */ React169__default.createElement("span", { className: "font-semibold" }, editedQuestion.questionType))), /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "max-h-[calc(80vh-150px)] p-1 pr-6" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "prompt", className: "font-semibold" }, "Question Prompt"), /* @__PURE__ */ React169__default.createElement(SimpleMarkdownEditor, { value: editedQuestion.prompt, onChange: (htmlContent) => handleSpecificFieldChange({ prompt: htmlContent }) })), renderSpecificForm(), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "points" }, "Points"), /* @__PURE__ */ React169__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__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "difficulty" }, "Difficulty"), /* @__PURE__ */ React169__default.createElement(Select2, { value: editedQuestion.difficulty || "
|
|
99472
|
+
} }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-[600px] md:max-w-[800px] lg:max-w-[1000px] max-h-[90vh]" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__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__default.createElement(DialogDescription2, null, "Configure the details for this question. Current type:", " ", /* @__PURE__ */ React169__default.createElement("span", { className: "font-semibold" }, editedQuestion.questionType))), /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "max-h-[calc(80vh-150px)] p-1 pr-6" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6 p-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "prompt", className: "font-semibold" }, "Question Prompt"), /* @__PURE__ */ React169__default.createElement(SimpleMarkdownEditor, { value: editedQuestion.prompt, onChange: (htmlContent) => handleSpecificFieldChange({ prompt: htmlContent }) })), renderSpecificForm(), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "points" }, "Points"), /* @__PURE__ */ React169__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__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "difficulty" }, "Difficulty"), /* @__PURE__ */ React169__default.createElement(Select2, { value: editedQuestion.difficulty || "Medium", onValueChange: (value) => handleSpecificFieldChange({ difficulty: value }) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "Easy" }, "Easy"), /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "Medium" }, "Medium"), /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "Hard" }, "Hard"))))), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "explanation" }, "Explanation (Optional)"), /* @__PURE__ */ React169__default.createElement(SimpleMarkdownEditor, { value: editedQuestion.explanation || "", onChange: (htmlContent) => handleSpecificFieldChange({ explanation: htmlContent }), minHeight: "100px" })), /* @__PURE__ */ React169__default.createElement("details", { className: "group", open: hasDropdownMetadata }, /* @__PURE__ */ React169__default.createElement("summary", { className: "cursor-pointer font-semibold text-primary hover:underline" }, "Advanced Metadata (Optional)"), renderMetadataFields()))), /* @__PURE__ */ React169__default.createElement(DialogFooter, { className: "pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline" }, "Cancel")), /* @__PURE__ */ React169__default.createElement(Button, { type: "button", onClick: handleSaveClick }, /* @__PURE__ */ React169__default.createElement(Save, { className: "mr-2 h-4 w-4" }), " Save Question"))));
|
|
99472
99473
|
};
|
|
99473
99474
|
|
|
99474
99475
|
// src/react-ui/components/authoring/AIQuestionGeneratorModal.tsx
|
|
@@ -99618,12 +99619,12 @@ var QuizContextSchema = z.object({
|
|
|
99618
99619
|
originalSubject: z.string().optional(),
|
|
99619
99620
|
originalCategory: z.string().optional(),
|
|
99620
99621
|
originalTopic: z.string().optional(),
|
|
99621
|
-
|
|
99622
|
+
description: z.string().optional().describe("The full description of the learning objective for deep context."),
|
|
99622
99623
|
gradeBand: z.string().optional()
|
|
99623
99624
|
});
|
|
99624
99625
|
var BaseQuestionGenerationClientInputSchema = z.object({
|
|
99625
99626
|
language: z.string().optional().default("English"),
|
|
99626
|
-
difficulty: z.enum(["
|
|
99627
|
+
difficulty: z.enum(["Easy", "Medium", "Hard"]),
|
|
99627
99628
|
quizContext: QuizContextSchema.optional(),
|
|
99628
99629
|
imageUrl: z.string().url().optional().describe("Optional URL of an image to be used as context.")
|
|
99629
99630
|
});
|
|
@@ -99632,7 +99633,7 @@ var BaseQuestionZodSchema = z.object({
|
|
|
99632
99633
|
prompt: z.string().min(1),
|
|
99633
99634
|
points: z.number().min(0).optional(),
|
|
99634
99635
|
explanation: z.string().optional(),
|
|
99635
|
-
difficulty: z.enum(["
|
|
99636
|
+
difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
99636
99637
|
topic: z.string().optional(),
|
|
99637
99638
|
category: z.string().optional(),
|
|
99638
99639
|
subject: z.string().optional(),
|
|
@@ -99728,7 +99729,7 @@ var AITrueFalseOutputFieldsSchema = z.object({
|
|
|
99728
99729
|
correctAnswer: z.boolean(),
|
|
99729
99730
|
explanation: z.string().optional().describe("An explanation of why the statement is true or false, especially important if false."),
|
|
99730
99731
|
points: z.number().optional().default(10),
|
|
99731
|
-
difficulty: z.enum(["
|
|
99732
|
+
difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
99732
99733
|
topic: z.string().optional(),
|
|
99733
99734
|
verifiedCategory: z.string().optional()
|
|
99734
99735
|
// Thêm để xác thực
|
|
@@ -99749,7 +99750,7 @@ Previous attempts failed. Ensure the JSON is valid and 'correctAnswer' is a bool
|
|
|
99749
99750
|
const misconceptionGuidance = quizContext?.targetMisconception ? `**Target Misconception:** The statement you create MUST be FALSE and based on this common mistake: "${quizContext.targetMisconception}"` : "";
|
|
99750
99751
|
const contextStrings = [
|
|
99751
99752
|
`**Required Category:** ${category}`,
|
|
99752
|
-
quizContext?.
|
|
99753
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
99753
99754
|
imageContextInstruction,
|
|
99754
99755
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
99755
99756
|
misconceptionGuidance,
|
|
@@ -99760,7 +99761,7 @@ Previous attempts failed. Ensure the JSON is valid and 'correctAnswer' is a bool
|
|
|
99760
99761
|
correctAnswer: true,
|
|
99761
99762
|
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 '!'.",
|
|
99762
99763
|
points: 10,
|
|
99763
|
-
difficulty: "
|
|
99764
|
+
difficulty: "Easy",
|
|
99764
99765
|
topic: "Swift Optionals",
|
|
99765
99766
|
verifiedCategory: category
|
|
99766
99767
|
}, null, 2);
|
|
@@ -99896,7 +99897,7 @@ var AIMCQOutputFieldsSchema = z.object({
|
|
|
99896
99897
|
correctTempOptionId: z.string().describe("The temporary ID of the correct option from the generated options array."),
|
|
99897
99898
|
explanation: z.string().optional().describe("A brief explanation of why the answer is correct."),
|
|
99898
99899
|
points: z.number().optional().default(10),
|
|
99899
|
-
difficulty: z.enum(["
|
|
99900
|
+
difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
99900
99901
|
topic: z.string().optional(),
|
|
99901
99902
|
verifiedCategory: z.string().optional().describe("The category this question actually addresses.")
|
|
99902
99903
|
});
|
|
@@ -99915,7 +99916,7 @@ Previous attempts failed...
|
|
|
99915
99916
|
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.` : "";
|
|
99916
99917
|
const contextStrings = [
|
|
99917
99918
|
`**Required Category:** ${category}`,
|
|
99918
|
-
quizContext?.
|
|
99919
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
99919
99920
|
imageContextInstruction,
|
|
99920
99921
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
99921
99922
|
quizContext?.targetMisconception && `**Target Misconception:** Use this to create plausible incorrect answers: "${quizContext.targetMisconception}"`,
|
|
@@ -99932,7 +99933,7 @@ Previous attempts failed...
|
|
|
99932
99933
|
correctTempOptionId: "C",
|
|
99933
99934
|
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.`,
|
|
99934
99935
|
points: 10,
|
|
99935
|
-
difficulty: "
|
|
99936
|
+
difficulty: "Easy",
|
|
99936
99937
|
topic: `Control Flow in ${category}`,
|
|
99937
99938
|
verifiedCategory: category
|
|
99938
99939
|
}, null, 2);
|
|
@@ -100080,7 +100081,7 @@ var AIMRQOutputFieldsSchema = z.object({
|
|
|
100080
100081
|
correctTempOptionIds: z.array(z.string()).min(1),
|
|
100081
100082
|
explanation: z.string().optional(),
|
|
100082
100083
|
points: z.number().optional().default(10),
|
|
100083
|
-
difficulty: z.enum(["
|
|
100084
|
+
difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
100084
100085
|
topic: z.string().optional(),
|
|
100085
100086
|
verifiedCategory: z.string().optional().describe("The category this question actually addresses.")
|
|
100086
100087
|
});
|
|
@@ -100099,7 +100100,7 @@ Previous attempts failed due to validation errors. Pay close attention to the nu
|
|
|
100099
100100
|
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.` : "";
|
|
100100
100101
|
const contextStrings = [
|
|
100101
100102
|
`**Required Category:** ${category} (This is the ONLY language to be used)`,
|
|
100102
|
-
quizContext?.
|
|
100103
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
100103
100104
|
imageContextInstruction,
|
|
100104
100105
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
100105
100106
|
quizContext?.targetMisconception && `**Target Misconception:** Use this to create plausible incorrect answers (distractors). The misconception is: "${quizContext.targetMisconception}"`,
|
|
@@ -100117,7 +100118,7 @@ Previous attempts failed due to validation errors. Pay close attention to the nu
|
|
|
100117
100118
|
correctTempOptionIds: ["A", "C", "D"],
|
|
100118
100119
|
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.",
|
|
100119
100120
|
points: 10,
|
|
100120
|
-
difficulty: "
|
|
100121
|
+
difficulty: "Medium",
|
|
100121
100122
|
topic: "Programming Paradigms",
|
|
100122
100123
|
verifiedCategory: category
|
|
100123
100124
|
}, null, 2);
|
|
@@ -100281,7 +100282,7 @@ var AIShortAnswerOutputFieldsSchema = z.object({
|
|
|
100281
100282
|
// isCaseSensitive không cần thiết ở đây, chúng ta sẽ quản lý nó ở phía client
|
|
100282
100283
|
explanation: z.string().optional(),
|
|
100283
100284
|
points: z.number().optional().default(10),
|
|
100284
|
-
difficulty: z.enum(["
|
|
100285
|
+
difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
100285
100286
|
topic: z.string().optional(),
|
|
100286
100287
|
verifiedCategory: z.string().optional()
|
|
100287
100288
|
// Thêm để xác thực
|
|
@@ -100301,7 +100302,7 @@ Previous attempts failed. Ensure 'acceptedAnswers' is a non-empty array of strin
|
|
|
100301
100302
|
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.` : "";
|
|
100302
100303
|
const contextStrings = [
|
|
100303
100304
|
`**Required Category:** ${category}`,
|
|
100304
|
-
quizContext?.
|
|
100305
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
100305
100306
|
imageContextInstruction,
|
|
100306
100307
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
100307
100308
|
quizContext?.targetMisconception && `**Target Misconception:** The question should require an answer that corrects this specific misconception: "${quizContext.targetMisconception}"`
|
|
@@ -100311,7 +100312,7 @@ Previous attempts failed. Ensure 'acceptedAnswers' is a non-empty array of strin
|
|
|
100311
100312
|
acceptedAnswers: ["let"],
|
|
100312
100313
|
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.",
|
|
100313
100314
|
points: 10,
|
|
100314
|
-
difficulty: "
|
|
100315
|
+
difficulty: "Easy",
|
|
100315
100316
|
topic: "Swift Constants",
|
|
100316
100317
|
verifiedCategory: category
|
|
100317
100318
|
}, null, 2);
|
|
@@ -100444,7 +100445,7 @@ var AINumericOutputFieldsSchema = z.object({
|
|
|
100444
100445
|
tolerance: z.number().min(0).optional(),
|
|
100445
100446
|
explanation: z.string().optional(),
|
|
100446
100447
|
points: z.number().optional().default(10),
|
|
100447
|
-
difficulty: z.enum(["
|
|
100448
|
+
difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
100448
100449
|
topic: z.string().optional(),
|
|
100449
100450
|
verifiedCategory: z.string().optional()
|
|
100450
100451
|
// Thêm để xác thực
|
|
@@ -100464,7 +100465,7 @@ Previous attempts failed. Ensure the 'answer' is a valid number and fits within
|
|
|
100464
100465
|
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.` : "";
|
|
100465
100466
|
const contextStrings = [
|
|
100466
100467
|
`**Required Category:** ${category}`,
|
|
100467
|
-
quizContext?.
|
|
100468
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
100468
100469
|
imageContextInstruction,
|
|
100469
100470
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
100470
100471
|
quizContext?.targetMisconception && `**Target Misconception:** The question should clarify this numerical error: "${quizContext.targetMisconception}"`
|
|
@@ -100480,7 +100481,7 @@ Previous attempts failed. Ensure the 'answer' is a valid number and fits within
|
|
|
100480
100481
|
tolerance: 0,
|
|
100481
100482
|
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).",
|
|
100482
100483
|
points: 10,
|
|
100483
|
-
difficulty: "
|
|
100484
|
+
difficulty: "Medium",
|
|
100484
100485
|
topic: "Swift Data Types",
|
|
100485
100486
|
verifiedCategory: category
|
|
100486
100487
|
}, null, 2);
|
|
@@ -100630,7 +100631,7 @@ var AIFillInTheBlanksOutputFieldsSchema = z.object({
|
|
|
100630
100631
|
})).min(1).describe("An array of text and blank segments representing the question."),
|
|
100631
100632
|
explanation: z.string().optional(),
|
|
100632
100633
|
points: z.number().optional().default(10),
|
|
100633
|
-
difficulty: z.enum(["
|
|
100634
|
+
difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
100634
100635
|
topic: z.string().optional(),
|
|
100635
100636
|
verifiedCategory: z.string().optional()
|
|
100636
100637
|
// Thêm để xác thực
|
|
@@ -100650,7 +100651,7 @@ Previous attempts failed. Pay strict attention to the JSON schema, especially th
|
|
|
100650
100651
|
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.` : "";
|
|
100651
100652
|
const contextStrings = [
|
|
100652
100653
|
`**Required Category:** ${category}`,
|
|
100653
|
-
quizContext?.
|
|
100654
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
100654
100655
|
imageContextInstruction,
|
|
100655
100656
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
100656
100657
|
quizContext?.targetMisconception && `**Target Misconception:** Design the blank to test this specific point: "${quizContext.targetMisconception}"`
|
|
@@ -100664,7 +100665,7 @@ Previous attempts failed. Pay strict attention to the JSON schema, especially th
|
|
|
100664
100665
|
],
|
|
100665
100666
|
explanation: "The 'func' keyword is used to declare a function in the Swift programming language.",
|
|
100666
100667
|
points: 10,
|
|
100667
|
-
difficulty: "
|
|
100668
|
+
difficulty: "Easy",
|
|
100668
100669
|
topic: "Swift Function Declaration",
|
|
100669
100670
|
verifiedCategory: category
|
|
100670
100671
|
}, null, 2);
|
|
@@ -100818,7 +100819,7 @@ var AISequenceOutputFieldsSchema = z.object({
|
|
|
100818
100819
|
itemsInCorrectOrder: z.array(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."),
|
|
100819
100820
|
explanation: z.string().optional(),
|
|
100820
100821
|
points: z.number().optional().default(10),
|
|
100821
|
-
difficulty: z.enum(["
|
|
100822
|
+
difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
100822
100823
|
topic: z.string().optional(),
|
|
100823
100824
|
verifiedCategory: z.string().optional()
|
|
100824
100825
|
// Thêm để xác thực
|
|
@@ -100838,7 +100839,7 @@ Previous attempts failed. Ensure the 'itemsInCorrectOrder' array has exactly the
|
|
|
100838
100839
|
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.` : "";
|
|
100839
100840
|
const contextStrings = [
|
|
100840
100841
|
`**Required Category:** ${category}`,
|
|
100841
|
-
quizContext?.
|
|
100842
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
100842
100843
|
imageContextInstruction,
|
|
100843
100844
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
100844
100845
|
quizContext?.targetMisconception && `**Target Misconception:** The sequence should clarify this specific process error: "${quizContext.targetMisconception}"`
|
|
@@ -100853,7 +100854,7 @@ Previous attempts failed. Ensure the 'itemsInCorrectOrder' array has exactly the
|
|
|
100853
100854
|
],
|
|
100854
100855
|
explanation: "This is the fundamental sequence for a basic data task in URLSession.",
|
|
100855
100856
|
points: 10,
|
|
100856
|
-
difficulty: "
|
|
100857
|
+
difficulty: "Medium",
|
|
100857
100858
|
topic: "Swift Networking",
|
|
100858
100859
|
verifiedCategory: category
|
|
100859
100860
|
}, null, 2);
|
|
@@ -100995,7 +100996,7 @@ var AIMatchingOutputFieldsSchema = z.object({
|
|
|
100995
100996
|
})).min(2),
|
|
100996
100997
|
explanation: z.string().optional(),
|
|
100997
100998
|
points: z.number().optional().default(10),
|
|
100998
|
-
difficulty: z.enum(["
|
|
100999
|
+
difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
100999
101000
|
topic: z.string().optional(),
|
|
101000
101001
|
verifiedCategory: z.string().optional()
|
|
101001
101002
|
// Thêm để xác thực
|
|
@@ -101015,7 +101016,7 @@ Previous attempts failed. Please ensure the 'correctPairs' array has exactly the
|
|
|
101015
101016
|
const imageContextInstruction = imageUrl ? `**Image Context:** You MUST analyze the provided image. The matching pairs must be directly related to the content of this image.` : "";
|
|
101016
101017
|
const contextStrings = [
|
|
101017
101018
|
`**Required Category:** ${category}`,
|
|
101018
|
-
quizContext?.
|
|
101019
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
101019
101020
|
imageContextInstruction,
|
|
101020
101021
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
101021
101022
|
quizContext?.targetMisconception && `**Target Misconception:** Design a pair that specifically tests this confusion: "${quizContext.targetMisconception}"`
|
|
@@ -101029,7 +101030,7 @@ Previous attempts failed. Please ensure the 'correctPairs' array has exactly the
|
|
|
101029
101030
|
],
|
|
101030
101031
|
explanation: "These are the fundamental characteristics of Swift's main collection types.",
|
|
101031
101032
|
points: 10,
|
|
101032
|
-
difficulty: "
|
|
101033
|
+
difficulty: "Easy",
|
|
101033
101034
|
topic: "Swift Collection Types",
|
|
101034
101035
|
verifiedCategory: category
|
|
101035
101036
|
}, null, 2);
|
|
@@ -101245,7 +101246,7 @@ var AIQuestionGeneratorModal = ({
|
|
|
101245
101246
|
};
|
|
101246
101247
|
const baseClientInput = {
|
|
101247
101248
|
language: language3,
|
|
101248
|
-
difficulty: "
|
|
101249
|
+
difficulty: "Medium",
|
|
101249
101250
|
quizContext
|
|
101250
101251
|
};
|
|
101251
101252
|
let generatedResult = {};
|
|
@@ -101850,10 +101851,6 @@ init_react_shim();
|
|
|
101850
101851
|
// src/services/TopicDataService.ts
|
|
101851
101852
|
init_react_shim();
|
|
101852
101853
|
var TopicDataService = class {
|
|
101853
|
-
/**
|
|
101854
|
-
* Saves an array of LearningObjective objects to Local Storage, overwriting existing data.
|
|
101855
|
-
* @param data The array of learning objectives to save.
|
|
101856
|
-
*/
|
|
101857
101854
|
static saveData(data) {
|
|
101858
101855
|
try {
|
|
101859
101856
|
if (typeof window === "undefined") return;
|
|
@@ -101863,24 +101860,15 @@ var TopicDataService = class {
|
|
|
101863
101860
|
console.error("Error saving learning objectives to Local Storage:", error);
|
|
101864
101861
|
}
|
|
101865
101862
|
}
|
|
101866
|
-
/**
|
|
101867
|
-
* Merges a new set of learning objectives with the existing data in Local Storage.
|
|
101868
|
-
* If an LO ID from newData already exists, it will be updated. Otherwise, it will be added.
|
|
101869
|
-
* @param newData The array of new or updated learning objectives.
|
|
101870
|
-
*/
|
|
101871
101863
|
static mergeData(newData) {
|
|
101872
101864
|
const existingData = this.getData();
|
|
101873
|
-
const loMap = new Map(existingData.map((lo) => [lo.
|
|
101865
|
+
const loMap = new Map(existingData.map((lo) => [lo.code, lo]));
|
|
101874
101866
|
newData.forEach((newLo) => {
|
|
101875
|
-
loMap.set(newLo.
|
|
101867
|
+
loMap.set(newLo.code, newLo);
|
|
101876
101868
|
});
|
|
101877
101869
|
const mergedData = Array.from(loMap.values());
|
|
101878
101870
|
this.saveData(mergedData);
|
|
101879
101871
|
}
|
|
101880
|
-
/**
|
|
101881
|
-
* Retrieves the array of LearningObjective objects from Local Storage.
|
|
101882
|
-
* @returns An array of learning objectives, or an empty array if none are found or an error occurs.
|
|
101883
|
-
*/
|
|
101884
101872
|
static getData() {
|
|
101885
101873
|
try {
|
|
101886
101874
|
if (typeof window === "undefined") return [];
|
|
@@ -101892,9 +101880,6 @@ var TopicDataService = class {
|
|
|
101892
101880
|
return [];
|
|
101893
101881
|
}
|
|
101894
101882
|
}
|
|
101895
|
-
/**
|
|
101896
|
-
* Removes all learning objective data from Local Storage.
|
|
101897
|
-
*/
|
|
101898
101883
|
static clearData() {
|
|
101899
101884
|
try {
|
|
101900
101885
|
if (typeof window === "undefined") return;
|
|
@@ -101903,11 +101888,6 @@ var TopicDataService = class {
|
|
|
101903
101888
|
console.error("Error clearing learning objectives from Local Storage:", error);
|
|
101904
101889
|
}
|
|
101905
101890
|
}
|
|
101906
|
-
/**
|
|
101907
|
-
* Parses TSV content into an array of LearningObjective objects.
|
|
101908
|
-
* @param tsvContent The raw string content from a .tsv file.
|
|
101909
|
-
* @returns An object containing the successfully parsed data and any errors encountered.
|
|
101910
|
-
*/
|
|
101911
101891
|
static parseTSV(tsvContent) {
|
|
101912
101892
|
const lines = tsvContent.split("\n").filter((line) => line.trim() !== "");
|
|
101913
101893
|
if (lines.length < 2) {
|
|
@@ -101929,6 +101909,7 @@ var TopicDataService = class {
|
|
|
101929
101909
|
}
|
|
101930
101910
|
const [
|
|
101931
101911
|
loId,
|
|
101912
|
+
name3,
|
|
101932
101913
|
loDescription,
|
|
101933
101914
|
subject,
|
|
101934
101915
|
category,
|
|
@@ -101938,18 +101919,21 @@ var TopicDataService = class {
|
|
|
101938
101919
|
stemElementsStr,
|
|
101939
101920
|
bloomLevelsStr
|
|
101940
101921
|
] = values;
|
|
101941
|
-
if (!loId || !subject || !category || !topic) {
|
|
101942
|
-
errors2.push(`Line ${index3 + 2}: Missing required fields (LO ID, Subject, Category, or Topic).`);
|
|
101922
|
+
if (!loId || !loDescription || !subject || !category || !topic) {
|
|
101923
|
+
errors2.push(`Line ${index3 + 2}: Missing required fields (LO ID, LO Description, Subject, Category, or Topic).`);
|
|
101943
101924
|
return;
|
|
101944
101925
|
}
|
|
101945
101926
|
const learningObjective = {
|
|
101946
|
-
|
|
101947
|
-
|
|
101927
|
+
id: generateUniqueId("lo_"),
|
|
101928
|
+
code: loId,
|
|
101929
|
+
name: name3,
|
|
101930
|
+
description: loDescription,
|
|
101931
|
+
// Can be the same as name or enhanced later
|
|
101948
101932
|
subject,
|
|
101949
101933
|
category,
|
|
101950
101934
|
topic,
|
|
101951
|
-
keywords: keywordsStr.split(",").map((k3) => k3.trim()).filter(Boolean),
|
|
101952
101935
|
grade,
|
|
101936
|
+
keywords: keywordsStr.split(",").map((k3) => k3.trim()).filter(Boolean),
|
|
101953
101937
|
stemElements: stemElementsStr.split(",").map((s4) => s4.trim()).filter(Boolean),
|
|
101954
101938
|
bloomLevelsGuideline: bloomLevelsStr.split(",").map((b2) => b2.trim()).filter(Boolean)
|
|
101955
101939
|
};
|
|
@@ -101957,40 +101941,21 @@ var TopicDataService = class {
|
|
|
101957
101941
|
});
|
|
101958
101942
|
return { data, errors: errors2 };
|
|
101959
101943
|
}
|
|
101960
|
-
/**
|
|
101961
|
-
* Gets a unique list of all subjects from the stored data.
|
|
101962
|
-
* @returns An array of subject strings.
|
|
101963
|
-
*/
|
|
101964
101944
|
static getSubjects() {
|
|
101965
101945
|
const data = this.getData();
|
|
101966
101946
|
const subjects = data.map((item) => item.subject);
|
|
101967
101947
|
return [...new Set(subjects)].sort();
|
|
101968
101948
|
}
|
|
101969
|
-
/**
|
|
101970
|
-
* Gets a unique list of categories for a given subject.
|
|
101971
|
-
* @param subject The subject to filter by.
|
|
101972
|
-
* @returns An array of category strings.
|
|
101973
|
-
*/
|
|
101974
101949
|
static getCategoriesBySubject(subject) {
|
|
101975
101950
|
const data = this.getData();
|
|
101976
101951
|
const categories = data.filter((item) => item.subject === subject).map((item) => item.category);
|
|
101977
101952
|
return [...new Set(categories)].sort();
|
|
101978
101953
|
}
|
|
101979
|
-
/**
|
|
101980
|
-
* Gets a unique list of topics for a given category.
|
|
101981
|
-
* @param category The category to filter by.
|
|
101982
|
-
* @returns An array of topic strings.
|
|
101983
|
-
*/
|
|
101984
101954
|
static getTopicsByCategory(category) {
|
|
101985
101955
|
const data = this.getData();
|
|
101986
101956
|
const topics = data.filter((item) => item.category === category).map((item) => item.topic);
|
|
101987
101957
|
return [...new Set(topics)].sort();
|
|
101988
101958
|
}
|
|
101989
|
-
/**
|
|
101990
|
-
* Retrieves all LearningObjective details for a given list of topics.
|
|
101991
|
-
* @param topics An array of topic strings to search for.
|
|
101992
|
-
* @returns An array of matching LearningObjective objects.
|
|
101993
|
-
*/
|
|
101994
101959
|
static getLearningObjectivesByTopics(topics) {
|
|
101995
101960
|
const data = this.getData();
|
|
101996
101961
|
const topicSet = new Set(topics);
|
|
@@ -102047,7 +102012,7 @@ Previous attempts failed. Pay strict attention to the JSON schema and all rules.
|
|
|
102047
102012
|
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.` : "";
|
|
102048
102013
|
const contextStrings = [
|
|
102049
102014
|
`**Subject:** ${subject}`,
|
|
102050
|
-
quizContext?.
|
|
102015
|
+
quizContext?.description && `**Learning Objective:** ${quizContext.description}`,
|
|
102051
102016
|
imageContextInstruction,
|
|
102052
102017
|
quizContext?.plannedBloomLevel && `**Cognitive Level (Bloom's):** ${quizContext.plannedBloomLevel}`,
|
|
102053
102018
|
quizContext?.targetMisconception && `**Target Misconception:** The problem should test against this common error: "${quizContext.targetMisconception}"`
|
|
@@ -102204,9 +102169,9 @@ var calculateCombinedDifficulty = (plannedQ) => {
|
|
|
102204
102169
|
break;
|
|
102205
102170
|
}
|
|
102206
102171
|
const totalScore = bloomScore + contextScore + questionTypeScore;
|
|
102207
|
-
if (totalScore <= 4) return "
|
|
102208
|
-
if (totalScore <= 7) return "
|
|
102209
|
-
return "
|
|
102172
|
+
if (totalScore <= 4) return "Easy";
|
|
102173
|
+
if (totalScore <= 7) return "Medium";
|
|
102174
|
+
return "Hard";
|
|
102210
102175
|
};
|
|
102211
102176
|
async function generateQuestionsFromQuizPlan(clientInput, apiKey) {
|
|
102212
102177
|
const { quizPlan, language: language3, imageContexts } = clientInput;
|
|
@@ -102219,7 +102184,7 @@ async function generateQuestionsFromQuizPlan(clientInput, apiKey) {
|
|
|
102219
102184
|
let lastError = null;
|
|
102220
102185
|
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
102221
102186
|
try {
|
|
102222
|
-
const fullLO = plannedQ.originalLoId ? allLearningObjectives.find((lo) => lo.
|
|
102187
|
+
const fullLO = plannedQ.originalLoId ? allLearningObjectives.find((lo) => lo.code === plannedQ.originalLoId) : null;
|
|
102223
102188
|
const quizContext = {
|
|
102224
102189
|
plannedTopic: plannedQ.plannedTopic,
|
|
102225
102190
|
plannedQuestionType: plannedQ.plannedQuestionType,
|
|
@@ -102232,7 +102197,7 @@ async function generateQuestionsFromQuizPlan(clientInput, apiKey) {
|
|
|
102232
102197
|
originalSubject: plannedQ.originalSubject,
|
|
102233
102198
|
originalCategory: plannedQ.originalCategory,
|
|
102234
102199
|
originalTopic: plannedQ.originalTopic,
|
|
102235
|
-
|
|
102200
|
+
description: fullLO?.description || plannedQ.plannedTopic
|
|
102236
102201
|
};
|
|
102237
102202
|
const imageUrl = plannedQ.imageId && imageContexts ? imageContexts.find((ctx) => ctx.id === plannedQ.imageId)?.imageUrl : void 0;
|
|
102238
102203
|
const baseClientInput = {
|
|
@@ -102586,7 +102551,7 @@ var AIFullQuizGeneratorModal = ({
|
|
|
102586
102551
|
};
|
|
102587
102552
|
const renderContent3 = () => {
|
|
102588
102553
|
if (currentStage === "review") {
|
|
102589
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 py-4" }, /* @__PURE__ */ React169__default.createElement("h3", { className: "text-lg font-
|
|
102554
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 py-4" }, /* @__PURE__ */ React169__default.createElement("h3", { className: "text-lg font-Medium mb-2 text-primary flex items-center" }, /* @__PURE__ */ React169__default.createElement(Eye, { className: "mr-2 h-5 w-5" }), " Review & Adjust AI Generated Quiz Plan"), /* @__PURE__ */ React169__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__default.createElement(ScrollArea2, { className: "max-h-[calc(60vh - 120px)] pr-3" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3" }, aiGeneratedPlan.map((plannedQ, index3) => /* @__PURE__ */ React169__default.createElement(Card, { key: `planned-${index3}-${plannedQ.plannedTopic.replace(/\s/g, "")}`, className: "p-3" }, /* @__PURE__ */ React169__default.createElement(CardContent, { className: "p-0 space-y-2" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-between items-start" }, /* @__PURE__ */ React169__default.createElement("p", { className: "font-semibold text-sm" }, "Q", index3 + 1, ": ", plannedQ.plannedTopic), /* @__PURE__ */ React169__default.createElement("div", { className: "flex space-x-1" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", onClick: () => handleMovePlannedQuestion(index3, "up"), disabled: index3 === 0 }, /* @__PURE__ */ React169__default.createElement(ArrowUp, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", onClick: () => handleMovePlannedQuestion(index3, "down"), disabled: index3 === aiGeneratedPlan.length - 1 }, /* @__PURE__ */ React169__default.createElement(ArrowDown, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", className: "h-7 w-7 text-destructive", onClick: () => handleRemovePlannedQuestion(index3) }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-2 gap-3 items-end" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: `review-qtype-${index3}`, className: "text-xs" }, "Question Type"), /* @__PURE__ */ React169__default.createElement(
|
|
102590
102555
|
Select2,
|
|
102591
102556
|
{
|
|
102592
102557
|
value: plannedQ.plannedQuestionType,
|
|
@@ -102615,7 +102580,7 @@ var AIFullQuizGeneratorModal = ({
|
|
|
102615
102580
|
min: "1",
|
|
102616
102581
|
max: "100"
|
|
102617
102582
|
}
|
|
102618
|
-
)), /* @__PURE__ */ React169__default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__default.createElement("legend", { className: "text-sm font-
|
|
102583
|
+
)), /* @__PURE__ */ React169__default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__default.createElement("legend", { className: "text-sm font-Medium px-1" }, "Topic Distribution"), topics.map((topicItem, index3) => /* @__PURE__ */ React169__default.createElement("div", { key: topicItem.id, className: "flex items-center gap-2 mb-2" }, /* @__PURE__ */ React169__default.createElement(
|
|
102619
102584
|
Input,
|
|
102620
102585
|
{
|
|
102621
102586
|
type: "text",
|
|
@@ -102635,7 +102600,7 @@ var AIFullQuizGeneratorModal = ({
|
|
|
102635
102600
|
min: "0",
|
|
102636
102601
|
max: "100"
|
|
102637
102602
|
}
|
|
102638
|
-
), /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => removeTopic(topicItem.id), disabled: topics.length <= 1 }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4 text-destructive" })))), /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", size: "sm", onClick: addTopic }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Topic")), /* @__PURE__ */ React169__default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__default.createElement("legend", { className: "text-sm font-
|
|
102603
|
+
), /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => removeTopic(topicItem.id), disabled: topics.length <= 1 }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4 text-destructive" })))), /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", size: "sm", onClick: addTopic }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Topic")), /* @__PURE__ */ React169__default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__default.createElement("legend", { className: "text-sm font-Medium px-1" }, "Bloom Level Distribution"), bloomLevels.map((bloomItem) => /* @__PURE__ */ React169__default.createElement("div", { key: bloomItem.id, className: "flex items-center gap-2 mb-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "w-32 capitalize flex-shrink-0" }, bloomItem.level), /* @__PURE__ */ React169__default.createElement(
|
|
102639
102604
|
Input,
|
|
102640
102605
|
{
|
|
102641
102606
|
type: "number",
|
|
@@ -102646,7 +102611,7 @@ var AIFullQuizGeneratorModal = ({
|
|
|
102646
102611
|
min: "0",
|
|
102647
102612
|
max: "100"
|
|
102648
102613
|
}
|
|
102649
|
-
)))), /* @__PURE__ */ React169__default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__default.createElement("legend", { className: "text-sm font-
|
|
102614
|
+
)))), /* @__PURE__ */ React169__default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__default.createElement("legend", { className: "text-sm font-Medium px-1" }, "Relevant Contexts (Optional, Select Multiple)"), /* @__PURE__ */ React169__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__default.createElement("div", { key: opt.contextId, className: "flex items-center space-x-2" }, /* @__PURE__ */ React169__default.createElement(
|
|
102650
102615
|
Checkbox2,
|
|
102651
102616
|
{
|
|
102652
102617
|
id: `ctx-full-${opt.contextId}`,
|
|
@@ -102668,7 +102633,7 @@ var AIFullQuizGeneratorModal = ({
|
|
|
102668
102633
|
placeholder: "Enter your specific custom context here...",
|
|
102669
102634
|
className: "min-h-[60px] mt-2 text-sm"
|
|
102670
102635
|
}
|
|
102671
|
-
)), /* @__PURE__ */ React169__default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__default.createElement("legend", { className: "text-sm font-
|
|
102636
|
+
)), /* @__PURE__ */ React169__default.createElement("fieldset", { className: "border p-3 rounded-md" }, /* @__PURE__ */ React169__default.createElement("legend", { className: "text-sm font-Medium px-1" }, "Question Types to Use (Select Multiple)"), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-2 gap-2 mt-2 max-h-40 overflow-y-auto" }, availableQuestionTypesForFullQuiz.map((qType) => /* @__PURE__ */ React169__default.createElement("div", { key: qType.value, className: "flex items-center space-x-2" }, /* @__PURE__ */ React169__default.createElement(
|
|
102672
102637
|
Checkbox2,
|
|
102673
102638
|
{
|
|
102674
102639
|
id: `qtype-full-${qType.value}`,
|
|
@@ -103068,7 +103033,7 @@ var AlertTitle = React169.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
103068
103033
|
"h5",
|
|
103069
103034
|
{
|
|
103070
103035
|
ref,
|
|
103071
|
-
className: cn("mb-1 font-
|
|
103036
|
+
className: cn("mb-1 font-Medium leading-none tracking-tight", className),
|
|
103072
103037
|
...props
|
|
103073
103038
|
}
|
|
103074
103039
|
));
|
|
@@ -103113,7 +103078,7 @@ var BaseRawQuestionSchema = z.object({
|
|
|
103113
103078
|
points: z.number().optional(),
|
|
103114
103079
|
explanation: z.string().optional(),
|
|
103115
103080
|
topic: z.string().optional(),
|
|
103116
|
-
difficulty: z.enum(["
|
|
103081
|
+
difficulty: z.enum(["Easy", "Medium", "Hard"]).optional(),
|
|
103117
103082
|
bloomLevel: z.string().optional()
|
|
103118
103083
|
});
|
|
103119
103084
|
var RawMCQSchema = BaseRawQuestionSchema.extend({
|
|
@@ -103466,7 +103431,7 @@ var QuizEditorService = class {
|
|
|
103466
103431
|
questionType: type,
|
|
103467
103432
|
prompt: "",
|
|
103468
103433
|
points: 10,
|
|
103469
|
-
difficulty: "
|
|
103434
|
+
difficulty: "Medium"
|
|
103470
103435
|
};
|
|
103471
103436
|
switch (type) {
|
|
103472
103437
|
case "true_false":
|
|
@@ -103693,7 +103658,7 @@ var SelectedQuestionsPanel = ({
|
|
|
103693
103658
|
},
|
|
103694
103659
|
/* @__PURE__ */ React169__default.createElement(ArrowDown, { className: "h-3 w-3" })
|
|
103695
103660
|
)),
|
|
103696
|
-
/* @__PURE__ */ React169__default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React169__default.createElement("div", { className: "font-
|
|
103661
|
+
/* @__PURE__ */ React169__default.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React169__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__default.createElement("div", { className: "text-xs text-muted-foreground mt-1" }, q2.questionType, " \u2022 ", q2.points || 0, " pts")),
|
|
103697
103662
|
/* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-1 flex-shrink-0" }, /* @__PURE__ */ React169__default.createElement(
|
|
103698
103663
|
Button,
|
|
103699
103664
|
{
|
|
@@ -104080,7 +104045,7 @@ var TableFooter = React169.forwardRef(({ className, ...props }, ref) => /* @__PU
|
|
|
104080
104045
|
{
|
|
104081
104046
|
ref,
|
|
104082
104047
|
className: cn(
|
|
104083
|
-
"border-t bg-muted/50 font-
|
|
104048
|
+
"border-t bg-muted/50 font-Medium [&>tr]:last:border-b-0",
|
|
104084
104049
|
className
|
|
104085
104050
|
),
|
|
104086
104051
|
...props
|
|
@@ -104104,7 +104069,7 @@ var TableHead = React169.forwardRef(({ className, ...props }, ref) => /* @__PURE
|
|
|
104104
104069
|
{
|
|
104105
104070
|
ref,
|
|
104106
104071
|
className: cn(
|
|
104107
|
-
"h-12 px-4 text-left align-middle font-
|
|
104072
|
+
"h-12 px-4 text-left align-middle font-Medium text-muted-foreground [&:has([role=checkbox])]:pr-0",
|
|
104108
104073
|
className
|
|
104109
104074
|
),
|
|
104110
104075
|
...props
|
|
@@ -104194,20 +104159,6 @@ var questionTypeManager = new LocalStorageManager("question_types");
|
|
|
104194
104159
|
var learningObjectiveManager = new LocalStorageManager("learning_objectives");
|
|
104195
104160
|
var contextManager = new LocalStorageManager("contexts");
|
|
104196
104161
|
var approachManager = new LocalStorageManager("approaches");
|
|
104197
|
-
function mapRawDifficultyToStandard(rawDifficulty) {
|
|
104198
|
-
switch (rawDifficulty) {
|
|
104199
|
-
case "E":
|
|
104200
|
-
case "E~M":
|
|
104201
|
-
return "easy";
|
|
104202
|
-
case "M":
|
|
104203
|
-
case "M~H":
|
|
104204
|
-
return "medium";
|
|
104205
|
-
case "H":
|
|
104206
|
-
return "hard";
|
|
104207
|
-
default:
|
|
104208
|
-
return "medium";
|
|
104209
|
-
}
|
|
104210
|
-
}
|
|
104211
104162
|
var MetadataService = class {
|
|
104212
104163
|
};
|
|
104213
104164
|
// --- Subject Services ---
|
|
@@ -104265,15 +104216,10 @@ MetadataService.deleteContext = (code4) => contextManager.delete(code4);
|
|
|
104265
104216
|
MetadataService.getApproaches = () => approachManager.getAll().sort((a4, b2) => a4.code.localeCompare(b2.code));
|
|
104266
104217
|
MetadataService.saveApproaches = (items) => approachManager.saveAll(items);
|
|
104267
104218
|
MetadataService.addApproach = (approachData) => {
|
|
104268
|
-
|
|
104269
|
-
return approachManager.add({ ...approachData, difficulty });
|
|
104219
|
+
return approachManager.add(approachData);
|
|
104270
104220
|
};
|
|
104271
104221
|
MetadataService.updateApproach = (id3, approachData) => {
|
|
104272
|
-
|
|
104273
|
-
if (approachData.rawDifficulty) {
|
|
104274
|
-
updates.difficulty = mapRawDifficultyToStandard(approachData.rawDifficulty);
|
|
104275
|
-
}
|
|
104276
|
-
return approachManager.update(id3, updates);
|
|
104222
|
+
return approachManager.update(id3, approachData);
|
|
104277
104223
|
};
|
|
104278
104224
|
MetadataService.deleteApproach = (code4) => approachManager.delete(code4);
|
|
104279
104225
|
// --- LearningObjective Services ---
|
|
@@ -104283,8 +104229,12 @@ MetadataService.getLearningObjectives = (subjectCode) => {
|
|
|
104283
104229
|
return filtered.sort((a4, b2) => a4.name.localeCompare(b2.name));
|
|
104284
104230
|
};
|
|
104285
104231
|
MetadataService.saveLearningObjectives = (items) => learningObjectiveManager.saveAll(items);
|
|
104286
|
-
MetadataService.addLearningObjective = (
|
|
104287
|
-
|
|
104232
|
+
MetadataService.addLearningObjective = (item) => {
|
|
104233
|
+
return learningObjectiveManager.add(item);
|
|
104234
|
+
};
|
|
104235
|
+
MetadataService.updateLearningObjective = (id3, updates) => {
|
|
104236
|
+
return learningObjectiveManager.update(id3, updates);
|
|
104237
|
+
};
|
|
104288
104238
|
MetadataService.deleteLearningObjective = (code4) => learningObjectiveManager.delete(code4);
|
|
104289
104239
|
|
|
104290
104240
|
// node_modules/date-fns/addDays.mjs
|
|
@@ -106184,7 +106134,7 @@ function QuestionList({
|
|
|
106184
106134
|
if (questions.length === 0) {
|
|
106185
106135
|
return /* @__PURE__ */ React169__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.");
|
|
106186
106136
|
}
|
|
106187
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, { className: "w-[30%]" }, "Question Text"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Type"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Grade"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Bloom's"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Last Modified"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, questions.map((question2) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: question2.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-
|
|
106137
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, { className: "w-[30%]" }, "Question Text"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Type"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Grade"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Bloom's"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Last Modified"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, questions.map((question2) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: question2.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-Medium max-w-xs truncate", title: question2.text }, /* @__PURE__ */ React169__default.createElement(MarkdownRenderer, { content: question2.questionConfig.prompt })), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, question2.code), /* @__PURE__ */ React169__default.createElement(TableCell, null, /* @__PURE__ */ React169__default.createElement(Badge2, { variant: "secondary" }, getLookupName(question2.questionTypeCode, metadata.questionTypes))), /* @__PURE__ */ React169__default.createElement(TableCell, null, getLookupName(question2.subjectCode, metadata.subjects)), /* @__PURE__ */ React169__default.createElement(TableCell, null, getLookupName(question2.topicCode, metadata.topics)), /* @__PURE__ */ React169__default.createElement(TableCell, null, getLookupName(question2.gradeLevelCode, metadata.gradeLevels)), /* @__PURE__ */ React169__default.createElement(TableCell, null, /* @__PURE__ */ React169__default.createElement(Badge2, { variant: "outline" }, getLookupName(question2.bloomLevelCode, metadata.bloomLevels))), /* @__PURE__ */ React169__default.createElement(TableCell, null, format(new Date(question2.lastModified), "MMM d, yyyy")), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, onView && /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => onView(question2), className: "mr-1" }, /* @__PURE__ */ React169__default.createElement(Eye, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => onEdit(question2), className: "mr-1" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => onDelete(question2), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" }))))))));
|
|
106188
106138
|
}
|
|
106189
106139
|
|
|
106190
106140
|
// src/react-ui/components/authoring/QuestionFilters.tsx
|
|
@@ -106265,7 +106215,7 @@ function QuestionFilters({
|
|
|
106265
106215
|
onChange: (e3) => setSearchTerm(e3.target.value),
|
|
106266
106216
|
className: "lg:col-span-2 xl:col-span-1"
|
|
106267
106217
|
}
|
|
106268
|
-
), /* @__PURE__ */ React169__default.createElement(Select2, { value: subjectCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setSubjectCode) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Subject" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Subjects"), subjects.map((s4) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: s4.code, value: s4.code }, s4.name)))), /* @__PURE__ */ React169__default.createElement(Select2, { value: topicCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setTopicCode), disabled: !subjectCode || filteredTopics.length === 0 }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Topic" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Topics"), filteredTopics.map((t4) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: t4.code, value: t4.code }, t4.name)))), /* @__PURE__ */ React169__default.createElement(Select2, { value: gradeLevelCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setGradeLevelCode) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Grade Level" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Grade Levels"), gradeLevels.map((gl) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: gl.code, value: gl.code }, gl.name)))), /* @__PURE__ */ React169__default.createElement(Select2, { value: bloomLevelCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setBloomLevelCode) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Bloom's Level" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Levels"), bloomLevels.map((bl) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: bl.code, value: bl.code }, bl.name)))), /* @__PURE__ */ React169__default.createElement(Select2, { value: questionTypeCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setQuestionTypeCode) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Question Type" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Types"), questionTypes.map((qt) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: qt.code, value: qt.code }, qt.name)))), /* @__PURE__ */ React169__default.createElement(Select2, { value: difficulty || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setDifficulty) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Difficulty" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Difficulties"), /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "
|
|
106218
|
+
), /* @__PURE__ */ React169__default.createElement(Select2, { value: subjectCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setSubjectCode) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Subject" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Subjects"), subjects.map((s4) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: s4.code, value: s4.code }, s4.name)))), /* @__PURE__ */ React169__default.createElement(Select2, { value: topicCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setTopicCode), disabled: !subjectCode || filteredTopics.length === 0 }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Topic" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Topics"), filteredTopics.map((t4) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: t4.code, value: t4.code }, t4.name)))), /* @__PURE__ */ React169__default.createElement(Select2, { value: gradeLevelCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setGradeLevelCode) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Grade Level" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Grade Levels"), gradeLevels.map((gl) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: gl.code, value: gl.code }, gl.name)))), /* @__PURE__ */ React169__default.createElement(Select2, { value: bloomLevelCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setBloomLevelCode) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Bloom's Level" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Levels"), bloomLevels.map((bl) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: bl.code, value: bl.code }, bl.name)))), /* @__PURE__ */ React169__default.createElement(Select2, { value: questionTypeCode || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setQuestionTypeCode) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Question Type" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Types"), questionTypes.map((qt) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: qt.code, value: qt.code }, qt.name)))), /* @__PURE__ */ React169__default.createElement(Select2, { value: difficulty || ALL_ITEMS_VALUE, onValueChange: createSelectHandler(setDifficulty) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Difficulty" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: ALL_ITEMS_VALUE }, "All Difficulties"), /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "Easy" }, "Easy"), /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "Medium" }, "Medium"), /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "Hard" }, "Hard"))), /* @__PURE__ */ React169__default.createElement("div", { className: "flex gap-2 col-span-full sm:col-span-1 xl:col-span-2 xl:col-start-6" }, /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleApplyFilters, className: "w-full sm:w-auto flex-grow" }, /* @__PURE__ */ React169__default.createElement(Search, { className: "mr-2 h-4 w-4" }), " Apply"), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleClearFilters, variant: "outline", className: "w-full sm:w-auto flex-grow" }, /* @__PURE__ */ React169__default.createElement(CircleX, { className: "mr-2 h-4 w-4" }), " Clear"))));
|
|
106269
106219
|
}
|
|
106270
106220
|
|
|
106271
106221
|
// src/react-ui/components/authoring/QuestionFormDialog.tsx
|
|
@@ -106373,7 +106323,7 @@ function QuestionFormDialog({
|
|
|
106373
106323
|
};
|
|
106374
106324
|
const dialogTitle = questionToEdit ? "Edit Question Metadata" : "Create New Question";
|
|
106375
106325
|
const dialogDescription = "First, define the metadata for the question. Then, edit the question's content and logic.";
|
|
106376
|
-
return /* @__PURE__ */ React169__default.createElement(React169__default.Fragment, null, /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isOpen, onOpenChange }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-xl md:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, dialogTitle), /* @__PURE__ */ React169__default.createElement(DialogDescription2, null, dialogDescription)), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "code" }, "Question Code"), /* @__PURE__ */ React169__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__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "gradeLevelCode" }, "Grade Level"), /* @__PURE__ */ React169__default.createElement(Select2, { value: gradeLevelCode, onValueChange: setGradeLevelCode }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "gradeLevelCode" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Select Grade Level" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, gradeLevels.map((gl) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: gl.code, value: gl.code }, gl.name)))))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject"), /* @__PURE__ */ React169__default.createElement(Select2, { value: subjectCode, onValueChange: setSubjectCode }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "subjectCode" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Select Subject" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, subjects.map((s4) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: s4.code, value: s4.code }, s4.name))))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "topicCode" }, "Topic"), /* @__PURE__ */ React169__default.createElement(Select2, { value: topicCode, onValueChange: setTopicCode, disabled: !subjectCode || filteredTopics.length === 0 }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "topicCode" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Select Topic" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, filteredTopics.map((t4) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: t4.code, value: t4.code }, t4.name)))))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "bloomLevelCode" }, "Bloom's Level"), /* @__PURE__ */ React169__default.createElement(Select2, { value: bloomLevelCode, onValueChange: setBloomLevelCode }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "bloomLevelCode" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Select Bloom's Level" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, bloomLevels.map((bl) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: bl.code, value: bl.code }, bl.name))))), /* @__PURE__ */ React169__default.createElement("div", { className: "pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Question Content & Logic"), questionConfig ? /* @__PURE__ */ React169__default.createElement("div", { className: "p-3 mt-2 border rounded-md bg-muted/30 flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("p", { className: "font-
|
|
106326
|
+
return /* @__PURE__ */ React169__default.createElement(React169__default.Fragment, null, /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isOpen, onOpenChange }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-xl md:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, dialogTitle), /* @__PURE__ */ React169__default.createElement(DialogDescription2, null, dialogDescription)), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "code" }, "Question Code"), /* @__PURE__ */ React169__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__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "gradeLevelCode" }, "Grade Level"), /* @__PURE__ */ React169__default.createElement(Select2, { value: gradeLevelCode, onValueChange: setGradeLevelCode }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "gradeLevelCode" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Select Grade Level" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, gradeLevels.map((gl) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: gl.code, value: gl.code }, gl.name)))))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject"), /* @__PURE__ */ React169__default.createElement(Select2, { value: subjectCode, onValueChange: setSubjectCode }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "subjectCode" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Select Subject" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, subjects.map((s4) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: s4.code, value: s4.code }, s4.name))))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "topicCode" }, "Topic"), /* @__PURE__ */ React169__default.createElement(Select2, { value: topicCode, onValueChange: setTopicCode, disabled: !subjectCode || filteredTopics.length === 0 }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "topicCode" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Select Topic" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, filteredTopics.map((t4) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: t4.code, value: t4.code }, t4.name)))))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "bloomLevelCode" }, "Bloom's Level"), /* @__PURE__ */ React169__default.createElement(Select2, { value: bloomLevelCode, onValueChange: setBloomLevelCode }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "bloomLevelCode" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Select Bloom's Level" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, bloomLevels.map((bl) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: bl.code, value: bl.code }, bl.name))))), /* @__PURE__ */ React169__default.createElement("div", { className: "pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement(Label2, { className: "font-semibold" }, "Question Content & Logic"), questionConfig ? /* @__PURE__ */ React169__default.createElement("div", { className: "p-3 mt-2 border rounded-md bg-muted/30 flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("p", { className: "font-Medium" }, "Type: ", /* @__PURE__ */ React169__default.createElement("span", { className: "font-normal" }, questionConfig.questionType)), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground truncate max-w-md" }, "Prompt: ", questionConfig.prompt.replace(/<[^>]*>?/gm, "") || "Not set")), /* @__PURE__ */ React169__default.createElement(Button, { variant: "outline", onClick: () => handleOpenQuestionEditor() }, /* @__PURE__ */ React169__default.createElement(SquarePen, { className: "mr-2 h-4 w-4" }), " Edit Content")) : /* @__PURE__ */ React169__default.createElement("div", { className: "p-3 mt-2 border-dashed border-2 rounded-md text-center" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-muted-foreground mb-2" }, "No content has been created yet."), /* @__PURE__ */ React169__default.createElement(Button, { variant: "default", onClick: () => handleOpenQuestionEditor("multiple_choice") }, /* @__PURE__ */ React169__default.createElement(BookCopy, { className: "mr-2 h-4 w-4" }), " Create Question Content")))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => onOpenChange(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !questionConfig }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save Question")))), questionConfig && /* @__PURE__ */ React169__default.createElement(
|
|
106377
106327
|
EditQuestionModal,
|
|
106378
106328
|
{
|
|
106379
106329
|
isOpen: isQuestionEditorOpen,
|
|
@@ -110691,10 +110641,10 @@ var RoadmapService = class {
|
|
|
110691
110641
|
}
|
|
110692
110642
|
return null;
|
|
110693
110643
|
}
|
|
110694
|
-
static updateRoadmapItemStatus(
|
|
110644
|
+
static updateRoadmapItemStatus(code4, isCompleted) {
|
|
110695
110645
|
const roadmap = this.getRoadmap();
|
|
110696
110646
|
if (roadmap) {
|
|
110697
|
-
const itemIndex = roadmap.items.findIndex((item) => item.
|
|
110647
|
+
const itemIndex = roadmap.items.findIndex((item) => item.code === code4);
|
|
110698
110648
|
if (itemIndex > -1) {
|
|
110699
110649
|
roadmap.items[itemIndex].isCompleted = isCompleted;
|
|
110700
110650
|
this.saveRoadmap(roadmap);
|
|
@@ -111275,7 +111225,7 @@ z.object({
|
|
|
111275
111225
|
startDate: z.string().describe("The start date for the analysis period in ISO format (YYYY-MM-DD)."),
|
|
111276
111226
|
endDate: z.string().describe("The end date for the analysis period in ISO format (YYYY-MM-DD)."),
|
|
111277
111227
|
allAvailableTopics: z.array(z.object({
|
|
111278
|
-
|
|
111228
|
+
code: z.string(),
|
|
111279
111229
|
subject: z.string(),
|
|
111280
111230
|
category: z.string(),
|
|
111281
111231
|
topic: z.string()
|
|
@@ -111286,7 +111236,7 @@ var RoadmapItemSchema = z.object({
|
|
|
111286
111236
|
topicName: z.string(),
|
|
111287
111237
|
reason: z.string(),
|
|
111288
111238
|
suggestedDifficulty: z.enum(["Very Easy", "Easy", "Medium", "Hard", "Expert"]),
|
|
111289
|
-
|
|
111239
|
+
code: z.string(),
|
|
111290
111240
|
isCompleted: z.boolean()
|
|
111291
111241
|
});
|
|
111292
111242
|
var WeeklyRoadmapSchema = z.object({
|
|
@@ -111351,7 +111301,7 @@ All topic names and loIds in your "weeklyRoadmap" output MUST be chosen directly
|
|
|
111351
111301
|
- **gamificationRemarks**: Write an encouraging message mentioning their achievements.
|
|
111352
111302
|
2. **For "weeklyRoadmap":**
|
|
111353
111303
|
- Create a 5-item roadmap for the upcoming week.
|
|
111354
|
-
- Prioritize the "areasForImprovement" you identified. For each, find the corresponding entry in "All Available Topics" and use its "topicName" and "
|
|
111304
|
+
- Prioritize the "areasForImprovement" you identified. For each, find the corresponding entry in "All Available Topics" and use its "topicName" and "code".
|
|
111355
111305
|
- If more items are needed, select related topics from "All Available Topics".
|
|
111356
111306
|
|
|
111357
111307
|
**IF Practice History IS EMPTY:**
|
|
@@ -111362,7 +111312,7 @@ All topic names and loIds in your "weeklyRoadmap" output MUST be chosen directly
|
|
|
111362
111312
|
- **gamificationRemarks**: Write a general motivational message about starting to learn.
|
|
111363
111313
|
2. **For "weeklyRoadmap":**
|
|
111364
111314
|
- Create a 5-item "starter" roadmap.
|
|
111365
|
-
- Select 5 diverse and foundational topics directly from the "All Available Topics" list. Use their exact "topicName" and "
|
|
111315
|
+
- Select 5 diverse and foundational topics directly from the "All Available Topics" list. Use their exact "topicName" and "code".
|
|
111366
111316
|
- For the "reason", explain that this is a good starting point to explore the subject.
|
|
111367
111317
|
|
|
111368
111318
|
--- END LOGIC FLOW ---
|
|
@@ -111390,7 +111340,7 @@ The 'suggestedDifficulty' field MUST ALWAYS be one of these exact English string
|
|
|
111390
111340
|
"topicName": "Topic C",
|
|
111391
111341
|
"reason": "To strengthen your understanding of this key area.",
|
|
111392
111342
|
"suggestedDifficulty": "Easy",
|
|
111393
|
-
"
|
|
111343
|
+
"code": "lo-id-for-topic-c-from-the-list",
|
|
111394
111344
|
"isCompleted": false
|
|
111395
111345
|
}
|
|
111396
111346
|
]
|
|
@@ -111652,11 +111602,11 @@ init_react_shim();
|
|
|
111652
111602
|
// src/ai/flows/assess-and-map-document-types.ts
|
|
111653
111603
|
init_react_shim();
|
|
111654
111604
|
var LearningObjectiveContextSchema = z.object({
|
|
111655
|
-
|
|
111605
|
+
code: z.string(),
|
|
111656
111606
|
subject: z.string(),
|
|
111657
111607
|
category: z.string(),
|
|
111658
111608
|
topic: z.string(),
|
|
111659
|
-
|
|
111609
|
+
description: z.string()
|
|
111660
111610
|
});
|
|
111661
111611
|
z.object({
|
|
111662
111612
|
language: z.string().default("English"),
|
|
@@ -111664,7 +111614,7 @@ z.object({
|
|
|
111664
111614
|
learningObjectives: z.array(LearningObjectiveContextSchema).min(1, { message: "At least one learning objective is required for mapping." })
|
|
111665
111615
|
});
|
|
111666
111616
|
var MappedLOSchema = z.object({
|
|
111667
|
-
|
|
111617
|
+
code: z.string().describe("The exact code from the provided learning objectives list that matches the document content."),
|
|
111668
111618
|
confidence: z.number().min(0).max(100).describe("A confidence score (0-100) of how well the document maps to this LO."),
|
|
111669
111619
|
reasoning: z.string().describe("A brief explanation for why this mapping is relevant.")
|
|
111670
111620
|
});
|
|
@@ -111700,7 +111650,7 @@ You are an expert curriculum analyst. Your task is to analyze a given document a
|
|
|
111700
111650
|
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).
|
|
111701
111651
|
|
|
111702
111652
|
2. **Specific Mapping:** Identify which specific LOs from the list are directly addressed by the document. For each match you find, provide:
|
|
111703
|
-
- The exact "
|
|
111653
|
+
- The exact "code" of the matched LO.
|
|
111704
111654
|
- A "confidence" score (0-100) for that specific match.
|
|
111705
111655
|
- A brief "reasoning" in ${language3} explaining why the document content maps to that LO.
|
|
111706
111656
|
|
|
@@ -111715,7 +111665,7 @@ Return a single, valid JSON object in this EXACT format. Do not include any othe
|
|
|
111715
111665
|
"isFreestyleRecommended": false,
|
|
111716
111666
|
"mappedLOs": [
|
|
111717
111667
|
{
|
|
111718
|
-
"
|
|
111668
|
+
"code": "SWIFT_FUNC_01",
|
|
111719
111669
|
"confidence": 95,
|
|
111720
111670
|
"reasoning": "The document provides a detailed explanation of function syntax and default parameters, which directly aligns with this learning objective."
|
|
111721
111671
|
}
|
|
@@ -111810,7 +111760,7 @@ Return the response as a single JSON object with a key "generatedQuestions" cont
|
|
|
111810
111760
|
"correctTempOptionId": "A",
|
|
111811
111761
|
"explanation": "The document states that mitochondria are the powerhouses of the cell, responsible for cellular respiration.",
|
|
111812
111762
|
"points": 10,
|
|
111813
|
-
"difficulty": "
|
|
111763
|
+
"difficulty": "Medium",
|
|
111814
111764
|
"topic": "Cell Biology"
|
|
111815
111765
|
},
|
|
111816
111766
|
{
|
|
@@ -111819,7 +111769,7 @@ Return the response as a single JSON object with a key "generatedQuestions" cont
|
|
|
111819
111769
|
"correctAnswer": false,
|
|
111820
111770
|
"explanation": "The text specifies that the cell wall is a feature of plant cells, not animal cells.",
|
|
111821
111771
|
"points": 10,
|
|
111822
|
-
"difficulty": "
|
|
111772
|
+
"difficulty": "Easy",
|
|
111823
111773
|
"topic": "Cell Biology"
|
|
111824
111774
|
}
|
|
111825
111775
|
]
|
|
@@ -112652,7 +112602,7 @@ var QuizReview = ({
|
|
|
112652
112602
|
};
|
|
112653
112603
|
return /* @__PURE__ */ React169__default.createElement(Card, { className: "w-full max-w-4xl mx-auto shadow-xl" }, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-3xl font-headline text-center flex items-center justify-center" }, /* @__PURE__ */ React169__default.createElement(BookOpen, { className: "mr-3 h-8 w-8 text-primary" }), "AI-Powered Quiz Review"), /* @__PURE__ */ React169__default.createElement(CardDescription, { className: "text-center text-lg" }, "Let's break down your results and reinforce your learning.")), /* @__PURE__ */ React169__default.createElement(CardContent, { className: "space-y-6" }, /* @__PURE__ */ React169__default.createElement(Card, { className: "bg-muted/30" }, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-xl flex items-center" }, /* @__PURE__ */ React169__default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-yellow-500" }), "Key Concepts Summary")), /* @__PURE__ */ React169__default.createElement(CardContent, null, /* @__PURE__ */ React169__default.createElement(MarkdownRenderer, { content: reviewContent.overallSummary }))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("h3", { className: "text-xl font-semibold mb-2" }, "Detailed Question Analysis"), /* @__PURE__ */ React169__default.createElement(Accordion2, { type: "single", collapsible: true, className: "w-full" }, quizResult.questionResults.map((qResult, index3) => {
|
|
112654
112604
|
const aiReview = getReviewForQuestion(qResult.questionId);
|
|
112655
|
-
return /* @__PURE__ */ React169__default.createElement(AccordionItem2, { value: `item-${index3}`, key: qResult.questionId }, /* @__PURE__ */ React169__default.createElement(AccordionTrigger2, null, /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center justify-between w-full pr-2" }, /* @__PURE__ */ React169__default.createElement("span", { className: "text-left font-
|
|
112605
|
+
return /* @__PURE__ */ React169__default.createElement(AccordionItem2, { value: `item-${index3}`, key: qResult.questionId }, /* @__PURE__ */ React169__default.createElement(AccordionTrigger2, null, /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center justify-between w-full pr-2" }, /* @__PURE__ */ React169__default.createElement("span", { className: "text-left font-Medium" }, "Question ", index3 + 1), qResult.isCorrect ? /* @__PURE__ */ React169__default.createElement("span", { className: "text-sm text-green-600 font-Medium flex items-center gap-1" }, /* @__PURE__ */ React169__default.createElement(CircleCheckBig, { className: "h-4 w-4" }), " Correct") : /* @__PURE__ */ React169__default.createElement("span", { className: "text-sm text-destructive font-Medium flex items-center gap-1" }, /* @__PURE__ */ React169__default.createElement(CircleX, { className: "h-4 w-4" }), " Incorrect"))), /* @__PURE__ */ React169__default.createElement(AccordionContent2, { className: "space-y-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "p-4 border rounded-md bg-background" }, /* @__PURE__ */ React169__default.createElement("p", { className: "font-semibold mb-2" }, "Original Question:"), /* @__PURE__ */ React169__default.createElement(MarkdownRenderer, { content: qResult.prompt })), qResult.questionType === "coding" ? renderCodingResult(qResult) : renderStandardResult(qResult), aiReview && /* @__PURE__ */ React169__default.createElement("div", { className: "p-4 border-l-4 border-primary bg-primary/10 rounded-r-md" }, /* @__PURE__ */ React169__default.createElement("p", { className: "font-semibold text-primary mb-2" }, "AI Tutor Explanation:"), /* @__PURE__ */ React169__default.createElement(MarkdownRenderer, { content: aiReview.explanation }))));
|
|
112656
112606
|
}))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("h3", { className: "text-xl font-semibold mb-2" }, "Topics for Further Study"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex flex-wrap gap-2" }, reviewContent.relatedTopics.map((topic, index3) => /* @__PURE__ */ React169__default.createElement(Badge2, { key: index3, variant: "secondary", className: "text-base px-3 py-1" }, topic))))), /* @__PURE__ */ React169__default.createElement(CardFooter, { className: "flex flex-col sm:flex-row justify-between gap-2" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "outline", onClick: onBackToResults, className: "w-full sm:w-auto" }, /* @__PURE__ */ React169__default.createElement(ArrowLeft, { className: "mr-2 h-4 w-4" }), "Back to Results"), /* @__PURE__ */ React169__default.createElement(Button, { onClick: onExit, className: "w-full sm:w-auto" }, /* @__PURE__ */ React169__default.createElement(LogOut, { className: "mr-2 h-4 w-4" }), "Finish & Exit")));
|
|
112657
112607
|
};
|
|
112658
112608
|
|
|
@@ -112699,7 +112649,7 @@ var PracticeHistoryTable = ({ history: history2, maxHeight = "400px" }) => {
|
|
|
112699
112649
|
if (percentage >= 50) return "secondary";
|
|
112700
112650
|
return "destructive";
|
|
112701
112651
|
};
|
|
112702
|
-
return /* @__PURE__ */ React169__default.createElement(React169__default.Fragment, null, /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, null, t4("history.title")), /* @__PURE__ */ React169__default.createElement(CardDescription, null, t4("history.description"))), /* @__PURE__ */ React169__default.createElement(CardContent, null, /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "w-full border rounded-md", style: { height: maxHeight } }, /* @__PURE__ */ React169__default.createElement(TooltipProvider2, { delayDuration: 100 }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, { className: "sticky top-0 bg-muted z-10" }, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, { className: "w-[120px]" }, t4("history.headers.date")), /* @__PURE__ */ React169__default.createElement(TableHead, null, t4("history.headers.topic")), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[80px]" }, t4("history.headers.score")), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[90px]" }, t4("history.headers.percentage")))), /* @__PURE__ */ React169__default.createElement(TableBody, null, history2.length > 0 ? history2.map((session) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: session.id, onClick: () => handleRowClick(session), className: "cursor-pointer" }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-
|
|
112652
|
+
return /* @__PURE__ */ React169__default.createElement(React169__default.Fragment, null, /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, null, t4("history.title")), /* @__PURE__ */ React169__default.createElement(CardDescription, null, t4("history.description"))), /* @__PURE__ */ React169__default.createElement(CardContent, null, /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "w-full border rounded-md", style: { height: maxHeight } }, /* @__PURE__ */ React169__default.createElement(TooltipProvider2, { delayDuration: 100 }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, { className: "sticky top-0 bg-muted z-10" }, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, { className: "w-[120px]" }, t4("history.headers.date")), /* @__PURE__ */ React169__default.createElement(TableHead, null, t4("history.headers.topic")), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[80px]" }, t4("history.headers.score")), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[90px]" }, t4("history.headers.percentage")))), /* @__PURE__ */ React169__default.createElement(TableBody, null, history2.length > 0 ? history2.map((session) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: session.id, onClick: () => handleRowClick(session), className: "cursor-pointer" }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-Medium text-xs text-muted-foreground" }, formatDate(session.timestamp)), /* @__PURE__ */ React169__default.createElement(TableCell, null, /* @__PURE__ */ React169__default.createElement("div", { className: "flex flex-col gap-1.5" }, session.topics.map((topicInfo, index3) => /* @__PURE__ */ React169__default.createElement(Tooltip2, { key: index3 }, /* @__PURE__ */ React169__default.createElement(TooltipTrigger2, { asChild: true }, /* @__PURE__ */ React169__default.createElement("p", { className: "font-semibold text-sm truncate" }, topicInfo.topic)), /* @__PURE__ */ React169__default.createElement(TooltipContent2, null, /* @__PURE__ */ React169__default.createElement("p", null, /* @__PURE__ */ React169__default.createElement("strong", null, t4("settingsModal.topics.tableHeaders.subject"), ":"), " ", topicInfo.subject), /* @__PURE__ */ React169__default.createElement("p", null, /* @__PURE__ */ React169__default.createElement("strong", null, t4("settingsModal.topics.tableHeaders.category"), ":"), " ", topicInfo.category)))))), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right font-mono text-sm" }, session.score !== null ? `${session.score}/${session.maxScore}` : "N/A"), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, session.percentage !== null && /* @__PURE__ */ React169__default.createElement(
|
|
112703
112653
|
Badge2,
|
|
112704
112654
|
{
|
|
112705
112655
|
variant: getPercentageBadgeVariant(session.percentage),
|
|
@@ -133514,12 +133464,12 @@ var ChartTooltipContent = React169.forwardRef(
|
|
|
133514
133464
|
const itemConfig = getPayloadConfigFromPayload(config3, item, key);
|
|
133515
133465
|
const value = !labelKey && typeof label === "string" ? config3[label]?.label || label : itemConfig?.label;
|
|
133516
133466
|
if (labelFormatter) {
|
|
133517
|
-
return /* @__PURE__ */ React169.createElement("div", { className: cn("font-
|
|
133467
|
+
return /* @__PURE__ */ React169.createElement("div", { className: cn("font-Medium", labelClassName) }, labelFormatter(value, payload));
|
|
133518
133468
|
}
|
|
133519
133469
|
if (!value) {
|
|
133520
133470
|
return null;
|
|
133521
133471
|
}
|
|
133522
|
-
return /* @__PURE__ */ React169.createElement("div", { className: cn("font-
|
|
133472
|
+
return /* @__PURE__ */ React169.createElement("div", { className: cn("font-Medium", labelClassName) }, value);
|
|
133523
133473
|
}, [
|
|
133524
133474
|
label,
|
|
133525
133475
|
labelFormatter,
|
|
@@ -133582,7 +133532,7 @@ var ChartTooltipContent = React169.forwardRef(
|
|
|
133582
133532
|
)
|
|
133583
133533
|
},
|
|
133584
133534
|
/* @__PURE__ */ React169.createElement("div", { className: "grid gap-1.5" }, nestLabel ? tooltipLabel : null, /* @__PURE__ */ React169.createElement("span", { className: "text-muted-foreground" }, itemConfig?.label || item.name)),
|
|
133585
|
-
item.value && /* @__PURE__ */ React169.createElement("span", { className: "font-mono font-
|
|
133535
|
+
item.value && /* @__PURE__ */ React169.createElement("span", { className: "font-mono font-Medium tabular-nums text-foreground" }, item.value.toLocaleString())
|
|
133586
133536
|
))
|
|
133587
133537
|
);
|
|
133588
133538
|
}))
|
|
@@ -134759,7 +134709,7 @@ var ManageTopics = () => {
|
|
|
134759
134709
|
return /* @__PURE__ */ React169__default.createElement(React169__default.Fragment, null, /* @__PURE__ */ React169__default.createElement(Card, { className: "w-full max-w-4xl mx-auto shadow-none border-none" }, /* @__PURE__ */ React169__default.createElement(CardHeader, { className: "px-1" }, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex items-center text-2xl font-headline" }, /* @__PURE__ */ React169__default.createElement(FileText, { className: "mr-3 h-6 w-6 text-primary" }), t4("settingsModal.topics.title")), /* @__PURE__ */ React169__default.createElement(CardDescription, null, t4("settingsModal.topics.description"))), /* @__PURE__ */ React169__default.createElement(CardContent, { className: "space-y-6 px-1" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "tsv-importer", className: "text-lg font-semibold" }, t4("settingsModal.topics.importData")), /* @__PURE__ */ React169__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__default.createElement("div", { className: "flex-grow" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("settingsModal.topics.importHint")), /* @__PURE__ */ React169__default.createElement("a", { href: "#", className: "text-xs text-primary hover:underline", onClick: (e3) => {
|
|
134760
134710
|
e3.preventDefault();
|
|
134761
134711
|
alert("Header format:\nLO ID LO Description Subject Category Topic Keywords Grade STEM Element(s) Bloom\u2019s Level(s) Guideline");
|
|
134762
|
-
} }, t4("settingsModal.topics.viewHeaderFormat"))), /* @__PURE__ */ React169__default.createElement(Input, { id: "tsv-importer", type: "file", ref: fileInputRef, accept: ".tsv,text/tab-separated-values", onChange: handleFileChange, className: "hidden" }), /* @__PURE__ */ React169__default.createElement(Button, { onClick: () => fileInputRef.current?.click() }, /* @__PURE__ */ React169__default.createElement(Upload, { className: "mr-2 h-4 w-4" }), t4("settingsModal.topics.chooseFile")))), importErrors.length > 0 && /* @__PURE__ */ React169__default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ React169__default.createElement(CircleAlert, { className: "h-4 w-4" }), /* @__PURE__ */ React169__default.createElement(AlertTitle, null, t4("settingsModal.topics.importErrors")), /* @__PURE__ */ React169__default.createElement(AlertDescription, null, /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-24 mt-2" }, /* @__PURE__ */ React169__default.createElement("ul", { className: "list-disc list-inside text-xs space-y-1" }, importErrors.map((error, index3) => /* @__PURE__ */ React169__default.createElement("li", { key: index3 }, error)))))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center sm:justify-between mb-2" }, /* @__PURE__ */ React169__default.createElement("h3", { className: "text-lg font-semibold" }, t4("settingsModal.topics.currentDataTitle")), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("settingsModal.topics.showingCount", { shown: filteredLearningObjectives.length, total: learningObjectives.length }))), /* @__PURE__ */ React169__default.createElement("div", { className: "mb-4" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subject-filter" }, t4("settingsModal.topics.filterBySubject")), /* @__PURE__ */ React169__default.createElement(Select2, { value: selectedSubjectFilter, onValueChange: setSelectedSubjectFilter, disabled: subjects.length === 0 }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "subject-filter", className: "w-full sm:w-[280px]" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: t4("settingsModal.topics.filterPlaceholder") })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "all" }, t4("settingsModal.topics.allSubjects")), subjects.map((subject) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: subject, value: subject }, subject))))), /* @__PURE__ */ React169__default.createElement("div", { className: "border rounded-lg" }, /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-72" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, { className: "sticky top-0 bg-muted" }, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, { className: "w-[150px]" }, t4("settingsModal.topics.tableHeaders.subject")), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "w-[150px]" }, t4("settingsModal.topics.tableHeaders.category")), /* @__PURE__ */ React169__default.createElement(TableHead, null, t4("settingsModal.topics.tableHeaders.topic")), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "w-[100px]" }, t4("settingsModal.topics.tableHeaders.
|
|
134712
|
+
} }, t4("settingsModal.topics.viewHeaderFormat"))), /* @__PURE__ */ React169__default.createElement(Input, { id: "tsv-importer", type: "file", ref: fileInputRef, accept: ".tsv,text/tab-separated-values", onChange: handleFileChange, className: "hidden" }), /* @__PURE__ */ React169__default.createElement(Button, { onClick: () => fileInputRef.current?.click() }, /* @__PURE__ */ React169__default.createElement(Upload, { className: "mr-2 h-4 w-4" }), t4("settingsModal.topics.chooseFile")))), importErrors.length > 0 && /* @__PURE__ */ React169__default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ React169__default.createElement(CircleAlert, { className: "h-4 w-4" }), /* @__PURE__ */ React169__default.createElement(AlertTitle, null, t4("settingsModal.topics.importErrors")), /* @__PURE__ */ React169__default.createElement(AlertDescription, null, /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-24 mt-2" }, /* @__PURE__ */ React169__default.createElement("ul", { className: "list-disc list-inside text-xs space-y-1" }, importErrors.map((error, index3) => /* @__PURE__ */ React169__default.createElement("li", { key: index3 }, error)))))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("div", { className: "flex flex-col sm:flex-row sm:items-center sm:justify-between mb-2" }, /* @__PURE__ */ React169__default.createElement("h3", { className: "text-lg font-semibold" }, t4("settingsModal.topics.currentDataTitle")), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("settingsModal.topics.showingCount", { shown: filteredLearningObjectives.length, total: learningObjectives.length }))), /* @__PURE__ */ React169__default.createElement("div", { className: "mb-4" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subject-filter" }, t4("settingsModal.topics.filterBySubject")), /* @__PURE__ */ React169__default.createElement(Select2, { value: selectedSubjectFilter, onValueChange: setSelectedSubjectFilter, disabled: subjects.length === 0 }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "subject-filter", className: "w-full sm:w-[280px]" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: t4("settingsModal.topics.filterPlaceholder") })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "all" }, t4("settingsModal.topics.allSubjects")), subjects.map((subject) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: subject, value: subject }, subject))))), /* @__PURE__ */ React169__default.createElement("div", { className: "border rounded-lg" }, /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-72" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, { className: "sticky top-0 bg-muted" }, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, { className: "w-[150px]" }, t4("settingsModal.topics.tableHeaders.subject")), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "w-[150px]" }, t4("settingsModal.topics.tableHeaders.category")), /* @__PURE__ */ React169__default.createElement(TableHead, null, t4("settingsModal.topics.tableHeaders.topic")), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "w-[100px]" }, t4("settingsModal.topics.tableHeaders.code")))), /* @__PURE__ */ React169__default.createElement(TableBody, null, isLoading ? /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableCell, { colSpan: 4, className: "text-center" }, t4("common.loading"))) : filteredLearningObjectives.length > 0 ? filteredLearningObjectives.map((lo) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: lo.code }, /* @__PURE__ */ React169__default.createElement(TableCell, null, lo.subject), /* @__PURE__ */ React169__default.createElement(TableCell, null, lo.category), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-Medium" }, lo.topic), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, lo.code))) : /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableCell, { colSpan: 4, className: "text-center h-24 text-muted-foreground" }, t4("settingsModal.topics.emptyData"))))))))), /* @__PURE__ */ React169__default.createElement(CardFooter, { className: "px-1" }, /* @__PURE__ */ React169__default.createElement(AlertDialog2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTrigger2, { asChild: true }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "destructive", disabled: learningObjectives.length === 0 }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "mr-2 h-4 w-4" }), t4("settingsModal.topics.clearAllData"))), /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, t4("settingsModal.topics.clearDataConfirmationTitle")), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, t4("settingsModal.topics.clearDataConfirmationMessage", { count: learningObjectives.length }))), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, null, t4("common.cancel")), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: handleClearData }, t4("settingsModal.topics.confirmDelete"))))))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isConfirmModalOpen, onOpenChange: setIsConfirmModalOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, t4("settingsModal.topics.confirmModal.title")), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, t4("settingsModal.topics.confirmModal.description", { count: parsedImportData?.data.length || 0 }))), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, { className: "gap-2" }, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { onClick: () => setParsedImportData(null) }, t4("common.cancel")), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: handleConfirmMerge, className: "bg-blue-600 hover:bg-blue-700" }, t4("settingsModal.topics.confirmModal.mergeButton")), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: handleConfirmOverwrite, className: "bg-amber-600 hover:bg-amber-700" }, t4("settingsModal.topics.confirmModal.overwriteButton"))))));
|
|
134763
134713
|
};
|
|
134764
134714
|
|
|
134765
134715
|
// src/react-ui/components/app/ManageImageContexts.tsx
|
|
@@ -135166,7 +135116,7 @@ var SettingsModal = ({ isOpen, onClose, defaultTab = "personal" }) => {
|
|
|
135166
135116
|
return goal.id;
|
|
135167
135117
|
}
|
|
135168
135118
|
};
|
|
135169
|
-
return /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => !open && onClose() }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-xl md:max-w-2xl lg:max-w-3xl max-h-[85vh] flex flex-col" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, { className: "shrink-0" }, /* @__PURE__ */ React169__default.createElement(DialogTitle2, { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Settings, { className: "mr-2 h-5 w-5 text-primary" }), t4("settingsModal.title")), /* @__PURE__ */ React169__default.createElement(DialogDescription2, null, t4("settingsModal.description"))), /* @__PURE__ */ React169__default.createElement(Tabs2, { value: activeTab, onValueChange: (value) => setActiveTab(value), className: "pt-2 flex-1 flex flex-col min-h-0" }, /* @__PURE__ */ React169__default.createElement(TabsList2, { className: "grid w-full grid-cols-5 shrink-0" }, /* @__PURE__ */ React169__default.createElement(TabsTrigger2, { value: "personal" }, /* @__PURE__ */ React169__default.createElement(User, { className: "mr-1 h-4 w-4" }), t4("settingsModal.personalTab")), /* @__PURE__ */ React169__default.createElement(TabsTrigger2, { value: "topics" }, /* @__PURE__ */ React169__default.createElement(ListTodo, { className: "mr-1 h-4 w-4" }), t4("settingsModal.topicsTab")), /* @__PURE__ */ React169__default.createElement(TabsTrigger2, { value: "imageContexts" }, /* @__PURE__ */ React169__default.createElement(ImagePlus, { className: "mr-1 h-4 w-4" }), "Images"), /* @__PURE__ */ React169__default.createElement(TabsTrigger2, { value: "layout" }, /* @__PURE__ */ React169__default.createElement(LayoutDashboard, { className: "mr-1 h-4 w-4" }), t4("settingsModal.layoutTab")), /* @__PURE__ */ React169__default.createElement(TabsTrigger2, { value: "apiKeys" }, /* @__PURE__ */ React169__default.createElement(KeyRound, { className: "mr-1 h-4 w-4" }), t4("settingsModal.apiKeysTab"))), /* @__PURE__ */ React169__default.createElement(TabsContent2, { value: "personal", className: "flex-1 overflow-auto mt-4" }, /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-full pr-6" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React169__default.createElement("div", { className: "p-4 border rounded-lg" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-semibold mb-3" }, t4("settingsModal.personal.basicInfo")), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "full-name" }, t4("settingsModal.personal.fullName")), /* @__PURE__ */ React169__default.createElement(Input, { id: "full-name", value: fullName, onChange: (e3) => setFullName(e3.target.value), placeholder: t4("settingsModal.personal.fullNamePlaceholder") })), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "weekly-goal" }, t4("settingsModal.personal.weeklyGoal")), /* @__PURE__ */ React169__default.createElement(Input, { id: "weekly-goal", type: "number", value: weeklyGoal, onChange: (e3) => setWeeklyGoal(parseInt(e3.target.value, 10) || 0), min: "1" })), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "language-select", className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Languages, { className: "mr-2 h-4 w-4" }), t4("settingsModal.personal.languageSelectLabel")), /* @__PURE__ */ React169__default.createElement(Select2, { value: language3, onValueChange: changeLanguage2 }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "language-select" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Select a language..." })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "en" }, "English"), /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "vi" }, "Ti\u1EBFng Vi\u1EC7t")))))), /* @__PURE__ */ React169__default.createElement("div", { className: "p-4 border rounded-lg" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-semibold mb-3 flex items-center" }, /* @__PURE__ */ React169__default.createElement(Target, { className: "mr-2 h-4 w-4" }), t4("settingsModal.personal.advancedGoals")), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2 mb-4" }, advancedGoals.map((goal) => /* @__PURE__ */ React169__default.createElement("div", { key: goal.id, className: "flex items-center justify-between p-2 bg-muted/50 rounded-md" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm flex-1" }, renderGoalDescription(goal)), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", onClick: () => handleDeleteGoal(goal.id) }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4 text-destructive" })))), advancedGoals.length === 0 && /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("settingsModal.personal.noGoals"))), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement("h5", { className: "font-medium" }, t4("settingsModal.personal.addNewGoal")), /* @__PURE__ */ React169__default.createElement(Select2, { value: newGoalType, onValueChange: (v) => setNewGoalType(v) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.goalTypePlaceholder") })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "average_score_subject" }, t4("settingsModal.personal.goalType.avgScoreSubject")), /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "mastery_topic" }, t4("settingsModal.personal.goalType.masteryTopic")))), newGoalType === "average_score_subject" && /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-2 gap-2 animate-in fade-in" }, /* @__PURE__ */ React169__default.createElement(Select2, { value: newGoalSubject, onValueChange: setNewGoalSubject }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.subjectPlaceholder") })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, allSubjects.map((s4) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: s4, value: s4 }, s4)))), /* @__PURE__ */ React169__default.createElement(Input, { type: "number", value: newGoalTargetValue, onChange: (e3) => setNewGoalTargetValue(parseInt(e3.target.value)), placeholder: t4("settingsModal.personal.targetScorePlaceholder") })), newGoalType === "mastery_topic" && /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-2 gap-2 animate-in fade-in" }, /* @__PURE__ */ React169__default.createElement(Select2, { value: newGoalSubject, onValueChange: setNewGoalSubject }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.subjectPlaceholder") })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, allSubjects.map((s4) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: s4, value: s4 }, s4)))), /* @__PURE__ */ React169__default.createElement(Select2, { value: newGoalTopic, onValueChange: setNewGoalTopic, disabled: !newGoalSubject }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.topicPlaceholder") })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, topicsForSelectedSubject.map((t5) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: t5, value: t5 }, t5)))), /* @__PURE__ */ React169__default.createElement(Input, { type: "number", value: newGoalTargetValue, onChange: (e3) => setNewGoalTargetValue(parseInt(e3.target.value)), placeholder: t4("settingsModal.personal.targetScorePlaceholder") }), /* @__PURE__ */ React169__default.createElement(Input, { type: "number", value: newGoalConsecutive, onChange: (e3) => setNewGoalConsecutive(parseInt(e3.target.value)), placeholder: t4("settingsModal.personal.consecutiveSessionsPlaceholder") })), newGoalType && /* @__PURE__ */ React169__default.createElement(Button, { size: "sm", onClick: handleAddNewGoal }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), t4("settingsModal.personal.addGoalButton"))))))), /* @__PURE__ */ React169__default.createElement(TabsContent2, { value: "topics", className: "flex-1 overflow-auto mt-4" }, /* @__PURE__ */ React169__default.createElement(ManageTopics, null)), /* @__PURE__ */ React169__default.createElement(TabsContent2, { value: "imageContexts", className: "flex-1 overflow-auto mt-4" }, /* @__PURE__ */ React169__default.createElement(ManageImageContexts, null)), /* @__PURE__ */ React169__default.createElement(TabsContent2, { value: "layout", className: "space-y-4 pt-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "p-4 border rounded-lg" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-semibold" }, t4("settingsModal.layout.title")), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground mt-1 mb-3" }, t4("settingsModal.layout.description")), /* @__PURE__ */ React169__default.createElement(AlertDialog2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTrigger2, { asChild: true }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "destructive" }, /* @__PURE__ */ React169__default.createElement(RefreshCw, { className: "mr-2 h-4 w-4" }), t4("settingsModal.layout.resetButton"))), /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, t4("settingsModal.layout.resetConfirmationTitle")), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, t4("settingsModal.layout.resetConfirmationMessage"))), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, null, t4("common.cancel")), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: handleResetLayout }, t4("settingsModal.layout.confirmReset"))))))), /* @__PURE__ */ React169__default.createElement(TabsContent2, { value: "apiKeys", className: "space-y-4 pt-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "gemini-api-key" }, t4("settingsModal.apiKeys.geminiKey")), /* @__PURE__ */ React169__default.createElement(Input, { id: "gemini-api-key", type: "password", value: geminiApiKey, onChange: (e3) => setGeminiApiKey(e3.target.value), placeholder: t4("settingsModal.apiKeys.geminiKeyPlaceholder") }), /* @__PURE__ */ React169__default.createElement("p", { className: "text-xs text-muted-foreground" }, t4("settingsModal.apiKeys.storageHint"))))), /* @__PURE__ */ React169__default.createElement(DialogFooter, { className: "gap-2 sm:justify-end pt-4 shrink-0" }, /* @__PURE__ */ React169__default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline" }, t4("common.close"))), /* @__PURE__ */ React169__default.createElement(Button, { type: "button", onClick: handleSave }, /* @__PURE__ */ React169__default.createElement(Save, { className: "mr-2 h-4 w-4" }), t4("settingsModal.saveChanges")))));
|
|
135119
|
+
return /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => !open && onClose() }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-xl md:max-w-2xl lg:max-w-3xl max-h-[85vh] flex flex-col" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, { className: "shrink-0" }, /* @__PURE__ */ React169__default.createElement(DialogTitle2, { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Settings, { className: "mr-2 h-5 w-5 text-primary" }), t4("settingsModal.title")), /* @__PURE__ */ React169__default.createElement(DialogDescription2, null, t4("settingsModal.description"))), /* @__PURE__ */ React169__default.createElement(Tabs2, { value: activeTab, onValueChange: (value) => setActiveTab(value), className: "pt-2 flex-1 flex flex-col min-h-0" }, /* @__PURE__ */ React169__default.createElement(TabsList2, { className: "grid w-full grid-cols-5 shrink-0" }, /* @__PURE__ */ React169__default.createElement(TabsTrigger2, { value: "personal" }, /* @__PURE__ */ React169__default.createElement(User, { className: "mr-1 h-4 w-4" }), t4("settingsModal.personalTab")), /* @__PURE__ */ React169__default.createElement(TabsTrigger2, { value: "topics" }, /* @__PURE__ */ React169__default.createElement(ListTodo, { className: "mr-1 h-4 w-4" }), t4("settingsModal.topicsTab")), /* @__PURE__ */ React169__default.createElement(TabsTrigger2, { value: "imageContexts" }, /* @__PURE__ */ React169__default.createElement(ImagePlus, { className: "mr-1 h-4 w-4" }), "Images"), /* @__PURE__ */ React169__default.createElement(TabsTrigger2, { value: "layout" }, /* @__PURE__ */ React169__default.createElement(LayoutDashboard, { className: "mr-1 h-4 w-4" }), t4("settingsModal.layoutTab")), /* @__PURE__ */ React169__default.createElement(TabsTrigger2, { value: "apiKeys" }, /* @__PURE__ */ React169__default.createElement(KeyRound, { className: "mr-1 h-4 w-4" }), t4("settingsModal.apiKeysTab"))), /* @__PURE__ */ React169__default.createElement(TabsContent2, { value: "personal", className: "flex-1 overflow-auto mt-4" }, /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-full pr-6" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React169__default.createElement("div", { className: "p-4 border rounded-lg" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-semibold mb-3" }, t4("settingsModal.personal.basicInfo")), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "full-name" }, t4("settingsModal.personal.fullName")), /* @__PURE__ */ React169__default.createElement(Input, { id: "full-name", value: fullName, onChange: (e3) => setFullName(e3.target.value), placeholder: t4("settingsModal.personal.fullNamePlaceholder") })), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "weekly-goal" }, t4("settingsModal.personal.weeklyGoal")), /* @__PURE__ */ React169__default.createElement(Input, { id: "weekly-goal", type: "number", value: weeklyGoal, onChange: (e3) => setWeeklyGoal(parseInt(e3.target.value, 10) || 0), min: "1" })), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "language-select", className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Languages, { className: "mr-2 h-4 w-4" }), t4("settingsModal.personal.languageSelectLabel")), /* @__PURE__ */ React169__default.createElement(Select2, { value: language3, onValueChange: changeLanguage2 }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "language-select" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Select a language..." })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "en" }, "English"), /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "vi" }, "Ti\u1EBFng Vi\u1EC7t")))))), /* @__PURE__ */ React169__default.createElement("div", { className: "p-4 border rounded-lg" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-semibold mb-3 flex items-center" }, /* @__PURE__ */ React169__default.createElement(Target, { className: "mr-2 h-4 w-4" }), t4("settingsModal.personal.advancedGoals")), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2 mb-4" }, advancedGoals.map((goal) => /* @__PURE__ */ React169__default.createElement("div", { key: goal.id, className: "flex items-center justify-between p-2 bg-muted/50 rounded-md" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm flex-1" }, renderGoalDescription(goal)), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", onClick: () => handleDeleteGoal(goal.id) }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4 text-destructive" })))), advancedGoals.length === 0 && /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground" }, t4("settingsModal.personal.noGoals"))), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement("h5", { className: "font-Medium" }, t4("settingsModal.personal.addNewGoal")), /* @__PURE__ */ React169__default.createElement(Select2, { value: newGoalType, onValueChange: (v) => setNewGoalType(v) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.goalTypePlaceholder") })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "average_score_subject" }, t4("settingsModal.personal.goalType.avgScoreSubject")), /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "mastery_topic" }, t4("settingsModal.personal.goalType.masteryTopic")))), newGoalType === "average_score_subject" && /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-2 gap-2 animate-in fade-in" }, /* @__PURE__ */ React169__default.createElement(Select2, { value: newGoalSubject, onValueChange: setNewGoalSubject }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.subjectPlaceholder") })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, allSubjects.map((s4) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: s4, value: s4 }, s4)))), /* @__PURE__ */ React169__default.createElement(Input, { type: "number", value: newGoalTargetValue, onChange: (e3) => setNewGoalTargetValue(parseInt(e3.target.value)), placeholder: t4("settingsModal.personal.targetScorePlaceholder") })), newGoalType === "mastery_topic" && /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-2 gap-2 animate-in fade-in" }, /* @__PURE__ */ React169__default.createElement(Select2, { value: newGoalSubject, onValueChange: setNewGoalSubject }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.subjectPlaceholder") })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, allSubjects.map((s4) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: s4, value: s4 }, s4)))), /* @__PURE__ */ React169__default.createElement(Select2, { value: newGoalTopic, onValueChange: setNewGoalTopic, disabled: !newGoalSubject }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: t4("settingsModal.personal.topicPlaceholder") })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, topicsForSelectedSubject.map((t5) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: t5, value: t5 }, t5)))), /* @__PURE__ */ React169__default.createElement(Input, { type: "number", value: newGoalTargetValue, onChange: (e3) => setNewGoalTargetValue(parseInt(e3.target.value)), placeholder: t4("settingsModal.personal.targetScorePlaceholder") }), /* @__PURE__ */ React169__default.createElement(Input, { type: "number", value: newGoalConsecutive, onChange: (e3) => setNewGoalConsecutive(parseInt(e3.target.value)), placeholder: t4("settingsModal.personal.consecutiveSessionsPlaceholder") })), newGoalType && /* @__PURE__ */ React169__default.createElement(Button, { size: "sm", onClick: handleAddNewGoal }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), t4("settingsModal.personal.addGoalButton"))))))), /* @__PURE__ */ React169__default.createElement(TabsContent2, { value: "topics", className: "flex-1 overflow-auto mt-4" }, /* @__PURE__ */ React169__default.createElement(ManageTopics, null)), /* @__PURE__ */ React169__default.createElement(TabsContent2, { value: "imageContexts", className: "flex-1 overflow-auto mt-4" }, /* @__PURE__ */ React169__default.createElement(ManageImageContexts, null)), /* @__PURE__ */ React169__default.createElement(TabsContent2, { value: "layout", className: "space-y-4 pt-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "p-4 border rounded-lg" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-semibold" }, t4("settingsModal.layout.title")), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-muted-foreground mt-1 mb-3" }, t4("settingsModal.layout.description")), /* @__PURE__ */ React169__default.createElement(AlertDialog2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTrigger2, { asChild: true }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "destructive" }, /* @__PURE__ */ React169__default.createElement(RefreshCw, { className: "mr-2 h-4 w-4" }), t4("settingsModal.layout.resetButton"))), /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, t4("settingsModal.layout.resetConfirmationTitle")), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, t4("settingsModal.layout.resetConfirmationMessage"))), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, null, t4("common.cancel")), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: handleResetLayout }, t4("settingsModal.layout.confirmReset"))))))), /* @__PURE__ */ React169__default.createElement(TabsContent2, { value: "apiKeys", className: "space-y-4 pt-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "gemini-api-key" }, t4("settingsModal.apiKeys.geminiKey")), /* @__PURE__ */ React169__default.createElement(Input, { id: "gemini-api-key", type: "password", value: geminiApiKey, onChange: (e3) => setGeminiApiKey(e3.target.value), placeholder: t4("settingsModal.apiKeys.geminiKeyPlaceholder") }), /* @__PURE__ */ React169__default.createElement("p", { className: "text-xs text-muted-foreground" }, t4("settingsModal.apiKeys.storageHint"))))), /* @__PURE__ */ React169__default.createElement(DialogFooter, { className: "gap-2 sm:justify-end pt-4 shrink-0" }, /* @__PURE__ */ React169__default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline" }, t4("common.close"))), /* @__PURE__ */ React169__default.createElement(Button, { type: "button", onClick: handleSave }, /* @__PURE__ */ React169__default.createElement(Save, { className: "mr-2 h-4 w-4" }), t4("settingsModal.saveChanges")))));
|
|
135170
135120
|
};
|
|
135171
135121
|
|
|
135172
135122
|
// src/react-ui/components/dashboard/Cheatsheet.tsx
|
|
@@ -135265,7 +135215,7 @@ var Cheatsheet = () => {
|
|
|
135265
135215
|
}
|
|
135266
135216
|
return null;
|
|
135267
135217
|
};
|
|
135268
|
-
return /* @__PURE__ */ React169__default.createElement(React169__default.Fragment, null, /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(BookCopy, { className: "mr-2 h-5 w-5 text-primary" }), t4("knowledgeCards.title")), /* @__PURE__ */ React169__default.createElement(CardDescription, null, t4("knowledgeCards.description"))), /* @__PURE__ */ React169__default.createElement(CardContent, { className: "space-y-4" }, /* @__PURE__ */ React169__default.createElement(Input, { type: "search", placeholder: t4("knowledgeCards.searchPlaceholder"), value: searchQuery, onChange: (e3) => setSearchQuery2(e3.target.value), disabled: allCards.length === 0 }), /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-[180px] w-full rounded-md border p-2" }, allCards.length > 0 ? filteredCards.length > 0 ? /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-1" }, filteredCards.map((card) => /* @__PURE__ */ React169__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-
|
|
135218
|
+
return /* @__PURE__ */ React169__default.createElement(React169__default.Fragment, null, /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(BookCopy, { className: "mr-2 h-5 w-5 text-primary" }), t4("knowledgeCards.title")), /* @__PURE__ */ React169__default.createElement(CardDescription, null, t4("knowledgeCards.description"))), /* @__PURE__ */ React169__default.createElement(CardContent, { className: "space-y-4" }, /* @__PURE__ */ React169__default.createElement(Input, { type: "search", placeholder: t4("knowledgeCards.searchPlaceholder"), value: searchQuery, onChange: (e3) => setSearchQuery2(e3.target.value), disabled: allCards.length === 0 }), /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-[180px] w-full rounded-md border p-2" }, allCards.length > 0 ? filteredCards.length > 0 ? /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-1" }, filteredCards.map((card) => /* @__PURE__ */ React169__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__default.createElement("div", { className: "flex items-center justify-center h-full" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-muted-foreground" }, t4("knowledgeCards.noMatch"))) : /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center justify-center h-full" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-muted-foreground" }, t4("knowledgeCards.empty")))), renderActionArea())), /* @__PURE__ */ React169__default.createElement(
|
|
135269
135219
|
CardViewerDialog,
|
|
135270
135220
|
{
|
|
135271
135221
|
isOpen: isDialogOpen,
|
|
@@ -135292,9 +135242,9 @@ var StatCard = ({
|
|
|
135292
135242
|
isLoading = false
|
|
135293
135243
|
}) => {
|
|
135294
135244
|
if (isLoading) {
|
|
135295
|
-
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2" }, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-sm font-
|
|
135245
|
+
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2" }, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-sm font-Medium" }, title), /* @__PURE__ */ React169__default.createElement(Skeleton, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(CardContent, null, /* @__PURE__ */ React169__default.createElement(Skeleton, { className: "h-8 w-3/4 mb-2" }), /* @__PURE__ */ React169__default.createElement(Skeleton, { className: "h-4 w-1/2" })));
|
|
135296
135246
|
}
|
|
135297
|
-
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2" }, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-sm font-
|
|
135247
|
+
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 pb-2" }, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "text-sm font-Medium" }, title), /* @__PURE__ */ React169__default.createElement("div", { className: "text-muted-foreground" }, icon)), /* @__PURE__ */ React169__default.createElement(CardContent, null, /* @__PURE__ */ React169__default.createElement("div", { className: "text-2xl font-bold" }, value, unit2 && /* @__PURE__ */ React169__default.createElement("span", { className: "text-xl font-Medium text-muted-foreground ml-1" }, unit2)), context && /* @__PURE__ */ React169__default.createElement("p", { className: "text-xs text-muted-foreground" }, context)));
|
|
135298
135248
|
};
|
|
135299
135249
|
|
|
135300
135250
|
// src/react-ui/components/dashboard/PerformanceSnapshot.tsx
|
|
@@ -135393,7 +135343,7 @@ var RoadmapChecklist = () => {
|
|
|
135393
135343
|
}, []);
|
|
135394
135344
|
const handleStartPractice = useCallback((item) => {
|
|
135395
135345
|
const practiceConfig = {
|
|
135396
|
-
loIds: [item.
|
|
135346
|
+
loIds: [item.code],
|
|
135397
135347
|
difficulty: item.suggestedDifficulty,
|
|
135398
135348
|
language: "Vietnamese"
|
|
135399
135349
|
};
|
|
@@ -135403,7 +135353,7 @@ var RoadmapChecklist = () => {
|
|
|
135403
135353
|
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(CalendarCheck, { className: "mr-2 h-5 w-5 text-primary" }), t4("roadmap.title")), /* @__PURE__ */ React169__default.createElement(CardDescription, null, t4("roadmap.description"))), /* @__PURE__ */ React169__default.createElement(CardContent, null, !roadmap || !roadmap.items || roadmap.items.length === 0 ? /* @__PURE__ */ React169__default.createElement("div", { className: "text-center text-muted-foreground py-8" }, /* @__PURE__ */ React169__default.createElement("p", null, t4("roadmap.emptyState")), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm" }, t4("roadmap.emptyStateSuggestion"))) : /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3" }, roadmap.items.map((item, index3) => /* @__PURE__ */ React169__default.createElement(
|
|
135404
135354
|
"div",
|
|
135405
135355
|
{
|
|
135406
|
-
key: `${item.
|
|
135356
|
+
key: `${item.code}-${index3}`,
|
|
135407
135357
|
className: "flex items-center justify-between p-3 border rounded-md bg-background hover:bg-muted/50 transition-colors"
|
|
135408
135358
|
},
|
|
135409
135359
|
/* @__PURE__ */ React169__default.createElement("div", { className: "flex items-start gap-3" }, /* @__PURE__ */ React169__default.createElement(
|
|
@@ -136946,7 +136896,7 @@ function Calendar2({
|
|
|
136946
136896
|
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
|
|
136947
136897
|
month: "space-y-4",
|
|
136948
136898
|
caption: "flex justify-center pt-1 relative items-center",
|
|
136949
|
-
caption_label: "text-sm font-
|
|
136899
|
+
caption_label: "text-sm font-Medium",
|
|
136950
136900
|
nav: "space-x-1 flex items-center",
|
|
136951
136901
|
nav_button: cn(
|
|
136952
136902
|
buttonVariants({ variant: "outline" }),
|
|
@@ -137068,7 +137018,7 @@ var AnalysisDialog = ({ isOpen, onClose }) => {
|
|
|
137068
137018
|
}
|
|
137069
137019
|
try {
|
|
137070
137020
|
const allAvailableTopics = TopicDataService.getData().map((lo) => ({
|
|
137071
|
-
|
|
137021
|
+
code: lo.code,
|
|
137072
137022
|
subject: lo.subject,
|
|
137073
137023
|
category: lo.category,
|
|
137074
137024
|
topic: lo.topic
|
|
@@ -137521,7 +137471,7 @@ var GeneratedQuizzesCard = () => {
|
|
|
137521
137471
|
onChange: (e3) => setSearchQuery2(e3.target.value),
|
|
137522
137472
|
disabled: uniqueQuizzes.length === 0
|
|
137523
137473
|
}
|
|
137524
|
-
), /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-[180px] w-full rounded-md border p-2" }, uniqueQuizzes.length > 0 ? filteredQuizzes.length > 0 ? /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-1" }, filteredQuizzes.map((quiz) => /* @__PURE__ */ React169__default.createElement("div", { key: quiz.id, className: "flex items-center justify-between p-2 rounded-md hover:bg-accent" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm font-
|
|
137474
|
+
), /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-[180px] w-full rounded-md border p-2" }, uniqueQuizzes.length > 0 ? filteredQuizzes.length > 0 ? /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-1" }, filteredQuizzes.map((quiz) => /* @__PURE__ */ React169__default.createElement("div", { key: quiz.id, className: "flex items-center justify-between p-2 rounded-md hover:bg-accent" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm font-Medium truncate pr-2", title: quiz.title }, quiz.title), /* @__PURE__ */ React169__default.createElement(Button, { size: "sm", variant: "ghost", onClick: () => handleRetake(quiz) }, /* @__PURE__ */ React169__default.createElement(CirclePlay, { className: "mr-2 h-4 w-4" }), t4("common.retake"))))) : /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center justify-center h-full" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-muted-foreground" }, t4("quizLists.generated.noMatch"))) : /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center justify-center h-full" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-muted-foreground" }, t4("quizLists.generated.empty"))))));
|
|
137525
137475
|
};
|
|
137526
137476
|
|
|
137527
137477
|
// src/react-ui/components/app/UploadResourceModal.tsx
|
|
@@ -137601,11 +137551,12 @@ var UploadResourceModal = ({ isOpen, onClose }) => {
|
|
|
137601
137551
|
language: i18n.language === "vi" ? "Vietnamese" : "English",
|
|
137602
137552
|
documentContent: textContent,
|
|
137603
137553
|
learningObjectives: learningObjectives.map((lo) => ({
|
|
137604
|
-
|
|
137554
|
+
name: lo.name,
|
|
137555
|
+
code: lo.code,
|
|
137605
137556
|
subject: lo.subject,
|
|
137606
137557
|
category: lo.category,
|
|
137607
137558
|
topic: lo.topic,
|
|
137608
|
-
|
|
137559
|
+
description: lo.description || ""
|
|
137609
137560
|
}))
|
|
137610
137561
|
}, apiKey);
|
|
137611
137562
|
setAnalysisResult(result);
|
|
@@ -137638,12 +137589,12 @@ var UploadResourceModal = ({ isOpen, onClose }) => {
|
|
|
137638
137589
|
generatedQuestions = result.generatedQuestions;
|
|
137639
137590
|
} else {
|
|
137640
137591
|
const plan = analysisResult.mappedLOs.map((lo) => {
|
|
137641
|
-
const sourceLO = TopicDataService.getData().find((orig) => orig.
|
|
137592
|
+
const sourceLO = TopicDataService.getData().find((orig) => orig.code === lo.code);
|
|
137642
137593
|
return {
|
|
137643
137594
|
plannedTopic: lo.reasoning,
|
|
137644
137595
|
plannedQuestionType: "multiple_choice",
|
|
137645
137596
|
plannedBloomLevel: "understanding",
|
|
137646
|
-
originalLoId: lo.
|
|
137597
|
+
originalLoId: lo.code,
|
|
137647
137598
|
originalTopic: sourceLO?.topic,
|
|
137648
137599
|
originalCategory: sourceLO?.category,
|
|
137649
137600
|
originalSubject: sourceLO?.subject
|
|
@@ -137688,7 +137639,7 @@ var UploadResourceModal = ({ isOpen, onClose }) => {
|
|
|
137688
137639
|
return /* @__PURE__ */ React169__default.createElement("div", { className: "flex flex-col items-center justify-center h-48" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-12 w-12 animate-spin text-primary" }), /* @__PURE__ */ React169__default.createElement("p", { className: "mt-4 text-muted-foreground font-semibold" }, stage === "analyzing" && t4("dialogs.uploadResource.analyzing"), stage === "generating" && t4("dialogs.uploadResource.generating")));
|
|
137689
137640
|
case "result":
|
|
137690
137641
|
if (!analysisResult) return null;
|
|
137691
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "py-4 space-y-4" }, /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardContent, { className: "p-4" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-semibold mb-2" }, "AI Analysis Complete"), analysisResult.isFreestyleRecommended ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-start gap-3 text-amber-700" }, /* @__PURE__ */ React169__default.createElement(BrainCircuit, { className: "h-5 w-5 mt-1 flex-shrink-0" }), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("p", { className: "font-
|
|
137642
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "py-4 space-y-4" }, /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardContent, { className: "p-4" }, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-semibold mb-2" }, "AI Analysis Complete"), analysisResult.isFreestyleRecommended ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-start gap-3 text-amber-700" }, /* @__PURE__ */ React169__default.createElement(BrainCircuit, { className: "h-5 w-5 mt-1 flex-shrink-0" }), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("p", { className: "font-Medium" }, t4("dialogs.uploadResource.freestyleRecommended")), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm" }, t4("dialogs.uploadResource.freestyleDescription")))) : /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-start gap-3 text-green-700" }, /* @__PURE__ */ React169__default.createElement(CircleCheckBig, { className: "h-5 w-5 mt-1 flex-shrink-0" }), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("p", { className: "font-Medium" }, t4("dialogs.uploadResource.curriculumMatch")), /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm" }, t4("dialogs.uploadResource.curriculumDescription")), /* @__PURE__ */ React169__default.createElement("p", { className: "text-xs mt-2 font-semibold" }, t4("dialogs.uploadResource.mappedTopics")), /* @__PURE__ */ React169__default.createElement("ul", { className: "list-disc list-inside text-xs" }, analysisResult.mappedLOs.map((lo) => /* @__PURE__ */ React169__default.createElement("li", { key: lo.code }, TopicDataService.getData().find((orig) => orig.code === lo.code)?.topic || lo.code))))))), error && /* @__PURE__ */ React169__default.createElement(Alert, { variant: "destructive" }, /* @__PURE__ */ React169__default.createElement(CircleAlert, { className: "h-4 w-4" }), /* @__PURE__ */ React169__default.createElement(AlertTitle, null, t4("common.error")), /* @__PURE__ */ React169__default.createElement(AlertDescription, null, error)));
|
|
137692
137643
|
}
|
|
137693
137644
|
};
|
|
137694
137645
|
return /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => !open && onClose() }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-lg" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(FileText, { className: "mr-2 h-5 w-5" }), t4("dialogs.uploadResource.title")), /* @__PURE__ */ React169__default.createElement(DialogDescription2, null, t4("dialogs.uploadResource.description"))), renderContent3(), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "outline" }, t4("common.cancel"))), stage === "result" && /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleGenerateQuiz }, /* @__PURE__ */ React169__default.createElement(Sparkles, { className: "mr-2 h-4 w-4" }), t4("dialogs.uploadResource.generateButton")))));
|
|
@@ -137809,7 +137760,7 @@ var FreestyleQuizzesCard = () => {
|
|
|
137809
137760
|
onChange: (e3) => setSearchQuery2(e3.target.value),
|
|
137810
137761
|
disabled: uniqueQuizzes.length === 0
|
|
137811
137762
|
}
|
|
137812
|
-
), /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-[180px] w-full rounded-md border p-2" }, uniqueQuizzes.length > 0 ? filteredQuizzes.length > 0 ? /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-1" }, filteredQuizzes.map((quiz) => /* @__PURE__ */ React169__default.createElement("div", { key: quiz.id, className: "flex items-center justify-between p-2 rounded-md hover:bg-accent" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm font-
|
|
137763
|
+
), /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "h-[180px] w-full rounded-md border p-2" }, uniqueQuizzes.length > 0 ? filteredQuizzes.length > 0 ? /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-1" }, filteredQuizzes.map((quiz) => /* @__PURE__ */ React169__default.createElement("div", { key: quiz.id, className: "flex items-center justify-between p-2 rounded-md hover:bg-accent" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm font-Medium truncate pr-2", title: quiz.title }, quiz.title), /* @__PURE__ */ React169__default.createElement(Button, { size: "sm", variant: "ghost", onClick: () => handleRetake(quiz) }, /* @__PURE__ */ React169__default.createElement(CirclePlay, { className: "mr-2 h-4 w-4" }), t4("common.retake"))))) : /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center justify-center h-full" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-muted-foreground" }, t4("quizLists.freestyle.noMatch"))) : /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center justify-center h-full" }, /* @__PURE__ */ React169__default.createElement("p", { className: "text-muted-foreground" }, t4("quizLists.freestyle.empty"))))));
|
|
137813
137764
|
};
|
|
137814
137765
|
|
|
137815
137766
|
// src/react-ui/components/common/ClientTranslation.tsx
|
|
@@ -137959,7 +137910,7 @@ var PersonalPracticeDashboard = ({ settingsPath, initialHistory, initialStats, i
|
|
|
137959
137910
|
}
|
|
137960
137911
|
try {
|
|
137961
137912
|
const allAvailableTopics = TopicDataService.getData().map((lo) => ({
|
|
137962
|
-
|
|
137913
|
+
code: lo.code,
|
|
137963
137914
|
subject: lo.subject,
|
|
137964
137915
|
category: lo.category,
|
|
137965
137916
|
topic: lo.topic
|
|
@@ -138453,7 +138404,7 @@ var PracticeModeController = () => {
|
|
|
138453
138404
|
try {
|
|
138454
138405
|
const config3 = JSON.parse(suggestedConfigString);
|
|
138455
138406
|
const allLOs = TopicDataService.getData();
|
|
138456
|
-
const suggestedLOs = allLOs.filter((lo) => config3.loIds?.includes(lo.
|
|
138407
|
+
const suggestedLOs = allLOs.filter((lo) => config3.loIds?.includes(lo.code));
|
|
138457
138408
|
if (suggestedLOs.length > 0) {
|
|
138458
138409
|
setInitialSuggestedLOs(suggestedLOs);
|
|
138459
138410
|
setInitialSuggestedDifficulty(config3.difficulty || "Medium");
|
|
@@ -138496,9 +138447,10 @@ var PracticeModeController = () => {
|
|
|
138496
138447
|
totalQuestions,
|
|
138497
138448
|
numCodingQuestions,
|
|
138498
138449
|
topics: selectedLOs.map((lo) => ({
|
|
138499
|
-
topic: lo.
|
|
138450
|
+
topic: lo.name || lo.code,
|
|
138451
|
+
// FIX: Provide fallback for name
|
|
138500
138452
|
ratio: 100 / selectedLOs.length,
|
|
138501
|
-
originalLoId: lo.
|
|
138453
|
+
originalLoId: lo.code,
|
|
138502
138454
|
originalSubject: lo.subject,
|
|
138503
138455
|
originalCategory: lo.category,
|
|
138504
138456
|
originalTopic: lo.topic
|
|
@@ -138690,7 +138642,7 @@ var SuggestionDialog = ({
|
|
|
138690
138642
|
if (!suggestion) {
|
|
138691
138643
|
return /* @__PURE__ */ React169__default.createElement("div", { className: "flex flex-col items-center justify-center h-64 gap-4" }, /* @__PURE__ */ React169__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."));
|
|
138692
138644
|
}
|
|
138693
|
-
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React169__default.createElement("div", { className: "p-4 bg-muted/50 rounded-lg" }, /* @__PURE__ */ React169__default.createElement(MarkdownRenderer, { content: suggestion.suggestionText })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-semibold mb-3" }, "K\u1EBF ho\u1EA1ch Luy\u1EC7n t\u1EADp \u0111\u01B0\u1EE3c G\u1EE3i \xFD:"), /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "max-h-[200px] pr-3" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3" }, suggestion.suggestedTopics.map((topic) => /* @__PURE__ */ React169__default.createElement("div", { key: topic.
|
|
138645
|
+
return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React169__default.createElement("div", { className: "p-4 bg-muted/50 rounded-lg" }, /* @__PURE__ */ React169__default.createElement(MarkdownRenderer, { content: suggestion.suggestionText })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement("h4", { className: "font-semibold mb-3" }, "K\u1EBF ho\u1EA1ch Luy\u1EC7n t\u1EADp \u0111\u01B0\u1EE3c G\u1EE3i \xFD:"), /* @__PURE__ */ React169__default.createElement(ScrollArea2, { className: "max-h-[200px] pr-3" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3" }, suggestion.suggestedTopics.map((topic) => /* @__PURE__ */ React169__default.createElement("div", { key: topic.code, className: "flex items-center justify-between p-3 border rounded-md" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex-1 mr-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2 mb-1" }, topic.reason === "review" ? /* @__PURE__ */ React169__default.createElement(Badge2, { variant: "destructive" }, /* @__PURE__ */ React169__default.createElement(RefreshCw, { className: "h-3 w-3 mr-1.5" }), "\xD4n t\u1EADp") : /* @__PURE__ */ React169__default.createElement(Badge2, { variant: "secondary" }, /* @__PURE__ */ React169__default.createElement(Search, { className: "h-3 w-3 mr-1.5" }), "Kh\xE1m ph\xE1")), /* @__PURE__ */ React169__default.createElement("p", { className: "font-Medium" }, topic.topicName)), /* @__PURE__ */ React169__default.createElement(Button, { size: "sm", onClick: () => onStartSuggestedPractice(topic) }, /* @__PURE__ */ React169__default.createElement(CirclePlay, { className: "h-4 w-4 mr-2" }), "B\u1EAFt \u0111\u1EA7u")))))));
|
|
138694
138646
|
};
|
|
138695
138647
|
return /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => !open && onClose() }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-lg md:max-w-xl" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, { className: "flex items-center text-2xl" }, /* @__PURE__ */ React169__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__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__default.createElement("div", { className: "py-4" }, renderContent3()), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline" }, "\u0110\xF3ng")))));
|
|
138696
138648
|
};
|
|
@@ -138700,12 +138652,96 @@ init_react_shim();
|
|
|
138700
138652
|
|
|
138701
138653
|
// src/react-ui/components/metadata/SubjectManager.tsx
|
|
138702
138654
|
init_react_shim();
|
|
138655
|
+
|
|
138656
|
+
// src/react-ui/components/metadata/MetadataImportControls.tsx
|
|
138657
|
+
init_react_shim();
|
|
138658
|
+
function MetadataImportControls({ metadataName, onImport }) {
|
|
138659
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
138660
|
+
const [jsonString, setJsonString] = useState("");
|
|
138661
|
+
const [isImporting, startImportTransition] = useTransition();
|
|
138662
|
+
const fileInputRef = useRef(null);
|
|
138663
|
+
const { toast: toast2 } = useToast();
|
|
138664
|
+
const processAndImportRecords = async (records, importSource) => {
|
|
138665
|
+
if (records.length === 0) {
|
|
138666
|
+
toast2({ title: "No Data", description: `The selected ${importSource === "file" ? "file" : "JSON string"} contains no data to import.`, variant: "destructive" });
|
|
138667
|
+
return;
|
|
138668
|
+
}
|
|
138669
|
+
await onImport(records);
|
|
138670
|
+
setIsOpen(false);
|
|
138671
|
+
setJsonString("");
|
|
138672
|
+
};
|
|
138673
|
+
const handleFileSelected = (event) => {
|
|
138674
|
+
const file = event.target.files?.[0];
|
|
138675
|
+
if (!file) return;
|
|
138676
|
+
if (file.type !== "application/json" && !file.name.endsWith(".csv")) {
|
|
138677
|
+
toast2({ title: "Invalid File Type", description: "Please select a JSON or CSV file.", variant: "destructive" });
|
|
138678
|
+
if (event.target) event.target.value = "";
|
|
138679
|
+
return;
|
|
138680
|
+
}
|
|
138681
|
+
startImportTransition(async () => {
|
|
138682
|
+
try {
|
|
138683
|
+
const fileContent = await file.text();
|
|
138684
|
+
let records = [];
|
|
138685
|
+
if (file.type === "application/json") {
|
|
138686
|
+
records = JSON.parse(fileContent);
|
|
138687
|
+
if (!Array.isArray(records)) throw new Error("JSON file must contain an array of objects.");
|
|
138688
|
+
} else if (file.name.endsWith(".csv")) {
|
|
138689
|
+
const lines = fileContent.split(/\r\n|\n/).filter((line) => line.trim() !== "");
|
|
138690
|
+
if (lines.length < 2) throw new Error("CSV must have a header and at least one data row.");
|
|
138691
|
+
const headers = lines[0].split(",").map((h3) => h3.trim());
|
|
138692
|
+
records = lines.slice(1).map((line) => {
|
|
138693
|
+
const values = line.split(",").map((v) => v.trim());
|
|
138694
|
+
const record = {};
|
|
138695
|
+
headers.forEach((header, index3) => {
|
|
138696
|
+
record[header] = values[index3];
|
|
138697
|
+
});
|
|
138698
|
+
return record;
|
|
138699
|
+
});
|
|
138700
|
+
}
|
|
138701
|
+
await processAndImportRecords(records, "file");
|
|
138702
|
+
} catch (err) {
|
|
138703
|
+
toast2({ title: "Import Error", description: `Failed to process file: ${err.message}`, variant: "destructive" });
|
|
138704
|
+
}
|
|
138705
|
+
});
|
|
138706
|
+
if (event.target) event.target.value = "";
|
|
138707
|
+
};
|
|
138708
|
+
const handleJsonStringImport = () => {
|
|
138709
|
+
if (!jsonString.trim()) {
|
|
138710
|
+
toast2({ title: "Missing Data", description: "JSON string cannot be empty.", variant: "destructive" });
|
|
138711
|
+
return;
|
|
138712
|
+
}
|
|
138713
|
+
startImportTransition(async () => {
|
|
138714
|
+
try {
|
|
138715
|
+
const records = JSON.parse(jsonString);
|
|
138716
|
+
if (!Array.isArray(records)) throw new Error("JSON string must represent an array of objects.");
|
|
138717
|
+
await processAndImportRecords(records, "text");
|
|
138718
|
+
} catch (err) {
|
|
138719
|
+
toast2({ title: "Import Error", description: `Failed to process JSON string: ${err.message}`, variant: "destructive" });
|
|
138720
|
+
}
|
|
138721
|
+
});
|
|
138722
|
+
};
|
|
138723
|
+
return /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isOpen, onOpenChange: setIsOpen }, /* @__PURE__ */ React169__default.createElement(DialogTrigger2, { asChild: true }, /* @__PURE__ */ React169__default.createElement(Button, { size: "sm", variant: "outline" }, /* @__PURE__ */ React169__default.createElement(Upload, { className: "mr-2 h-4 w-4" }), " Import ", metadataName)), /* @__PURE__ */ React169__default.createElement(DialogContent2, null, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, "Bulk Import ", metadataName), /* @__PURE__ */ React169__default.createElement(DialogDescription2, null, "Import multiple records from a file or by pasting JSON data.")), /* @__PURE__ */ React169__default.createElement(Tabs2, { defaultValue: "file" }, /* @__PURE__ */ React169__default.createElement(TabsList2, { className: "grid w-full grid-cols-2" }, /* @__PURE__ */ React169__default.createElement(TabsTrigger2, { value: "file" }, /* @__PURE__ */ React169__default.createElement(FileJson, { className: "mr-2 h-4 w-4" }), " From File"), /* @__PURE__ */ React169__default.createElement(TabsTrigger2, { value: "text" }, /* @__PURE__ */ React169__default.createElement(ClipboardPaste, { className: "mr-2 h-4 w-4" }), " From Text")), /* @__PURE__ */ React169__default.createElement(TabsContent2, { value: "file", className: "pt-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ React169__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__default.createElement(Button, { variant: "outline", onClick: () => fileInputRef.current?.click(), disabled: isImporting }, isImporting ? /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React169__default.createElement(Upload, { className: "mr-2 h-4 w-4" }), isImporting ? "Importing..." : "Select File"), /* @__PURE__ */ React169__default.createElement("input", { type: "file", ref: fileInputRef, onChange: handleFileSelected, accept: ".json,.csv", className: "hidden" }))), /* @__PURE__ */ React169__default.createElement(TabsContent2, { value: "text", className: "pt-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-3" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "jsonInput" }, "JSON Data (Array of Objects)"), /* @__PURE__ */ React169__default.createElement(
|
|
138724
|
+
Textarea,
|
|
138725
|
+
{
|
|
138726
|
+
id: "jsonInput",
|
|
138727
|
+
value: jsonString,
|
|
138728
|
+
onChange: (e3) => setJsonString(e3.target.value),
|
|
138729
|
+
placeholder: '[{"code": "SUB1", "name": "Subject 1"}, ...]',
|
|
138730
|
+
rows: 8,
|
|
138731
|
+
className: "font-mono text-xs",
|
|
138732
|
+
disabled: isImporting
|
|
138733
|
+
}
|
|
138734
|
+
), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleJsonStringImport, disabled: isImporting || !jsonString.trim() }, isImporting ? /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React169__default.createElement(ClipboardPaste, { className: "mr-2 h-4 w-4" }), "Import from Text"))))));
|
|
138735
|
+
}
|
|
138736
|
+
|
|
138737
|
+
// src/react-ui/components/metadata/SubjectManager.tsx
|
|
138703
138738
|
function SubjectManager({
|
|
138704
138739
|
initialData,
|
|
138705
138740
|
isLoading: isLoadingProp,
|
|
138706
138741
|
onAdd,
|
|
138707
138742
|
onUpdate,
|
|
138708
|
-
onDelete
|
|
138743
|
+
onDelete,
|
|
138744
|
+
onBulkAdd
|
|
138709
138745
|
}) {
|
|
138710
138746
|
const [subjects, setSubjects] = useState([]);
|
|
138711
138747
|
const [isLoading, setIsLoading] = useState(true);
|
|
@@ -138803,12 +138839,37 @@ function SubjectManager({
|
|
|
138803
138839
|
}
|
|
138804
138840
|
});
|
|
138805
138841
|
};
|
|
138806
|
-
|
|
138842
|
+
const handleImport = async (records) => {
|
|
138843
|
+
if (!onBulkAdd) return;
|
|
138844
|
+
const validatedRecords = records.map((rec) => {
|
|
138845
|
+
if (typeof rec.code === "string" && typeof rec.name === "string") {
|
|
138846
|
+
return { code: rec.code, name: rec.name };
|
|
138847
|
+
}
|
|
138848
|
+
return null;
|
|
138849
|
+
}).filter((rec) => rec !== null);
|
|
138850
|
+
if (validatedRecords.length !== records.length) {
|
|
138851
|
+
toast2({
|
|
138852
|
+
title: "Import Warning",
|
|
138853
|
+
description: "Some records had invalid or missing 'code' or 'name' fields and were ignored.",
|
|
138854
|
+
variant: "destructive"
|
|
138855
|
+
});
|
|
138856
|
+
}
|
|
138857
|
+
if (validatedRecords.length > 0) {
|
|
138858
|
+
await onBulkAdd(validatedRecords);
|
|
138859
|
+
}
|
|
138860
|
+
};
|
|
138861
|
+
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(BookCopy, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Subjects"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__default.createElement(
|
|
138862
|
+
MetadataImportControls,
|
|
138863
|
+
{
|
|
138864
|
+
metadataName: "Subjects",
|
|
138865
|
+
onImport: handleImport
|
|
138866
|
+
}
|
|
138867
|
+
), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Subject")))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : subjects.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No subjects found. Add one to get started!") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Created At"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Updated At"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, subjects.map((subject) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: subject.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, subject.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-Medium" }, subject.name), /* @__PURE__ */ React169__default.createElement(TableCell, null, format(new Date(subject.createdAt), "dd/MM/yyyy HH:mm")), /* @__PURE__ */ React169__default.createElement(TableCell, null, format(new Date(subject.updatedAt), "dd/MM/yyyy HH:mm")), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(subject), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(subject), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentSubject ? "Edit Subject" : "Add New Subject"), /* @__PURE__ */ React169__default.createElement(DialogDescription2, null, currentSubject ? "Update the details of the subject." : "Enter details for the new subject.")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "subjectCode", value: subjectCode, onChange: (e3) => setSubjectCode(e3.target.value.toUpperCase()), placeholder: "e.g., MATH", disabled: !!currentSubject })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subjectName" }, "Subject Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "subjectName", value: subjectName, onChange: (e3) => setSubjectName(e3.target.value), placeholder: "e.g., Mathematics" }))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !subjectName.trim() || !subjectCode.trim() }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This action cannot be undone. This will permanently delete the subject "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
138807
138868
|
}
|
|
138808
138869
|
|
|
138809
138870
|
// src/react-ui/components/metadata/GradeLevelManager.tsx
|
|
138810
138871
|
init_react_shim();
|
|
138811
|
-
function GradeLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
|
|
138872
|
+
function GradeLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
|
|
138812
138873
|
const [items, setItems] = useState([]);
|
|
138813
138874
|
const [isLoading, setIsLoading] = useState(true);
|
|
138814
138875
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
@@ -138905,7 +138966,26 @@ function GradeLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpd
|
|
|
138905
138966
|
}
|
|
138906
138967
|
});
|
|
138907
138968
|
};
|
|
138908
|
-
|
|
138969
|
+
const handleImport = async (records) => {
|
|
138970
|
+
if (!onBulkAdd) return;
|
|
138971
|
+
const validatedRecords = records.map((rec) => {
|
|
138972
|
+
if (typeof rec.code === "string" && typeof rec.name === "string") {
|
|
138973
|
+
return { code: rec.code, name: rec.name };
|
|
138974
|
+
}
|
|
138975
|
+
return null;
|
|
138976
|
+
}).filter((rec) => rec !== null);
|
|
138977
|
+
if (validatedRecords.length !== records.length) {
|
|
138978
|
+
toast2({
|
|
138979
|
+
title: "Import Warning",
|
|
138980
|
+
description: "Some records had invalid or missing 'code' or 'name' fields and were ignored.",
|
|
138981
|
+
variant: "destructive"
|
|
138982
|
+
});
|
|
138983
|
+
}
|
|
138984
|
+
if (validatedRecords.length > 0) {
|
|
138985
|
+
await onBulkAdd(validatedRecords);
|
|
138986
|
+
}
|
|
138987
|
+
};
|
|
138988
|
+
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Award, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Grade Levels"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__default.createElement(MetadataImportControls, { metadataName: "Grade Levels", onImport: handleImport }), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Grade Level")))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No grade levels found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-Medium" }, item.name), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Grade Level" : "Add New Grade Level")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., G9", disabled: !!currentItem })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Grade 9" }))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemName.trim() || !itemCode.trim() }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
138909
138989
|
}
|
|
138910
138990
|
|
|
138911
138991
|
// src/react-ui/components/metadata/TopicManager.tsx
|
|
@@ -138916,7 +138996,8 @@ function TopicManager({
|
|
|
138916
138996
|
isLoading: isLoadingProp,
|
|
138917
138997
|
onAdd,
|
|
138918
138998
|
onUpdate,
|
|
138919
|
-
onDelete
|
|
138999
|
+
onDelete,
|
|
139000
|
+
onBulkAdd
|
|
138920
139001
|
}) {
|
|
138921
139002
|
const [topics, setTopics] = useState([]);
|
|
138922
139003
|
const [subjects, setSubjects] = useState([]);
|
|
@@ -139020,15 +139101,34 @@ function TopicManager({
|
|
|
139020
139101
|
}
|
|
139021
139102
|
});
|
|
139022
139103
|
};
|
|
139104
|
+
const handleImport = async (records) => {
|
|
139105
|
+
if (!onBulkAdd) return;
|
|
139106
|
+
const validatedRecords = records.map((rec) => {
|
|
139107
|
+
if (typeof rec.code === "string" && typeof rec.name === "string" && typeof rec.subjectCode === "string") {
|
|
139108
|
+
return { code: rec.code, name: rec.name, subjectCode: rec.subjectCode };
|
|
139109
|
+
}
|
|
139110
|
+
return null;
|
|
139111
|
+
}).filter((rec) => rec !== null);
|
|
139112
|
+
if (validatedRecords.length !== records.length) {
|
|
139113
|
+
toast2({
|
|
139114
|
+
title: "Import Warning",
|
|
139115
|
+
description: "Some records had invalid or missing 'code', 'name', or 'subjectCode' fields and were ignored.",
|
|
139116
|
+
variant: "destructive"
|
|
139117
|
+
});
|
|
139118
|
+
}
|
|
139119
|
+
if (validatedRecords.length > 0) {
|
|
139120
|
+
await onBulkAdd(validatedRecords);
|
|
139121
|
+
}
|
|
139122
|
+
};
|
|
139023
139123
|
const getSubjectName = (subjectCode) => {
|
|
139024
139124
|
return subjects.find((s4) => s4.code === subjectCode)?.name || "N/A";
|
|
139025
139125
|
};
|
|
139026
|
-
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Tag, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Topics"), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm", disabled: subjects.length === 0 }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Topic")), subjects.length === 0 && !isLoading && /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-destructive" }, "Please add subjects before adding topics.")), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : topics.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No topics found. Add one to get started!") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, topics.map((topic) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: topic.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, topic.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-
|
|
139126
|
+
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Tag, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Topics"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__default.createElement(MetadataImportControls, { metadataName: "Topics", onImport: handleImport }), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm", disabled: subjects.length === 0 }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Topic"))), subjects.length === 0 && !isLoading && /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-destructive" }, "Please add subjects before adding topics.")), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : topics.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No topics found. Add one to get started!") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, topics.map((topic) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: topic.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, topic.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-Medium" }, topic.name), /* @__PURE__ */ React169__default.createElement(TableCell, null, getSubjectName(topic.subjectCode), " (", topic.subjectCode, ")"), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(topic), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(topic), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Topic" : "Add New Topic")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemCode" }, "Topic Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., ALG-BASICS", disabled: !!currentItem })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemName" }, "Topic Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Algebra Basics" })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject"), /* @__PURE__ */ React169__default.createElement(Select2, { value: selectedSubjectCode, onValueChange: setSelectedSubjectCode, disabled: subjects.length === 0 }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "subjectCode" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Select a subject" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, subjects.map((subject) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: subject.code, value: subject.code }, subject.name, " (", subject.code, ")")))))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemName.trim() || !itemCode.trim() || !selectedSubjectCode }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete topic "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
139027
139127
|
}
|
|
139028
139128
|
|
|
139029
139129
|
// src/react-ui/components/metadata/CategoryManager.tsx
|
|
139030
139130
|
init_react_shim();
|
|
139031
|
-
function CategoryManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
|
|
139131
|
+
function CategoryManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
|
|
139032
139132
|
const [items, setItems] = useState([]);
|
|
139033
139133
|
const [isLoading, setIsLoading] = useState(true);
|
|
139034
139134
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
@@ -139128,12 +139228,37 @@ function CategoryManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdat
|
|
|
139128
139228
|
}
|
|
139129
139229
|
});
|
|
139130
139230
|
};
|
|
139131
|
-
|
|
139231
|
+
const handleImport = async (records) => {
|
|
139232
|
+
if (!onBulkAdd) return;
|
|
139233
|
+
const validationResult = records.reduce((acc, rec) => {
|
|
139234
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
139235
|
+
acc.valid.push({
|
|
139236
|
+
code: rec.code,
|
|
139237
|
+
name: rec.name,
|
|
139238
|
+
description: typeof rec.description === "string" ? rec.description : void 0
|
|
139239
|
+
});
|
|
139240
|
+
} else {
|
|
139241
|
+
acc.invalidCount++;
|
|
139242
|
+
}
|
|
139243
|
+
return acc;
|
|
139244
|
+
}, { valid: [], invalidCount: 0 });
|
|
139245
|
+
if (validationResult.invalidCount > 0) {
|
|
139246
|
+
toast2({
|
|
139247
|
+
title: "Import Warning",
|
|
139248
|
+
description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
|
|
139249
|
+
variant: "destructive"
|
|
139250
|
+
});
|
|
139251
|
+
}
|
|
139252
|
+
if (validationResult.valid.length > 0) {
|
|
139253
|
+
await onBulkAdd(validationResult.valid);
|
|
139254
|
+
}
|
|
139255
|
+
};
|
|
139256
|
+
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Layers, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Categories"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__default.createElement(MetadataImportControls, { metadataName: "Categories", onImport: handleImport }), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Category")))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No categories found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-Medium" }, item.name), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Category" : "Add New Category")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., CORE_CONCEPT", disabled: !!currentItem })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Core Concept" })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Fundamental ideas within a subject." }))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemName.trim() || !itemCode.trim() }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
139132
139257
|
}
|
|
139133
139258
|
|
|
139134
139259
|
// src/react-ui/components/metadata/BloomLevelManager.tsx
|
|
139135
139260
|
init_react_shim();
|
|
139136
|
-
function BloomLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
|
|
139261
|
+
function BloomLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
|
|
139137
139262
|
const [items, setItems] = useState([]);
|
|
139138
139263
|
const [isLoading, setIsLoading] = useState(true);
|
|
139139
139264
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
@@ -139233,12 +139358,37 @@ function BloomLevelManager({ initialData, isLoading: isLoadingProp, onAdd, onUpd
|
|
|
139233
139358
|
}
|
|
139234
139359
|
});
|
|
139235
139360
|
};
|
|
139236
|
-
|
|
139361
|
+
const handleImport = async (records) => {
|
|
139362
|
+
if (!onBulkAdd) return;
|
|
139363
|
+
const validationResult = records.reduce((acc, rec) => {
|
|
139364
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
139365
|
+
acc.valid.push({
|
|
139366
|
+
code: rec.code,
|
|
139367
|
+
name: rec.name,
|
|
139368
|
+
description: typeof rec.description === "string" ? rec.description : void 0
|
|
139369
|
+
});
|
|
139370
|
+
} else {
|
|
139371
|
+
acc.invalidCount++;
|
|
139372
|
+
}
|
|
139373
|
+
return acc;
|
|
139374
|
+
}, { valid: [], invalidCount: 0 });
|
|
139375
|
+
if (validationResult.invalidCount > 0) {
|
|
139376
|
+
toast2({
|
|
139377
|
+
title: "Import Warning",
|
|
139378
|
+
description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
|
|
139379
|
+
variant: "destructive"
|
|
139380
|
+
});
|
|
139381
|
+
}
|
|
139382
|
+
if (validationResult.valid.length > 0) {
|
|
139383
|
+
await onBulkAdd(validationResult.valid);
|
|
139384
|
+
}
|
|
139385
|
+
};
|
|
139386
|
+
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Brain, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Bloom's Levels"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__default.createElement(MetadataImportControls, { metadataName: "Bloom's Levels", onImport: handleImport }), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Bloom's Level")))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Bloom's Levels found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-Medium" }, item.name), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Bloom's Level" : "Add New Bloom's Level")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., REMEMBER", disabled: !!currentItem })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Remembering" })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Recall facts and basic concepts." }))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemCode.trim() || !itemName.trim() }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
139237
139387
|
}
|
|
139238
139388
|
|
|
139239
139389
|
// src/react-ui/components/metadata/QuestionTypeManager.tsx
|
|
139240
139390
|
init_react_shim();
|
|
139241
|
-
function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
|
|
139391
|
+
function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
|
|
139242
139392
|
const [items, setItems] = useState([]);
|
|
139243
139393
|
const [isLoading, setIsLoading] = useState(true);
|
|
139244
139394
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
@@ -139308,6 +139458,31 @@ function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onU
|
|
|
139308
139458
|
}
|
|
139309
139459
|
});
|
|
139310
139460
|
};
|
|
139461
|
+
const handleImport = async (records) => {
|
|
139462
|
+
if (!onBulkAdd) return;
|
|
139463
|
+
const validationResult = records.reduce((acc, rec) => {
|
|
139464
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
139465
|
+
acc.valid.push({
|
|
139466
|
+
code: rec.code,
|
|
139467
|
+
name: rec.name,
|
|
139468
|
+
description: typeof rec.description === "string" ? rec.description : void 0
|
|
139469
|
+
});
|
|
139470
|
+
} else {
|
|
139471
|
+
acc.invalidCount++;
|
|
139472
|
+
}
|
|
139473
|
+
return acc;
|
|
139474
|
+
}, { valid: [], invalidCount: 0 });
|
|
139475
|
+
if (validationResult.invalidCount > 0) {
|
|
139476
|
+
toast2({
|
|
139477
|
+
title: "Import Warning",
|
|
139478
|
+
description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
|
|
139479
|
+
variant: "destructive"
|
|
139480
|
+
});
|
|
139481
|
+
}
|
|
139482
|
+
if (validationResult.valid.length > 0) {
|
|
139483
|
+
await onBulkAdd(validationResult.valid);
|
|
139484
|
+
}
|
|
139485
|
+
};
|
|
139311
139486
|
const handleSubmit = () => {
|
|
139312
139487
|
if (!itemName.trim() || !itemCode.trim()) {
|
|
139313
139488
|
toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
|
|
@@ -139338,22 +139513,19 @@ function QuestionTypeManager({ initialData, isLoading: isLoadingProp, onAdd, onU
|
|
|
139338
139513
|
}
|
|
139339
139514
|
});
|
|
139340
139515
|
};
|
|
139341
|
-
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(CircleHelp, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Question Types"), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Question Type"))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Question Types found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-
|
|
139516
|
+
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(CircleHelp, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Question Types"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__default.createElement(MetadataImportControls, { metadataName: "Question Types", onImport: handleImport }), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Question Type")))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Question Types found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-Medium" }, item.name), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Question Type" : "Add New Question Type")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React169__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__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Multiple Choice" })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React169__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__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemCode.trim() || !itemName.trim() }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
139342
139517
|
}
|
|
139343
139518
|
|
|
139344
139519
|
// src/react-ui/components/metadata/LearningObjectiveManager.tsx
|
|
139345
139520
|
init_react_shim();
|
|
139346
|
-
function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
|
|
139521
|
+
function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
|
|
139347
139522
|
const [items, setItems] = useState([]);
|
|
139348
139523
|
const [subjects, setSubjects] = useState([]);
|
|
139349
139524
|
const [isLoading, setIsLoading] = useState(true);
|
|
139350
139525
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
139351
139526
|
const [isAlertOpen, setIsAlertOpen] = useState(false);
|
|
139352
139527
|
const [currentItem, setCurrentItem] = useState(null);
|
|
139353
|
-
const [
|
|
139354
|
-
const [itemCode, setItemCode] = useState("");
|
|
139355
|
-
const [itemDescription, setItemDescription] = useState("");
|
|
139356
|
-
const [selectedSubjectCode, setSelectedSubjectCode] = useState(void 0);
|
|
139528
|
+
const [formState, setFormState] = useState({});
|
|
139357
139529
|
const [itemToDelete, setItemToDelete] = useState(null);
|
|
139358
139530
|
const [isPending, startTransition] = useTransition();
|
|
139359
139531
|
const { toast: toast2 } = useToast();
|
|
@@ -139380,20 +139552,17 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
|
|
|
139380
139552
|
refreshData();
|
|
139381
139553
|
}
|
|
139382
139554
|
}, [isControlled, initialData, subjectsProp, isLoadingProp]);
|
|
139555
|
+
const handleFormChange = (field, value) => {
|
|
139556
|
+
setFormState((prev) => ({ ...prev, [field]: value }));
|
|
139557
|
+
};
|
|
139383
139558
|
const handleAddItem = () => {
|
|
139384
139559
|
setCurrentItem(null);
|
|
139385
|
-
|
|
139386
|
-
setItemCode("");
|
|
139387
|
-
setItemDescription("");
|
|
139388
|
-
setSelectedSubjectCode(subjects.length > 0 ? subjects[0].code : void 0);
|
|
139560
|
+
setFormState({ subjectCode: subjects.length > 0 ? subjects[0].code : "" });
|
|
139389
139561
|
setIsDialogOpen(true);
|
|
139390
139562
|
};
|
|
139391
139563
|
const handleEditItem = (item) => {
|
|
139392
139564
|
setCurrentItem(item);
|
|
139393
|
-
|
|
139394
|
-
setItemCode(item.code);
|
|
139395
|
-
setItemDescription(item.description || "");
|
|
139396
|
-
setSelectedSubjectCode(item.subjectCode);
|
|
139565
|
+
setFormState(item);
|
|
139397
139566
|
setIsDialogOpen(true);
|
|
139398
139567
|
};
|
|
139399
139568
|
const handleDeleteItem = (item) => {
|
|
@@ -139420,7 +139589,7 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
|
|
|
139420
139589
|
});
|
|
139421
139590
|
};
|
|
139422
139591
|
const handleSubmit = () => {
|
|
139423
|
-
if (!
|
|
139592
|
+
if (!formState.name?.trim() || !formState.code?.trim()) {
|
|
139424
139593
|
toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
|
|
139425
139594
|
return;
|
|
139426
139595
|
}
|
|
@@ -139428,17 +139597,17 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
|
|
|
139428
139597
|
try {
|
|
139429
139598
|
if (currentItem) {
|
|
139430
139599
|
if (isControlled && onUpdate) {
|
|
139431
|
-
await onUpdate({
|
|
139600
|
+
await onUpdate({ ...currentItem, ...formState });
|
|
139432
139601
|
} else {
|
|
139433
|
-
MetadataService.updateLearningObjective(currentItem.id,
|
|
139602
|
+
MetadataService.updateLearningObjective(currentItem.id, formState);
|
|
139434
139603
|
refreshData();
|
|
139435
139604
|
}
|
|
139436
139605
|
toast2({ title: "Success", description: "Learning Objective updated." });
|
|
139437
139606
|
} else {
|
|
139438
139607
|
if (isControlled && onAdd) {
|
|
139439
|
-
await onAdd(
|
|
139608
|
+
await onAdd(formState);
|
|
139440
139609
|
} else {
|
|
139441
|
-
MetadataService.addLearningObjective(
|
|
139610
|
+
MetadataService.addLearningObjective(formState);
|
|
139442
139611
|
refreshData();
|
|
139443
139612
|
}
|
|
139444
139613
|
toast2({ title: "Success", description: "Learning Objective added." });
|
|
@@ -139449,16 +139618,14 @@ function LearningObjectiveManager({ initialData, subjects: subjectsProp, isLoadi
|
|
|
139449
139618
|
}
|
|
139450
139619
|
});
|
|
139451
139620
|
};
|
|
139452
|
-
const
|
|
139453
|
-
if (!subjectCode) return "N/A";
|
|
139454
|
-
return subjects.find((s4) => s4.code === subjectCode)?.name || "N/A";
|
|
139621
|
+
const handleImport = async (records) => {
|
|
139455
139622
|
};
|
|
139456
|
-
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Learning Objectives"), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective"))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React169__default.createElement(TableCell, null, getSubjectName(item.subjectCode)), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), disabled: !!currentItem })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemSubject" }, "Subject (Optional)"), /* @__PURE__ */ React169__default.createElement(Select2, { value: selectedSubjectCode || "", onValueChange: (value) => setSelectedSubjectCode(value === "_NONE_" ? void 0 : value) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "itemSubject" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, { placeholder: "Select a subject" })), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, /* @__PURE__ */ React169__default.createElement(SelectItem2, { value: "_NONE_" }, "No Specific Subject"), subjects.map((subject) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: subject.id, value: subject.code }, subject.name))))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value) }))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemName.trim() || !itemCode.trim() }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
139623
|
+
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Lightbulb, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Learning Objectives"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__default.createElement(MetadataImportControls, { metadataName: "Learning Objectives", onImport: handleImport }), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Learning Objective")))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Learning Objectives found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Subject"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Topic"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-medium" }, item.name), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.subject || item.subjectCode), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.topic || item.topicCode), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Learning Objective" : "Add New Learning Objective")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "code" }, "Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "code", value: formState.code || "", onChange: (e3) => handleFormChange("code", e3.target.value.toUpperCase()), disabled: !!currentItem })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "name" }, "Name (Description)"), /* @__PURE__ */ React169__default.createElement(Input, { id: "name", value: formState.name || "", onChange: (e3) => handleFormChange("name", e3.target.value) }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subject" }, "Subject Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "subject", value: formState.subject || "", onChange: (e3) => handleFormChange("subject", e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "subjectCode" }, "Subject Code"), /* @__PURE__ */ React169__default.createElement(EditableCombobox, { options: subjects.map((s4) => ({ value: s4.code, label: s4.name })), value: formState.subjectCode || "", onChange: (val) => handleFormChange("subjectCode", val), placeholder: "Select a subject..." }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "category" }, "Category Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "category", value: formState.category || "", onChange: (e3) => handleFormChange("category", e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "categoryCode" }, "Category Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "categoryCode", value: formState.categoryCode || "", onChange: (e3) => handleFormChange("categoryCode", e3.target.value) }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "topic" }, "Topic Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "topic", value: formState.topic || "", onChange: (e3) => handleFormChange("topic", e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "topicCode" }, "Topic Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "topicCode", value: formState.topicCode || "", onChange: (e3) => handleFormChange("topicCode", e3.target.value) }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "grade" }, "Grade Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "grade", value: formState.grade || "", onChange: (e3) => handleFormChange("grade", e3.target.value) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "gradeCode" }, "Grade Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "gradeCode", value: formState.gradeCode || "", onChange: (e3) => handleFormChange("gradeCode", e3.target.value) }))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "keywords" }, "Keywords (comma-separated)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "keywords", value: formState.keywords?.join(", ") || "", onChange: (e3) => handleFormChange("keywords", e3.target.value.split(",").map((s4) => s4.trim())) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "stemElements" }, "STEM Elements (comma-separated)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "stemElements", value: formState.stemElements?.join(", ") || "", onChange: (e3) => handleFormChange("stemElements", e3.target.value.split(",").map((s4) => s4.trim())) })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "bloomLevelsGuideline" }, "Bloom's Guideline (comma-separated)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "bloomLevelsGuideline", value: formState.bloomLevelsGuideline?.join(", ") || "", onChange: (e3) => handleFormChange("bloomLevelsGuideline", e3.target.value.split(",").map((s4) => s4.trim())) }))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !formState.name?.trim() || !formState.code?.trim() }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
139457
139624
|
}
|
|
139458
139625
|
|
|
139459
139626
|
// src/react-ui/components/metadata/ContextManager.tsx
|
|
139460
139627
|
init_react_shim();
|
|
139461
|
-
function ContextManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete }) {
|
|
139628
|
+
function ContextManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate, onDelete, onBulkAdd }) {
|
|
139462
139629
|
const [items, setItems] = useState([]);
|
|
139463
139630
|
const [isLoading, setIsLoading] = useState(true);
|
|
139464
139631
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
@@ -139528,6 +139695,31 @@ function ContextManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate
|
|
|
139528
139695
|
}
|
|
139529
139696
|
});
|
|
139530
139697
|
};
|
|
139698
|
+
const handleImport = async (records) => {
|
|
139699
|
+
if (!onBulkAdd) return;
|
|
139700
|
+
const validationResult = records.reduce((acc, rec) => {
|
|
139701
|
+
if (typeof rec.code === "string" && rec.code.trim() && typeof rec.name === "string" && rec.name.trim()) {
|
|
139702
|
+
acc.valid.push({
|
|
139703
|
+
code: rec.code,
|
|
139704
|
+
name: rec.name,
|
|
139705
|
+
description: typeof rec.description === "string" ? rec.description : void 0
|
|
139706
|
+
});
|
|
139707
|
+
} else {
|
|
139708
|
+
acc.invalidCount++;
|
|
139709
|
+
}
|
|
139710
|
+
return acc;
|
|
139711
|
+
}, { valid: [], invalidCount: 0 });
|
|
139712
|
+
if (validationResult.invalidCount > 0) {
|
|
139713
|
+
toast2({
|
|
139714
|
+
title: "Import Warning",
|
|
139715
|
+
description: `${validationResult.invalidCount} records had invalid or missing 'code' or 'name' fields and were ignored.`,
|
|
139716
|
+
variant: "destructive"
|
|
139717
|
+
});
|
|
139718
|
+
}
|
|
139719
|
+
if (validationResult.valid.length > 0) {
|
|
139720
|
+
await onBulkAdd(validationResult.valid);
|
|
139721
|
+
}
|
|
139722
|
+
};
|
|
139531
139723
|
const handleSubmit = () => {
|
|
139532
139724
|
if (!itemName.trim() || !itemCode.trim()) {
|
|
139533
139725
|
toast2({ title: "Validation Error", description: "Code and Name are required.", variant: "destructive" });
|
|
@@ -139558,13 +139750,13 @@ function ContextManager({ initialData, isLoading: isLoadingProp, onAdd, onUpdate
|
|
|
139558
139750
|
}
|
|
139559
139751
|
});
|
|
139560
139752
|
};
|
|
139561
|
-
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(ScanText, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Contexts"), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Context"))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Contexts found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-
|
|
139753
|
+
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(ScanText, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Contexts"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__default.createElement(MetadataImportControls, { metadataName: "Categories", onImport: handleImport }), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Context")))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Contexts found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Code"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Description"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-mono text-xs" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-Medium" }, item.name), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.description), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-md" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Context" : "Add New Context")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemCode" }, "Code"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemCode", value: itemCode, onChange: (e3) => setItemCode(e3.target.value.toUpperCase()), placeholder: "e.g., HIST_INQ", disabled: !!currentItem })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemName" }, "Name"), /* @__PURE__ */ React169__default.createElement(Input, { id: "itemName", value: itemName, onChange: (e3) => setItemName(e3.target.value), placeholder: "e.g., Historical Inquiry" })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "itemDescription" }, "Description (Optional)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "itemDescription", value: itemDescription, onChange: (e3) => setItemDescription(e3.target.value), placeholder: "e.g., Analyzing primary and secondary sources." }))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending || !itemCode.trim() || !itemName.trim() }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.name, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
139562
139754
|
}
|
|
139563
139755
|
|
|
139564
139756
|
// src/react-ui/components/metadata/ApproachManager.tsx
|
|
139565
139757
|
init_react_shim();
|
|
139566
139758
|
var knowledgeDimensions = ["Factual", "Conceptual", "Procedural"];
|
|
139567
|
-
var
|
|
139759
|
+
var standardDifficulties = ["Easy", "Medium", "Hard"];
|
|
139568
139760
|
function ApproachManager({
|
|
139569
139761
|
initialData,
|
|
139570
139762
|
bloomLevels: bloomLevelsProp,
|
|
@@ -139572,7 +139764,8 @@ function ApproachManager({
|
|
|
139572
139764
|
isLoading: isLoadingProp,
|
|
139573
139765
|
onAdd,
|
|
139574
139766
|
onUpdate,
|
|
139575
|
-
onDelete
|
|
139767
|
+
onDelete,
|
|
139768
|
+
onBulkAdd
|
|
139576
139769
|
}) {
|
|
139577
139770
|
const [items, setItems] = useState([]);
|
|
139578
139771
|
const [bloomLevels, setBloomLevels] = useState([]);
|
|
@@ -139613,7 +139806,7 @@ function ApproachManager({
|
|
|
139613
139806
|
const resetForm = () => {
|
|
139614
139807
|
setFormState({
|
|
139615
139808
|
knowledgeDimension: "Factual",
|
|
139616
|
-
|
|
139809
|
+
difficulty: ["Medium"],
|
|
139617
139810
|
bloomLevelCode: bloomLevels.length > 0 ? bloomLevels[0].code : "",
|
|
139618
139811
|
iSpringQuizType: questionTypes.length > 0 ? questionTypes[0].code : "multiple_choice"
|
|
139619
139812
|
});
|
|
@@ -139625,18 +139818,7 @@ function ApproachManager({
|
|
|
139625
139818
|
};
|
|
139626
139819
|
const handleEditItem = (item) => {
|
|
139627
139820
|
setCurrentItem(item);
|
|
139628
|
-
setFormState(
|
|
139629
|
-
code: item.code,
|
|
139630
|
-
verbEn: item.verbEn,
|
|
139631
|
-
verbVi: item.verbVi,
|
|
139632
|
-
bloomLevelCode: item.bloomLevelCode,
|
|
139633
|
-
knowledgeDimension: item.knowledgeDimension,
|
|
139634
|
-
iSpringQuizType: item.iSpringQuizType,
|
|
139635
|
-
rawDifficulty: item.rawDifficulty,
|
|
139636
|
-
suggestContext: item.suggestContext,
|
|
139637
|
-
exampleEn: item.exampleEn,
|
|
139638
|
-
exampleVi: item.exampleVi
|
|
139639
|
-
});
|
|
139821
|
+
setFormState(item);
|
|
139640
139822
|
setIsDialogOpen(true);
|
|
139641
139823
|
};
|
|
139642
139824
|
const handleDeleteItem = (item) => {
|
|
@@ -139663,9 +139845,9 @@ function ApproachManager({
|
|
|
139663
139845
|
});
|
|
139664
139846
|
};
|
|
139665
139847
|
const handleSubmit = () => {
|
|
139666
|
-
const { code: code4, verbEn, verbVi, bloomLevelCode, iSpringQuizType, knowledgeDimension,
|
|
139667
|
-
if (!code4?.trim() || !verbEn?.trim() || !verbVi?.trim() || !bloomLevelCode || !iSpringQuizType || !knowledgeDimension || !
|
|
139668
|
-
toast2({ title: "Validation Error", description: "All fields except examples and context are required.", variant: "destructive" });
|
|
139848
|
+
const { code: code4, name: name3, verbEn, verbVi, bloomLevelCode, iSpringQuizType, knowledgeDimension, difficulty } = formState;
|
|
139849
|
+
if (!code4?.trim() || !name3?.trim() || !verbEn?.trim() || !verbVi?.trim() || !bloomLevelCode || !iSpringQuizType || !knowledgeDimension || !difficulty || difficulty.length === 0) {
|
|
139850
|
+
toast2({ title: "Validation Error", description: "All fields except examples and context are required, and at least one difficulty must be selected.", variant: "destructive" });
|
|
139669
139851
|
return;
|
|
139670
139852
|
}
|
|
139671
139853
|
startTransition(async () => {
|
|
@@ -139693,7 +139875,47 @@ function ApproachManager({
|
|
|
139693
139875
|
}
|
|
139694
139876
|
});
|
|
139695
139877
|
};
|
|
139696
|
-
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Settings2, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Approaches"), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Approach"))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Approaches found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Approach ID"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Verb (VI)"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Cognitive Level"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "iSpring Type"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-medium" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.verbVi), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.bloomLevelCode), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.iSpringQuizType), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Approach" : "Add New Approach")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "code" }, "Approach Code"), /* @__PURE__ */ React169__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__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "verbEn" }, "Verb (English)"), /* @__PURE__ */ React169__default.createElement(Input, { id: "verbEn", value: formState.verbEn || "", onChange: (e3) => setFormState((s4) => ({ ...s4, verbEn: e3.target.value })), placeholder: "e.g., Identify" }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "verbVi" }, "Verb (Vietnamese)"), /* @__PURE__ */ React169__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__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "bloomLevelCode" }, "Cognitive Level"), /* @__PURE__ */ React169__default.createElement(Select2, { value: formState.bloomLevelCode, onValueChange: (v) => setFormState((s4) => ({ ...s4, bloomLevelCode: v })) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, bloomLevels.map((level) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: level.code, value: level.code }, level.name)))))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "knowledgeDimension" }, "Knowledge Dimension"), /* @__PURE__ */ React169__default.createElement(Select2, { value: formState.knowledgeDimension, onValueChange: (v) => setFormState((s4) => ({ ...s4, knowledgeDimension: v })) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, knowledgeDimensions.map((kd) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: kd, value: kd }, kd))))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "iSpringQuizType" }, "iSpring Quiz Type"), /* @__PURE__ */ React169__default.createElement(Select2, { value: formState.iSpringQuizType, onValueChange: (v) => setFormState((s4) => ({ ...s4, iSpringQuizType: v })) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, questionTypes.map((qt) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: qt.code, value: qt.code }, qt.name))))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "rawDifficulty" }, "Raw Difficulty"), /* @__PURE__ */ React169__default.createElement(Select2, { value: formState.rawDifficulty, onValueChange: (v) => setFormState((s4) => ({ ...s4, rawDifficulty: v })) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, rawDifficultyLevels.map((rd) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: rd, value: rd }, rd)))))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "suggestContext" }, "Suggest Context (comma-separated codes)"), /* @__PURE__ */ React169__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__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "exampleEn" }, "Example (English)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "exampleEn", value: formState.exampleEn || "", onChange: (e3) => setFormState((s4) => ({ ...s4, exampleEn: e3.target.value })), placeholder: "English example prompt..." })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "exampleVi" }, "Example (Vietnamese)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "exampleVi", value: formState.exampleVi || "", onChange: (e3) => setFormState((s4) => ({ ...s4, exampleVi: e3.target.value })), placeholder: "Vietnamese example prompt..." }))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.code, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
139878
|
+
const handleImport = async (records) => {
|
|
139879
|
+
if (!onBulkAdd) return;
|
|
139880
|
+
const parseStringToArray = (input) => {
|
|
139881
|
+
if (Array.isArray(input)) return input;
|
|
139882
|
+
if (typeof input === "string") return input.split(",").map((s4) => s4.trim()).filter(Boolean);
|
|
139883
|
+
return [];
|
|
139884
|
+
};
|
|
139885
|
+
const validatedRecords = records.reduce((acc, rec) => {
|
|
139886
|
+
if (rec.code && rec.name && rec.verbEn && rec.verbVi && rec.knowledgeDimension && rec.iSpringQuizType && rec.difficulty && rec.bloomLevelCode) {
|
|
139887
|
+
acc.push({
|
|
139888
|
+
code: rec.code,
|
|
139889
|
+
name: rec.name,
|
|
139890
|
+
verbEn: rec.verbEn,
|
|
139891
|
+
verbVi: rec.verbVi,
|
|
139892
|
+
knowledgeDimension: rec.knowledgeDimension,
|
|
139893
|
+
iSpringQuizType: rec.iSpringQuizType,
|
|
139894
|
+
difficulty: parseStringToArray(rec.difficulty),
|
|
139895
|
+
bloomLevelCode: rec.bloomLevelCode,
|
|
139896
|
+
suggestContext: rec.suggestContext,
|
|
139897
|
+
exampleEn: rec.exampleEn,
|
|
139898
|
+
exampleVi: rec.exampleVi
|
|
139899
|
+
});
|
|
139900
|
+
}
|
|
139901
|
+
return acc;
|
|
139902
|
+
}, []);
|
|
139903
|
+
if (validatedRecords.length !== records.length) {
|
|
139904
|
+
toast2({
|
|
139905
|
+
title: "Import Warning",
|
|
139906
|
+
description: `${records.length - validatedRecords.length} records had missing required fields and were ignored.`,
|
|
139907
|
+
variant: "destructive"
|
|
139908
|
+
});
|
|
139909
|
+
}
|
|
139910
|
+
if (validatedRecords.length > 0) {
|
|
139911
|
+
await onBulkAdd(validatedRecords);
|
|
139912
|
+
}
|
|
139913
|
+
};
|
|
139914
|
+
return /* @__PURE__ */ React169__default.createElement(Card, null, /* @__PURE__ */ React169__default.createElement(CardHeader, null, /* @__PURE__ */ React169__default.createElement(CardTitle, { className: "flex justify-between items-center" }, /* @__PURE__ */ React169__default.createElement("span", { className: "flex items-center" }, /* @__PURE__ */ React169__default.createElement(Settings2, { className: "mr-2 h-5 w-5 text-primary" }), " Manage Approaches"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center gap-2" }, onBulkAdd && /* @__PURE__ */ React169__default.createElement(MetadataImportControls, { metadataName: "Approaches", onImport: handleImport }), /* @__PURE__ */ React169__default.createElement(Button, { onClick: handleAddItem, size: "sm" }, /* @__PURE__ */ React169__default.createElement(CirclePlus, { className: "mr-2 h-4 w-4" }), " Add Approach")))), /* @__PURE__ */ React169__default.createElement(CardContent, null, isLoading ? /* @__PURE__ */ React169__default.createElement("div", { className: "flex justify-center items-center h-32" }, /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "h-8 w-8 animate-spin text-primary" })) : items.length === 0 ? /* @__PURE__ */ React169__default.createElement("p", { className: "text-center text-muted-foreground py-4" }, "No Approaches found.") : /* @__PURE__ */ React169__default.createElement("div", { className: "overflow-x-auto" }, /* @__PURE__ */ React169__default.createElement(Table3, null, /* @__PURE__ */ React169__default.createElement(TableHeader, null, /* @__PURE__ */ React169__default.createElement(TableRow, null, /* @__PURE__ */ React169__default.createElement(TableHead, null, "Approach ID"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Name"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Verb (VI)"), /* @__PURE__ */ React169__default.createElement(TableHead, null, "Cognitive Level"), /* @__PURE__ */ React169__default.createElement(TableHead, { className: "text-right w-[120px]" }, "Actions"))), /* @__PURE__ */ React169__default.createElement(TableBody, null, items.map((item) => /* @__PURE__ */ React169__default.createElement(TableRow, { key: item.id }, /* @__PURE__ */ React169__default.createElement(TableCell, { className: "font-Medium" }, item.code), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.name), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.verbVi), /* @__PURE__ */ React169__default.createElement(TableCell, null, item.bloomLevelCode), /* @__PURE__ */ React169__default.createElement(TableCell, { className: "text-right" }, /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleEditItem(item), className: "mr-2" }, /* @__PURE__ */ React169__default.createElement(PenLine, { className: "h-4 w-4" })), /* @__PURE__ */ React169__default.createElement(Button, { variant: "ghost", size: "icon", onClick: () => handleDeleteItem(item), className: "text-destructive hover:text-destructive" }, /* @__PURE__ */ React169__default.createElement(Trash2, { className: "h-4 w-4" })))))))), /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isDialogOpen, onOpenChange: setIsDialogOpen }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-2xl max-h-[90vh] overflow-y-auto" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, null, currentItem ? "Edit Approach" : "Add New Approach")), /* @__PURE__ */ React169__default.createElement("div", { className: "grid gap-4 py-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "code" }, "Approach Code"), /* @__PURE__ */ React169__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__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "name" }, "Name / Description"), /* @__PURE__ */ React169__default.createElement(Input, { id: "name", value: formState.name || "", onChange: (e3) => setFormState((s4) => ({ ...s4, name: e3.target.value })), placeholder: "e.g., Identify a Fact" }))), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "verbEn" }, "Verb (English)"), /* @__PURE__ */ React169__default.createElement(Input, { id: "verbEn", value: formState.verbEn || "", onChange: (e3) => setFormState((s4) => ({ ...s4, verbEn: e3.target.value })), placeholder: "e.g., Identify" })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "verbVi" }, "Verb (Vietnamese)"), /* @__PURE__ */ React169__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__default.createElement("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "bloomLevelCode" }, "Cognitive Level"), /* @__PURE__ */ React169__default.createElement(Select2, { value: formState.bloomLevelCode, onValueChange: (v) => setFormState((s4) => ({ ...s4, bloomLevelCode: v })) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, bloomLevels.map((level) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: level.code, value: level.code }, level.name))))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "knowledgeDimension" }, "Knowledge Dimension"), /* @__PURE__ */ React169__default.createElement(Select2, { value: formState.knowledgeDimension, onValueChange: (v) => setFormState((s4) => ({ ...s4, knowledgeDimension: v })) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, knowledgeDimensions.map((kd) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: kd, value: kd }, kd))))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "iSpringQuizType" }, "iSpring Quiz Type"), /* @__PURE__ */ React169__default.createElement(Select2, { value: formState.iSpringQuizType, onValueChange: (v) => setFormState((s4) => ({ ...s4, iSpringQuizType: v })) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, questionTypes.map((qt) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: qt.code, value: qt.code }, qt.name)))))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, null, "Difficulty"), /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center space-x-4 pt-2" }, standardDifficulties.map((diff2) => /* @__PURE__ */ React169__default.createElement("div", { key: diff2, className: "flex items-center space-x-2" }, /* @__PURE__ */ React169__default.createElement(Checkbox2, { id: `diff-${diff2}`, checked: (formState.difficulty || []).includes(diff2), onCheckedChange: (checked) => {
|
|
139915
|
+
const current = formState.difficulty || [];
|
|
139916
|
+
const newDiff = checked ? [...current, diff2] : current.filter((d) => d !== diff2);
|
|
139917
|
+
setFormState((s4) => ({ ...s4, difficulty: newDiff }));
|
|
139918
|
+
} }), /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: `diff-${diff2}` }, diff2))))), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "suggestContext" }, "Suggest Context (comma-separated codes)"), /* @__PURE__ */ React169__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__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "exampleEn" }, "Example (English)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "exampleEn", value: formState.exampleEn || "", onChange: (e3) => setFormState((s4) => ({ ...s4, exampleEn: e3.target.value })), placeholder: "English example prompt..." })), /* @__PURE__ */ React169__default.createElement("div", null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "exampleVi" }, "Example (Vietnamese)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "exampleVi", value: formState.exampleVi || "", onChange: (e3) => setFormState((s4) => ({ ...s4, exampleVi: e3.target.value })), placeholder: "Vietnamese example prompt..." }))), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__PURE__ */ React169__default.createElement(Button, { type: "button", variant: "outline", onClick: () => setIsDialogOpen(false), disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(Button, { type: "submit", onClick: handleSubmit, disabled: isPending }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Save")))), /* @__PURE__ */ React169__default.createElement(AlertDialog2, { open: isAlertOpen, onOpenChange: setIsAlertOpen }, /* @__PURE__ */ React169__default.createElement(AlertDialogContent2, null, /* @__PURE__ */ React169__default.createElement(AlertDialogHeader, null, /* @__PURE__ */ React169__default.createElement(AlertDialogTitle2, null, "Are you sure?"), /* @__PURE__ */ React169__default.createElement(AlertDialogDescription2, null, 'This will permanently delete "', itemToDelete?.code, '".')), /* @__PURE__ */ React169__default.createElement(AlertDialogFooter, null, /* @__PURE__ */ React169__default.createElement(AlertDialogCancel2, { disabled: isPending }, "Cancel"), /* @__PURE__ */ React169__default.createElement(AlertDialogAction2, { onClick: confirmDelete, disabled: isPending, className: "bg-destructive hover:bg-destructive/90" }, isPending && /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }), " Delete"))))));
|
|
139697
139919
|
}
|
|
139698
139920
|
|
|
139699
139921
|
// src/react-ui/components/metadata/MetadataTabs.tsx
|
|
@@ -140369,7 +140591,7 @@ var ToastAction2 = React169.forwardRef(({ className, ...props }, ref) => /* @__P
|
|
|
140369
140591
|
{
|
|
140370
140592
|
ref,
|
|
140371
140593
|
className: cn(
|
|
140372
|
-
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-
|
|
140594
|
+
"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",
|
|
140373
140595
|
className
|
|
140374
140596
|
),
|
|
140375
140597
|
...props
|
|
@@ -141964,4 +142186,4 @@ react-tooltip/dist/react-tooltip.min.mjs:
|
|
|
141964
142186
|
*)
|
|
141965
142187
|
*/
|
|
141966
142188
|
|
|
141967
|
-
export { AIFullQuizGeneratorModal, AIQuestionGeneratorModal, APIKeyManagerModal, Accordion2 as Accordion, AccordionContent2 as AccordionContent, AccordionItem2 as AccordionItem, AccordionTrigger2 as AccordionTrigger, Achievements, ActivityCalendar, Alert, AlertDescription, AlertTitle, ApiKeySettings, ApproachManager, Badge2 as Badge, BloomLevelManager, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CategoryManager, Cheatsheet, Checkbox2 as Checkbox, ContextManager, Dialog2 as Dialog, DialogContent2 as DialogContent, DialogDescription2 as DialogDescription, DialogFooter, DialogHeader, DialogTitle2 as DialogTitle, EditQuestionModal, FreestyleQuizzesCard, GeneratedQuizzesCard, GradeLevelManager, ImportQuestionsModal, Input, Label2 as Label, LanguageProvider, LearningObjectiveManager, ManageTopics, MetadataTabs, PerformanceCharts, PersonalPracticeDashboard, PracticeHistoryTable, PracticeModeController, Progress2 as Progress, QuestionFilters, QuestionFormDialog, QuestionList, QuestionPreviewModal, QuestionRenderer, QuestionTypeManager, QuizAuthoringTool, QuizDataManagement, QuizPlayer, QuizResult, QuizReview, QuizSettingsForm, RadioGroup2 as RadioGroup, RadioGroupItem2 as RadioGroupItem, SCORMExportModal, ScrollArea2 as ScrollArea, Select2 as Select, SelectContent2 as SelectContent, SelectItem2 as SelectItem, SelectTrigger2 as SelectTrigger, SelectValue2 as SelectValue, SelectedQuestionsPanel, SettingsModal, Skeleton, SubjectManager, SuggestionDialog, Tabs2 as Tabs, TabsContent2 as TabsContent, TabsList2 as TabsList, TabsTrigger2 as TabsTrigger, Toaster, Tooltip2 as Tooltip, TooltipContent2 as TooltipContent, TooltipProvider2 as TooltipProvider, TooltipTrigger2 as TooltipTrigger, TopicManager, UploadResourceModal, toast, useToast };
|
|
142189
|
+
export { AIFullQuizGeneratorModal, AIQuestionGeneratorModal, APIKeyManagerModal, Accordion2 as Accordion, AccordionContent2 as AccordionContent, AccordionItem2 as AccordionItem, AccordionTrigger2 as AccordionTrigger, Achievements, ActivityCalendar, Alert, AlertDescription, AlertTitle, ApiKeySettings, ApproachManager, Badge2 as Badge, BloomLevelManager, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CategoryManager, Cheatsheet, Checkbox2 as Checkbox, ContextManager, Dialog2 as Dialog, DialogContent2 as DialogContent, DialogDescription2 as DialogDescription, DialogFooter, DialogHeader, DialogTitle2 as DialogTitle, EditQuestionModal, FreestyleQuizzesCard, GeneratedQuizzesCard, GradeLevelManager, ImportQuestionsModal, Input, Label2 as Label, LanguageProvider, LearningObjectiveManager, ManageTopics, MetadataImportControls, MetadataTabs, PerformanceCharts, PersonalPracticeDashboard, PracticeHistoryTable, PracticeModeController, Progress2 as Progress, QuestionFilters, QuestionFormDialog, QuestionList, QuestionPreviewModal, QuestionRenderer, QuestionTypeManager, QuizAuthoringTool, QuizDataManagement, QuizPlayer, QuizResult, QuizReview, QuizSettingsForm, RadioGroup2 as RadioGroup, RadioGroupItem2 as RadioGroupItem, SCORMExportModal, ScrollArea2 as ScrollArea, Select2 as Select, SelectContent2 as SelectContent, SelectItem2 as SelectItem, SelectTrigger2 as SelectTrigger, SelectValue2 as SelectValue, SelectedQuestionsPanel, SettingsModal, Skeleton, SubjectManager, SuggestionDialog, Tabs2 as Tabs, TabsContent2 as TabsContent, TabsList2 as TabsList, TabsTrigger2 as TabsTrigger, Toaster, Tooltip2 as Tooltip, TooltipContent2 as TooltipContent, TooltipProvider2 as TooltipProvider, TooltipTrigger2 as TooltipTrigger, TopicManager, UploadResourceModal, toast, useToast };
|