@thanh01.pmt/interactive-quiz-kit 1.0.73 → 1.0.74

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.
@@ -71671,21 +71671,30 @@ var EditableCombobox = ({
71671
71671
  disabled = false
71672
71672
  }) => {
71673
71673
  const [open, setOpen] = React119__namespace.useState(false);
71674
- const [inputValue, setInputValue] = React119__namespace.useState(value);
71674
+ const [inputValue, setInputValue] = React119__namespace.useState("");
71675
71675
  React119__namespace.useEffect(() => {
71676
- setInputValue(value);
71677
- }, [value]);
71678
- const handleSelect = (currentValue) => {
71679
- const newValue = currentValue === value ? "" : currentValue;
71680
- onChange(newValue);
71681
- setInputValue(newValue);
71676
+ if (value) {
71677
+ const selectedOption = options.find((option) => option.value.toLowerCase() === value.toLowerCase());
71678
+ setInputValue(selectedOption ? selectedOption.label : value);
71679
+ } else {
71680
+ setInputValue("");
71681
+ }
71682
+ }, [value, options, open]);
71683
+ const handleSelect = (selectedValue) => {
71684
+ onChange(selectedValue);
71682
71685
  setOpen(false);
71683
71686
  };
71684
- const handleBlur = () => {
71685
- onChange(inputValue);
71687
+ const handleOpenChange = (isOpen) => {
71688
+ if (!isOpen) {
71689
+ const match2 = options.find((option) => option.label.toLowerCase() === inputValue.toLowerCase());
71690
+ if (!match2 && inputValue !== (options.find((opt) => opt.value === value)?.label || value)) {
71691
+ onChange(inputValue);
71692
+ }
71693
+ }
71694
+ setOpen(isOpen);
71686
71695
  };
71687
71696
  const displayLabel = options.find((option) => option.value.toLowerCase() === value?.toLowerCase())?.label || value;
71688
- return /* @__PURE__ */ React119__namespace.createElement(Popover2, { open, onOpenChange: setOpen }, /* @__PURE__ */ React119__namespace.createElement(PopoverTrigger2, { asChild: true }, /* @__PURE__ */ React119__namespace.createElement(
71697
+ return /* @__PURE__ */ React119__namespace.createElement(Popover2, { open, onOpenChange: handleOpenChange }, /* @__PURE__ */ React119__namespace.createElement(PopoverTrigger2, { asChild: true }, /* @__PURE__ */ React119__namespace.createElement(
71689
71698
  Button,
71690
71699
  {
71691
71700
  variant: "outline",
@@ -71701,8 +71710,7 @@ var EditableCombobox = ({
71701
71710
  {
71702
71711
  placeholder: searchPlaceholder,
71703
71712
  value: inputValue,
71704
- onValueChange: setInputValue,
71705
- onBlur: handleBlur
71713
+ onValueChange: setInputValue
71706
71714
  }
71707
71715
  ), /* @__PURE__ */ React119__namespace.createElement(CommandList, null, /* @__PURE__ */ React119__namespace.createElement(CommandEmpty, null, noResultsMessage), /* @__PURE__ */ React119__namespace.createElement(CommandGroup, null, options.map((option) => /* @__PURE__ */ React119__namespace.createElement(
71708
71716
  CommandItem,
@@ -73001,6 +73009,10 @@ var supportedQuestionTypesForAI = [
73001
73009
  { value: "sequence", label: "Sequence" },
73002
73010
  { value: "matching", label: "Matching" }
73003
73011
  ];
73012
+ var availableLanguages = [
73013
+ { value: "English", label: "English" },
73014
+ { value: "Vietnamese", label: "Ti\u1EBFng Vi\u1EC7t" }
73015
+ ];
73004
73016
  var AIQuestionGeneratorModal = ({
73005
73017
  isOpen,
73006
73018
  onClose,
@@ -73010,51 +73022,65 @@ var AIQuestionGeneratorModal = ({
73010
73022
  subjects = [],
73011
73023
  topics = [],
73012
73024
  gradeLevels = [],
73013
- bloomLevels = []
73025
+ bloomLevels = [],
73026
+ categories = []
73014
73027
  }) => {
73015
- const [prompt, setPrompt] = React119.useState("");
73028
+ const [additionalInfo, setAdditionalInfo] = React119.useState("");
73016
73029
  const [isLoading, setIsLoading] = React119.useState(false);
73017
73030
  const [error, setError] = React119.useState(null);
73018
73031
  const { toast: toast2 } = useToast();
73019
73032
  const [subjectCode, setSubjectCode] = React119.useState("");
73033
+ const [categoryCode, setCategoryCode] = React119.useState("");
73020
73034
  const [topicCode, setTopicCode] = React119.useState("");
73021
73035
  const [gradeBand, setGradeBand] = React119.useState("");
73022
73036
  const [bloomLevelCode, setBloomLevelCode] = React119.useState("");
73023
73037
  const [selectedQuestionType, setSelectedQuestionType] = React119.useState("multiple_choice");
73038
+ const [selectedLanguage, setSelectedLanguage] = React119.useState(language3);
73024
73039
  const [numberOfOptions, setNumberOfOptions] = React119.useState(4);
73025
- const [minCorrectAnswers, setMinCorrectAnswers] = React119.useState(2);
73026
- const [maxCorrectAnswers, setMaxCorrectAnswers] = React119.useState(3);
73027
- const [isCaseSensitive, setIsCaseSensitive] = React119.useState(false);
73028
- const [numberOfBlanks, setNumberOfBlanks] = React119.useState(2);
73029
- const [numberOfSequenceItems, setNumberOfSequenceItems] = React119.useState(4);
73030
- const [numberOfMatchingPairs, setNumberOfMatchingPairs] = React119.useState(4);
73031
73040
  const [isApiKeyManagerModalOpen, setIsApiKeyManagerModalOpen] = React119.useState(false);
73032
73041
  const [geminiApiKeyExists, setGeminiApiKeyExists] = React119.useState(false);
73033
73042
  const finalQuestionType = questionTypeProp || selectedQuestionType;
73034
73043
  React119.useEffect(() => {
73035
73044
  if (isOpen) {
73036
- setPrompt("");
73045
+ setAdditionalInfo("");
73037
73046
  setError(null);
73038
73047
  setIsLoading(false);
73039
73048
  setSubjectCode("");
73049
+ setCategoryCode("");
73040
73050
  setTopicCode("");
73041
73051
  setGradeBand("");
73042
73052
  setBloomLevelCode("");
73043
73053
  setSelectedQuestionType(questionTypeProp || "multiple_choice");
73054
+ setSelectedLanguage(language3);
73044
73055
  setGeminiApiKeyExists(APIKeyService.hasAPIKey(GEMINI_API_KEY_SERVICE_NAME));
73045
73056
  }
73046
- }, [isOpen, questionTypeProp]);
73057
+ }, [isOpen, questionTypeProp, language3]);
73058
+ const filteredCategories = React119.useMemo(() => {
73059
+ return categories;
73060
+ }, [categories]);
73047
73061
  const filteredTopics = React119.useMemo(() => {
73048
- if (!subjectCode) return [];
73049
- return topics.filter((t2) => t2.subjectCode === subjectCode);
73050
- }, [subjectCode, topics]);
73062
+ if (!subjectCode || !categoryCode) return [];
73063
+ return topics.filter(
73064
+ (t2) => t2.subjectCode === subjectCode
73065
+ /* && t.categoryCode === categoryCode */
73066
+ );
73067
+ }, [subjectCode, categoryCode, topics]);
73068
+ const handleSubjectChange = (newSubjectCode) => {
73069
+ setSubjectCode(newSubjectCode);
73070
+ setCategoryCode("");
73071
+ setTopicCode("");
73072
+ };
73073
+ const handleCategoryChange = (newCategoryCode) => {
73074
+ setCategoryCode(newCategoryCode);
73075
+ setTopicCode("");
73076
+ };
73051
73077
  const handleApiKeyModalClose = () => {
73052
73078
  setIsApiKeyManagerModalOpen(false);
73053
73079
  setGeminiApiKeyExists(APIKeyService.hasAPIKey(GEMINI_API_KEY_SERVICE_NAME));
73054
73080
  };
73055
73081
  const handleSubmit = async () => {
73056
- if (!prompt.trim()) {
73057
- setError("Please provide a prompt for the question.");
73082
+ if (!subjectCode || !categoryCode || !topicCode || !gradeBand || !bloomLevelCode) {
73083
+ setError("Please fill in all required metadata fields: Subject, Category, Topic, Grade Level, and Bloom's Level.");
73058
73084
  return;
73059
73085
  }
73060
73086
  const geminiKey = APIKeyService.getAPIKey(GEMINI_API_KEY_SERVICE_NAME);
@@ -73068,14 +73094,15 @@ var AIQuestionGeneratorModal = ({
73068
73094
  setIsLoading(true);
73069
73095
  try {
73070
73096
  const quizContext = {
73071
- plannedTopic: prompt,
73097
+ plannedTopic: additionalInfo.trim() || topicCode,
73072
73098
  originalSubject: subjectCode,
73073
73099
  originalTopic: topicCode,
73100
+ originalCategory: categoryCode,
73074
73101
  gradeBand,
73075
73102
  plannedBloomLevel: bloomLevelCode
73076
73103
  };
73077
73104
  const baseClientInput = {
73078
- language: language3,
73105
+ language: selectedLanguage,
73079
73106
  difficulty: "Medium",
73080
73107
  quizContext
73081
73108
  };
@@ -73088,33 +73115,32 @@ var AIQuestionGeneratorModal = ({
73088
73115
  generatedResult = await generateMCQQuestion({ ...baseClientInput, numberOfOptions }, geminiKey);
73089
73116
  break;
73090
73117
  case "multiple_response":
73091
- generatedResult = await generateMRQQuestion({ ...baseClientInput, numberOfOptions, minCorrectAnswers, maxCorrectAnswers }, geminiKey);
73118
+ generatedResult = await generateMRQQuestion({ ...baseClientInput, numberOfOptions: 5, minCorrectAnswers: 2, maxCorrectAnswers: 3 }, geminiKey);
73092
73119
  break;
73093
73120
  case "short_answer":
73094
- generatedResult = await generateShortAnswerQuestion({ ...baseClientInput, isCaseSensitive }, geminiKey);
73121
+ generatedResult = await generateShortAnswerQuestion({ ...baseClientInput, isCaseSensitive: false }, geminiKey);
73095
73122
  break;
73096
73123
  case "numeric":
73097
73124
  generatedResult = await generateNumericQuestion({ ...baseClientInput, allowDecimals: true, tolerance: 0 }, geminiKey);
73098
73125
  break;
73099
73126
  case "fill_in_the_blanks":
73100
- generatedResult = await generateFillInTheBlanksQuestion({ ...baseClientInput, numberOfBlanks, isCaseSensitive }, geminiKey);
73127
+ generatedResult = await generateFillInTheBlanksQuestion({ ...baseClientInput, numberOfBlanks: 2, isCaseSensitive: false }, geminiKey);
73101
73128
  break;
73102
73129
  case "sequence":
73103
- generatedResult = await generateSequenceQuestion({ ...baseClientInput, numberOfItems: numberOfSequenceItems }, geminiKey);
73130
+ generatedResult = await generateSequenceQuestion({ ...baseClientInput, numberOfItems: 4 }, geminiKey);
73104
73131
  break;
73105
73132
  case "matching":
73106
- generatedResult = await generateMatchingQuestion({ ...baseClientInput, numberOfPairs: numberOfMatchingPairs, shuffleOptions: true }, geminiKey);
73133
+ generatedResult = await generateMatchingQuestion({ ...baseClientInput, numberOfPairs: 4, shuffleOptions: true }, geminiKey);
73107
73134
  break;
73108
73135
  default:
73109
73136
  throw new Error(`AI generation for '${finalQuestionType}' is not implemented in this flow.`);
73110
73137
  }
73111
- if (generatedResult.error) {
73112
- throw new Error(generatedResult.error);
73113
- }
73138
+ if (generatedResult.error) throw new Error(generatedResult.error);
73114
73139
  if (generatedResult.question) {
73115
73140
  const completeQuestion = generatedResult.question;
73116
73141
  completeQuestion.subject = subjectCode;
73117
73142
  completeQuestion.topic = topicCode;
73143
+ completeQuestion.category = categoryCode;
73118
73144
  completeQuestion.gradeBand = gradeBand;
73119
73145
  completeQuestion.bloomLevel = bloomLevelCode;
73120
73146
  if (completeQuestion.points === void 0) completeQuestion.points = 10;
@@ -73140,47 +73166,13 @@ var AIQuestionGeneratorModal = ({
73140
73166
  const comboboxOptions = {
73141
73167
  subjects: subjects.map((s2) => ({ value: s2.code, label: s2.name })),
73142
73168
  topics: filteredTopics.map((t2) => ({ value: t2.code, label: t2.name })),
73169
+ categories: filteredCategories.map((c2) => ({ value: c2.code, label: c2.name })),
73143
73170
  gradeLevels: gradeLevels.map((g) => ({ value: g.code, label: g.name })),
73144
73171
  bloomLevels: bloomLevels.map((b) => ({ value: b.code, label: b.name }))
73145
73172
  };
73146
- const renderSpecificParams = () => {
73147
- switch (finalQuestionType) {
73148
- case "multiple_choice":
73149
- case "multiple_response":
73150
- return /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "ai-num-options" }, "Number of Options (2-8)"), /* @__PURE__ */ React119__namespace.default.createElement(
73151
- Input,
73152
- {
73153
- id: "ai-num-options",
73154
- type: "number",
73155
- value: numberOfOptions,
73156
- onChange: (e2) => setNumberOfOptions(parseInt(e2.target.value, 10)),
73157
- min: 2,
73158
- max: 8
73159
- }
73160
- ), finalQuestionType === "multiple_response" && /* @__PURE__ */ React119__namespace.default.createElement(React119__namespace.default.Fragment, null, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "ai-min-correct" }, "Min Correct Answers"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "ai-min-correct", type: "number", value: minCorrectAnswers, onChange: (e2) => setMinCorrectAnswers(parseInt(e2.target.value, 10)), min: 1, max: numberOfOptions }), /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "ai-max-correct" }, "Max Correct Answers"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "ai-max-correct", type: "number", value: maxCorrectAnswers, onChange: (e2) => setMaxCorrectAnswers(parseInt(e2.target.value, 10)), min: minCorrectAnswers, max: numberOfOptions })));
73161
- case "short_answer":
73162
- case "fill_in_the_blanks":
73163
- return /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "flex items-center space-x-2 pt-4 border-t" }, /* @__PURE__ */ React119__namespace.default.createElement("input", { type: "checkbox", id: "ai-case-sensitive", checked: isCaseSensitive, onChange: (e2) => setIsCaseSensitive(e2.target.checked), className: "h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary" }), /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "ai-case-sensitive" }, "Case Sensitive Answers"), finalQuestionType === "fill_in_the_blanks" && /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-1 ml-4" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "ai-num-blanks" }, "Number of Blanks (1-5)"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "ai-num-blanks", type: "number", value: numberOfBlanks, onChange: (e2) => setNumberOfBlanks(parseInt(e2.target.value, 10)), min: 1, max: 5 })));
73164
- case "sequence":
73165
- return /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "ai-num-seq-items" }, "Number of Items to Sequence (2-10)"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "ai-num-seq-items", type: "number", value: numberOfSequenceItems, onChange: (e2) => setNumberOfSequenceItems(parseInt(e2.target.value, 10)), min: 2, max: 10 }));
73166
- case "matching":
73167
- return /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "ai-num-match-pairs" }, "Number of Pairs to Match (2-8)"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "ai-num-match-pairs", type: "number", value: numberOfMatchingPairs, onChange: (e2) => setNumberOfMatchingPairs(parseInt(e2.target.value, 10)), min: 2, max: 8 }));
73168
- default:
73169
- return null;
73170
- }
73171
- };
73172
73173
  return /* @__PURE__ */ React119__namespace.default.createElement(React119__namespace.default.Fragment, null, /* @__PURE__ */ React119__namespace.default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => {
73173
73174
  if (!open) onClose();
73174
- } }, /* @__PURE__ */ React119__namespace.default.createElement(DialogContent2, { className: "sm:max-w-[600px]" }, /* @__PURE__ */ React119__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(DialogTitle2, { className: "flex items-center font-headline text-2xl" }, /* @__PURE__ */ React119__namespace.default.createElement(WandSparkles, { className: "mr-2 h-6 w-6 text-primary" }), " AI Question Generator"), /* @__PURE__ */ React119__namespace.default.createElement(DialogDescription2, null, "Provide a prompt and metadata to generate a '", finalQuestionType, "' question.")), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-4 py-4 max-h-[60vh] overflow-y-auto px-2" }, !geminiApiKeyExists && /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "p-3 mb-4 border border-amber-500 bg-amber-50 rounded-md text-amber-700" }), !questionTypeProp && /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "ai-q-type-select" }, "Question Type"), /* @__PURE__ */ React119__namespace.default.createElement(Select2, { value: selectedQuestionType, onValueChange: (v) => setSelectedQuestionType(v) }, /* @__PURE__ */ React119__namespace.default.createElement(SelectTrigger2, { id: "ai-q-type-select" }, /* @__PURE__ */ React119__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React119__namespace.default.createElement(SelectContent2, null, supportedQuestionTypesForAI.map((type) => /* @__PURE__ */ React119__namespace.default.createElement(SelectItem2, { key: type.value, value: type.value }, type.label))))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "ai-prompt" }, "Prompt / Topic"), /* @__PURE__ */ React119__namespace.default.createElement(
73175
- Textarea,
73176
- {
73177
- id: "ai-prompt",
73178
- value: prompt,
73179
- onChange: (e2) => setPrompt(e2.target.value),
73180
- placeholder: "e.g., The process of photosynthesis, The causes of World War II, Basic Algebra Equations",
73181
- className: "min-h-[100px]"
73182
- }
73183
- )), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, null, "Subject"), /* @__PURE__ */ React119__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.subjects, value: subjectCode, onChange: setSubjectCode, placeholder: "Select or type a Subject..." })), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, null, "Topic"), /* @__PURE__ */ React119__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.topics, value: topicCode, onChange: setTopicCode, placeholder: "Select or type a Topic...", disabled: !subjectCode })), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, null, "Grade Level"), /* @__PURE__ */ React119__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.gradeLevels, value: gradeBand, onChange: setGradeBand, placeholder: "Select or type a Grade..." })), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, null, "Bloom's Level"), /* @__PURE__ */ React119__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.bloomLevels, value: bloomLevelCode, onChange: setBloomLevelCode, placeholder: "Select a Bloom's Level..." }))), renderSpecificParams(), error && /* @__PURE__ */ React119__namespace.default.createElement("p", { className: "text-sm text-destructive flex items-center mt-2" }, /* @__PURE__ */ React119__namespace.default.createElement(TriangleAlert, { className: "mr-1 h-4 w-4" }), " ", error)), /* @__PURE__ */ React119__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React119__namespace.default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React119__namespace.default.createElement(Button, { type: "button", variant: "outline" }, "Cancel")), /* @__PURE__ */ React119__namespace.default.createElement(Button, { type: "button", onClick: handleSubmit, disabled: isLoading || !prompt.trim() || !geminiApiKeyExists }, isLoading ? /* @__PURE__ */ React119__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React119__namespace.default.createElement(WandSparkles, { className: "mr-2 h-4 w-4" }), "Generate Question")))), /* @__PURE__ */ React119__namespace.default.createElement(APIKeyManagerModal, { isOpen: isApiKeyManagerModalOpen, onClose: handleApiKeyModalClose }));
73175
+ } }, /* @__PURE__ */ React119__namespace.default.createElement(DialogContent2, { className: "sm:max-w-[700px]" }, /* @__PURE__ */ React119__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React119__namespace.default.createElement(DialogTitle2, { className: "flex items-center font-headline text-2xl" }, /* @__PURE__ */ React119__namespace.default.createElement(WandSparkles, { className: "mr-2 h-6 w-6 text-primary" }), " AI Question Generator"), /* @__PURE__ */ React119__namespace.default.createElement(DialogDescription2, null, "Provide metadata and optional info to generate a '", finalQuestionType, "' question.")), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-4 py-4 max-h-[60vh] overflow-y-auto px-2" }, /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-4" }, !questionTypeProp && /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, null, "Question Type"), /* @__PURE__ */ React119__namespace.default.createElement(Select2, { value: selectedQuestionType, onValueChange: (v) => setSelectedQuestionType(v) }, /* @__PURE__ */ React119__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React119__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React119__namespace.default.createElement(SelectContent2, null, supportedQuestionTypesForAI.map((type) => /* @__PURE__ */ React119__namespace.default.createElement(SelectItem2, { key: type.value, value: type.value }, type.label))))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, null, "Language"), /* @__PURE__ */ React119__namespace.default.createElement(Select2, { value: selectedLanguage, onValueChange: setSelectedLanguage }, /* @__PURE__ */ React119__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React119__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React119__namespace.default.createElement(SelectContent2, null, availableLanguages.map((lang) => /* @__PURE__ */ React119__namespace.default.createElement(SelectItem2, { key: lang.value, value: lang.value }, lang.label)))))), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "ai-additional-info" }, "Additional Info (Optional)"), /* @__PURE__ */ React119__namespace.default.createElement(Textarea, { id: "ai-additional-info", value: additionalInfo, onChange: (e2) => setAdditionalInfo(e2.target.value), placeholder: "Provide extra context, a specific topic, or a detailed prompt for the AI...", className: "min-h-[100px]" })), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-4" }, /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, null, "Subject *"), /* @__PURE__ */ React119__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.subjects, value: subjectCode, onChange: handleSubjectChange, placeholder: "Select Subject..." })), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, null, "Category *"), /* @__PURE__ */ React119__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.categories, value: categoryCode, onChange: handleCategoryChange, placeholder: "Select Category...", disabled: !subjectCode })), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, null, "Topic *"), /* @__PURE__ */ React119__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.topics, value: topicCode, onChange: setTopicCode, placeholder: "Select Topic...", disabled: !categoryCode })), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, null, "Grade Level *"), /* @__PURE__ */ React119__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.gradeLevels, value: gradeBand, onChange: setGradeBand, placeholder: "Select Grade..." })), /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, null, "Bloom's Level *"), /* @__PURE__ */ React119__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.bloomLevels, value: bloomLevelCode, onChange: setBloomLevelCode, placeholder: "Select Bloom's Level..." }))), finalQuestionType === "multiple_choice" && /* @__PURE__ */ React119__namespace.default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React119__namespace.default.createElement(Label2, { htmlFor: "ai-num-options" }, "Number of Options (2-8)"), /* @__PURE__ */ React119__namespace.default.createElement(Input, { id: "ai-num-options", type: "number", value: numberOfOptions, onChange: (e2) => setNumberOfOptions(parseInt(e2.target.value, 10)), min: 2, max: 8 })), error && /* @__PURE__ */ React119__namespace.default.createElement("p", { className: "text-sm text-destructive flex items-center mt-2" }, /* @__PURE__ */ React119__namespace.default.createElement(TriangleAlert, { className: "mr-1 h-4 w-4" }), " ", error)), /* @__PURE__ */ React119__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React119__namespace.default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React119__namespace.default.createElement(Button, { type: "button", variant: "outline" }, "Cancel")), /* @__PURE__ */ React119__namespace.default.createElement(Button, { type: "button", onClick: handleSubmit, disabled: isLoading || !geminiApiKeyExists || !subjectCode || !categoryCode || !topicCode || !gradeBand || !bloomLevelCode }, isLoading ? /* @__PURE__ */ React119__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React119__namespace.default.createElement(WandSparkles, { className: "mr-2 h-4 w-4" }), "Generate Question")))), /* @__PURE__ */ React119__namespace.default.createElement(APIKeyManagerModal, { isOpen: isApiKeyManagerModalOpen, onClose: handleApiKeyModalClose }));
73184
73176
  };
73185
73177
 
73186
73178
  // src/react-ui/components/authoring/AIFullQuizGeneratorModal.tsx
@@ -2,7 +2,7 @@ export { B as BaseQuestion, e as BlocklyProgrammingQuestion, C as CodingQuestion
2
2
  export { APIKeyService, AchievementService, Approach, ApproachTableRawDifficulty, BloomLevelName, BloomLevelType, Category, CodeNamedEntity, Context, GEMINI_API_KEY_SERVICE_NAME, GradeLevel, KnowledgeCardService, KnowledgeDimension, LearningObjective, MetadataService, PracticeHistoryService, QuestionBankService, QuestionImportService, QuestionInBank, QuestionTypeType, QuizEditorService, QuizEngine, QuizEngineCallbacks, QuizEngineConstructorOptions, QuoteService, SCORMService, StandardDifficulty, Subject, Topic, UserConfigService, cn, emptyQuiz, exportQuizAsSCORMZip, generateLauncherHTML, generateSCORMManifest, generateUniqueId, sampleQuiz } from './index.cjs';
3
3
  export { i as Achievement, j as AchievementDefinition, r as ActivityCalendarData, u as AnalysisReport, A as AnswerDetail, x as ChatContext, C as ChatMessage, v as DashboardCardConfig, D as DashboardCardId, w as DashboardLayout, y as Goal, G as GoalType, t as ImageContextItem, I as ImportError, K as KnowledgeCard, L as LearningAnalysis, e as PerformanceByBloomLevel, b as PerformanceByCategory, d as PerformanceByDifficulty, P as PerformanceByLearningObjective, c as PerformanceByTopic, f as PerformanceMetric, s as PerformanceSummary, k as PracticeDifficulty, n as PracticeSession, p as PracticeSessionSummary, o as PracticeStats, m as PracticeSuggestion, l as PracticeSuggestionTopic, q as PracticeTopicSummary, g as QuestionReview, Q as QuizResultType, h as QuizReviewContent, R as RoadmapItem, T as TestCaseResult, U as UserAnswerType, a as UserAnswers, W as WeeklyRoadmap } from './ai-ecosystem-DyQYZbyX.cjs';
4
4
  export { AssessAndMapDocumentClientInput, AssessAndMapDocumentOutput, BloomLevelStringsForAI, GenerateCodingQuestionClientInput, GenerateCodingQuestionOutput, GenerateFillInTheBlanksQuestionClientInput, GenerateFillInTheBlanksQuestionOutput, GenerateLearningAnalysisClientInput, GenerateLearningAnalysisOutput, GenerateMCQQuestionClientInput, GenerateMCQQuestionOutput, GenerateMRQQuestionClientInput, GenerateMRQQuestionOutput, GenerateMatchingQuestionClientInput, GenerateMatchingQuestionOutput, GenerateMotivationalQuoteClientInput, GenerateMotivationalQuoteOutput, GenerateNumericQuestionClientInput, GenerateNumericQuestionOutput, GeneratePracticeSuggestionClientInput, GeneratePracticeSuggestionOutput, GenerateQuestionsFromQuizPlanClientInput, GenerateQuestionsFromQuizPlanOutput, GenerateQuizFromTextClientInput, GenerateQuizFromTextOutput, GenerateQuizPlanClientInput, GenerateQuizPlanOutput, GenerateQuizReviewClientInput, GenerateQuizReviewOutput, GenerateSequenceQuestionClientInput, GenerateSequenceQuestionOutput, GenerateShortAnswerQuestionClientInput, GenerateShortAnswerQuestionOutput, GenerateSingleKnowledgeCardClientInput, GenerateSingleKnowledgeCardOutput, GenerateTrueFalseQuestionClientInput, GenerateTrueFalseQuestionOutput, PlanKnowledgeCardsClientInput, PlanKnowledgeCardsOutput, PlannedQuestion, assessAndMapDocument, generateCodingQuestion, generateFillInTheBlanksQuestion, generateLearningAnalysis, generateMCQQuestion, generateMRQQuestion, generateMatchingQuestion, generateMotivationalQuote, generateNumericQuestion, generatePracticeSuggestion, generateQuestionsFromQuizPlan, generateQuizFromText, generateQuizPlan, generateQuizReview, generateSequenceQuestion, generateShortAnswerQuestion, generateSingleKnowledgeCard, generateTrueFalseQuestion, planKnowledgeCards } from './ai.cjs';
5
- export { c as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, e as APIKeyManagerModal, f as ApiKeySettings, m as ApproachManager, B as BloomLevelManager, C as CategoryManager, l as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, n as MetadataImportControls, M as MetadataTabs, h as QuestionFilters, i as QuestionFormDialog, g as QuestionList, a as QuestionPreviewModal, k as QuestionTypeManager, Q as QuizAuthoringTool, b as QuizSettingsForm, d as SCORMExportModal, S as SelectedQuestionsPanel, j as SubjectManager, o as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-6AR8w2TO.cjs';
5
+ export { c as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, e as APIKeyManagerModal, f as ApiKeySettings, m as ApproachManager, B as BloomLevelManager, C as CategoryManager, l as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, n as MetadataImportControls, M as MetadataTabs, h as QuestionFilters, i as QuestionFormDialog, g as QuestionList, a as QuestionPreviewModal, k as QuestionTypeManager, Q as QuizAuthoringTool, b as QuizSettingsForm, d as SCORMExportModal, S as SelectedQuestionsPanel, j as SubjectManager, o as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-Bvhmyef9.cjs';
6
6
  import 'clsx';
7
7
  import 'zod';
8
8
  import 'react';
@@ -2,7 +2,7 @@ export { B as BaseQuestion, e as BlocklyProgrammingQuestion, C as CodingQuestion
2
2
  export { APIKeyService, AchievementService, Approach, ApproachTableRawDifficulty, BloomLevelName, BloomLevelType, Category, CodeNamedEntity, Context, GEMINI_API_KEY_SERVICE_NAME, GradeLevel, KnowledgeCardService, KnowledgeDimension, LearningObjective, MetadataService, PracticeHistoryService, QuestionBankService, QuestionImportService, QuestionInBank, QuestionTypeType, QuizEditorService, QuizEngine, QuizEngineCallbacks, QuizEngineConstructorOptions, QuoteService, SCORMService, StandardDifficulty, Subject, Topic, UserConfigService, cn, emptyQuiz, exportQuizAsSCORMZip, generateLauncherHTML, generateSCORMManifest, generateUniqueId, sampleQuiz } from './index.js';
3
3
  export { i as Achievement, j as AchievementDefinition, r as ActivityCalendarData, u as AnalysisReport, A as AnswerDetail, x as ChatContext, C as ChatMessage, v as DashboardCardConfig, D as DashboardCardId, w as DashboardLayout, y as Goal, G as GoalType, t as ImageContextItem, I as ImportError, K as KnowledgeCard, L as LearningAnalysis, e as PerformanceByBloomLevel, b as PerformanceByCategory, d as PerformanceByDifficulty, P as PerformanceByLearningObjective, c as PerformanceByTopic, f as PerformanceMetric, s as PerformanceSummary, k as PracticeDifficulty, n as PracticeSession, p as PracticeSessionSummary, o as PracticeStats, m as PracticeSuggestion, l as PracticeSuggestionTopic, q as PracticeTopicSummary, g as QuestionReview, Q as QuizResultType, h as QuizReviewContent, R as RoadmapItem, T as TestCaseResult, U as UserAnswerType, a as UserAnswers, W as WeeklyRoadmap } from './ai-ecosystem-Qa_SdE2T.js';
4
4
  export { AssessAndMapDocumentClientInput, AssessAndMapDocumentOutput, BloomLevelStringsForAI, GenerateCodingQuestionClientInput, GenerateCodingQuestionOutput, GenerateFillInTheBlanksQuestionClientInput, GenerateFillInTheBlanksQuestionOutput, GenerateLearningAnalysisClientInput, GenerateLearningAnalysisOutput, GenerateMCQQuestionClientInput, GenerateMCQQuestionOutput, GenerateMRQQuestionClientInput, GenerateMRQQuestionOutput, GenerateMatchingQuestionClientInput, GenerateMatchingQuestionOutput, GenerateMotivationalQuoteClientInput, GenerateMotivationalQuoteOutput, GenerateNumericQuestionClientInput, GenerateNumericQuestionOutput, GeneratePracticeSuggestionClientInput, GeneratePracticeSuggestionOutput, GenerateQuestionsFromQuizPlanClientInput, GenerateQuestionsFromQuizPlanOutput, GenerateQuizFromTextClientInput, GenerateQuizFromTextOutput, GenerateQuizPlanClientInput, GenerateQuizPlanOutput, GenerateQuizReviewClientInput, GenerateQuizReviewOutput, GenerateSequenceQuestionClientInput, GenerateSequenceQuestionOutput, GenerateShortAnswerQuestionClientInput, GenerateShortAnswerQuestionOutput, GenerateSingleKnowledgeCardClientInput, GenerateSingleKnowledgeCardOutput, GenerateTrueFalseQuestionClientInput, GenerateTrueFalseQuestionOutput, PlanKnowledgeCardsClientInput, PlanKnowledgeCardsOutput, PlannedQuestion, assessAndMapDocument, generateCodingQuestion, generateFillInTheBlanksQuestion, generateLearningAnalysis, generateMCQQuestion, generateMRQQuestion, generateMatchingQuestion, generateMotivationalQuote, generateNumericQuestion, generatePracticeSuggestion, generateQuestionsFromQuizPlan, generateQuizFromText, generateQuizPlan, generateQuizReview, generateSequenceQuestion, generateShortAnswerQuestion, generateSingleKnowledgeCard, generateTrueFalseQuestion, planKnowledgeCards } from './ai.js';
5
- export { c as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, e as APIKeyManagerModal, f as ApiKeySettings, m as ApproachManager, B as BloomLevelManager, C as CategoryManager, l as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, n as MetadataImportControls, M as MetadataTabs, h as QuestionFilters, i as QuestionFormDialog, g as QuestionList, a as QuestionPreviewModal, k as QuestionTypeManager, Q as QuizAuthoringTool, b as QuizSettingsForm, d as SCORMExportModal, S as SelectedQuestionsPanel, j as SubjectManager, o as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-DAXYZdrz.js';
5
+ export { c as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, e as APIKeyManagerModal, f as ApiKeySettings, m as ApproachManager, B as BloomLevelManager, C as CategoryManager, l as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, n as MetadataImportControls, M as MetadataTabs, h as QuestionFilters, i as QuestionFormDialog, g as QuestionList, a as QuestionPreviewModal, k as QuestionTypeManager, Q as QuizAuthoringTool, b as QuizSettingsForm, d as SCORMExportModal, S as SelectedQuestionsPanel, j as SubjectManager, o as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-B2MPZYhi.js';
6
6
  import 'clsx';
7
7
  import 'zod';
8
8
  import 'react';
@@ -71606,21 +71606,30 @@ var EditableCombobox = ({
71606
71606
  disabled = false
71607
71607
  }) => {
71608
71608
  const [open, setOpen] = React119.useState(false);
71609
- const [inputValue, setInputValue] = React119.useState(value);
71609
+ const [inputValue, setInputValue] = React119.useState("");
71610
71610
  React119.useEffect(() => {
71611
- setInputValue(value);
71612
- }, [value]);
71613
- const handleSelect = (currentValue) => {
71614
- const newValue = currentValue === value ? "" : currentValue;
71615
- onChange(newValue);
71616
- setInputValue(newValue);
71611
+ if (value) {
71612
+ const selectedOption = options.find((option) => option.value.toLowerCase() === value.toLowerCase());
71613
+ setInputValue(selectedOption ? selectedOption.label : value);
71614
+ } else {
71615
+ setInputValue("");
71616
+ }
71617
+ }, [value, options, open]);
71618
+ const handleSelect = (selectedValue) => {
71619
+ onChange(selectedValue);
71617
71620
  setOpen(false);
71618
71621
  };
71619
- const handleBlur = () => {
71620
- onChange(inputValue);
71622
+ const handleOpenChange = (isOpen) => {
71623
+ if (!isOpen) {
71624
+ const match2 = options.find((option) => option.label.toLowerCase() === inputValue.toLowerCase());
71625
+ if (!match2 && inputValue !== (options.find((opt) => opt.value === value)?.label || value)) {
71626
+ onChange(inputValue);
71627
+ }
71628
+ }
71629
+ setOpen(isOpen);
71621
71630
  };
71622
71631
  const displayLabel = options.find((option) => option.value.toLowerCase() === value?.toLowerCase())?.label || value;
71623
- return /* @__PURE__ */ React119.createElement(Popover2, { open, onOpenChange: setOpen }, /* @__PURE__ */ React119.createElement(PopoverTrigger2, { asChild: true }, /* @__PURE__ */ React119.createElement(
71632
+ return /* @__PURE__ */ React119.createElement(Popover2, { open, onOpenChange: handleOpenChange }, /* @__PURE__ */ React119.createElement(PopoverTrigger2, { asChild: true }, /* @__PURE__ */ React119.createElement(
71624
71633
  Button,
71625
71634
  {
71626
71635
  variant: "outline",
@@ -71636,8 +71645,7 @@ var EditableCombobox = ({
71636
71645
  {
71637
71646
  placeholder: searchPlaceholder,
71638
71647
  value: inputValue,
71639
- onValueChange: setInputValue,
71640
- onBlur: handleBlur
71648
+ onValueChange: setInputValue
71641
71649
  }
71642
71650
  ), /* @__PURE__ */ React119.createElement(CommandList, null, /* @__PURE__ */ React119.createElement(CommandEmpty, null, noResultsMessage), /* @__PURE__ */ React119.createElement(CommandGroup, null, options.map((option) => /* @__PURE__ */ React119.createElement(
71643
71651
  CommandItem,
@@ -72936,6 +72944,10 @@ var supportedQuestionTypesForAI = [
72936
72944
  { value: "sequence", label: "Sequence" },
72937
72945
  { value: "matching", label: "Matching" }
72938
72946
  ];
72947
+ var availableLanguages = [
72948
+ { value: "English", label: "English" },
72949
+ { value: "Vietnamese", label: "Ti\u1EBFng Vi\u1EC7t" }
72950
+ ];
72939
72951
  var AIQuestionGeneratorModal = ({
72940
72952
  isOpen,
72941
72953
  onClose,
@@ -72945,51 +72957,65 @@ var AIQuestionGeneratorModal = ({
72945
72957
  subjects = [],
72946
72958
  topics = [],
72947
72959
  gradeLevels = [],
72948
- bloomLevels = []
72960
+ bloomLevels = [],
72961
+ categories = []
72949
72962
  }) => {
72950
- const [prompt, setPrompt] = useState("");
72963
+ const [additionalInfo, setAdditionalInfo] = useState("");
72951
72964
  const [isLoading, setIsLoading] = useState(false);
72952
72965
  const [error, setError] = useState(null);
72953
72966
  const { toast: toast2 } = useToast();
72954
72967
  const [subjectCode, setSubjectCode] = useState("");
72968
+ const [categoryCode, setCategoryCode] = useState("");
72955
72969
  const [topicCode, setTopicCode] = useState("");
72956
72970
  const [gradeBand, setGradeBand] = useState("");
72957
72971
  const [bloomLevelCode, setBloomLevelCode] = useState("");
72958
72972
  const [selectedQuestionType, setSelectedQuestionType] = useState("multiple_choice");
72973
+ const [selectedLanguage, setSelectedLanguage] = useState(language3);
72959
72974
  const [numberOfOptions, setNumberOfOptions] = useState(4);
72960
- const [minCorrectAnswers, setMinCorrectAnswers] = useState(2);
72961
- const [maxCorrectAnswers, setMaxCorrectAnswers] = useState(3);
72962
- const [isCaseSensitive, setIsCaseSensitive] = useState(false);
72963
- const [numberOfBlanks, setNumberOfBlanks] = useState(2);
72964
- const [numberOfSequenceItems, setNumberOfSequenceItems] = useState(4);
72965
- const [numberOfMatchingPairs, setNumberOfMatchingPairs] = useState(4);
72966
72975
  const [isApiKeyManagerModalOpen, setIsApiKeyManagerModalOpen] = useState(false);
72967
72976
  const [geminiApiKeyExists, setGeminiApiKeyExists] = useState(false);
72968
72977
  const finalQuestionType = questionTypeProp || selectedQuestionType;
72969
72978
  useEffect(() => {
72970
72979
  if (isOpen) {
72971
- setPrompt("");
72980
+ setAdditionalInfo("");
72972
72981
  setError(null);
72973
72982
  setIsLoading(false);
72974
72983
  setSubjectCode("");
72984
+ setCategoryCode("");
72975
72985
  setTopicCode("");
72976
72986
  setGradeBand("");
72977
72987
  setBloomLevelCode("");
72978
72988
  setSelectedQuestionType(questionTypeProp || "multiple_choice");
72989
+ setSelectedLanguage(language3);
72979
72990
  setGeminiApiKeyExists(APIKeyService.hasAPIKey(GEMINI_API_KEY_SERVICE_NAME));
72980
72991
  }
72981
- }, [isOpen, questionTypeProp]);
72992
+ }, [isOpen, questionTypeProp, language3]);
72993
+ const filteredCategories = useMemo(() => {
72994
+ return categories;
72995
+ }, [categories]);
72982
72996
  const filteredTopics = useMemo(() => {
72983
- if (!subjectCode) return [];
72984
- return topics.filter((t2) => t2.subjectCode === subjectCode);
72985
- }, [subjectCode, topics]);
72997
+ if (!subjectCode || !categoryCode) return [];
72998
+ return topics.filter(
72999
+ (t2) => t2.subjectCode === subjectCode
73000
+ /* && t.categoryCode === categoryCode */
73001
+ );
73002
+ }, [subjectCode, categoryCode, topics]);
73003
+ const handleSubjectChange = (newSubjectCode) => {
73004
+ setSubjectCode(newSubjectCode);
73005
+ setCategoryCode("");
73006
+ setTopicCode("");
73007
+ };
73008
+ const handleCategoryChange = (newCategoryCode) => {
73009
+ setCategoryCode(newCategoryCode);
73010
+ setTopicCode("");
73011
+ };
72986
73012
  const handleApiKeyModalClose = () => {
72987
73013
  setIsApiKeyManagerModalOpen(false);
72988
73014
  setGeminiApiKeyExists(APIKeyService.hasAPIKey(GEMINI_API_KEY_SERVICE_NAME));
72989
73015
  };
72990
73016
  const handleSubmit = async () => {
72991
- if (!prompt.trim()) {
72992
- setError("Please provide a prompt for the question.");
73017
+ if (!subjectCode || !categoryCode || !topicCode || !gradeBand || !bloomLevelCode) {
73018
+ setError("Please fill in all required metadata fields: Subject, Category, Topic, Grade Level, and Bloom's Level.");
72993
73019
  return;
72994
73020
  }
72995
73021
  const geminiKey = APIKeyService.getAPIKey(GEMINI_API_KEY_SERVICE_NAME);
@@ -73003,14 +73029,15 @@ var AIQuestionGeneratorModal = ({
73003
73029
  setIsLoading(true);
73004
73030
  try {
73005
73031
  const quizContext = {
73006
- plannedTopic: prompt,
73032
+ plannedTopic: additionalInfo.trim() || topicCode,
73007
73033
  originalSubject: subjectCode,
73008
73034
  originalTopic: topicCode,
73035
+ originalCategory: categoryCode,
73009
73036
  gradeBand,
73010
73037
  plannedBloomLevel: bloomLevelCode
73011
73038
  };
73012
73039
  const baseClientInput = {
73013
- language: language3,
73040
+ language: selectedLanguage,
73014
73041
  difficulty: "Medium",
73015
73042
  quizContext
73016
73043
  };
@@ -73023,33 +73050,32 @@ var AIQuestionGeneratorModal = ({
73023
73050
  generatedResult = await generateMCQQuestion({ ...baseClientInput, numberOfOptions }, geminiKey);
73024
73051
  break;
73025
73052
  case "multiple_response":
73026
- generatedResult = await generateMRQQuestion({ ...baseClientInput, numberOfOptions, minCorrectAnswers, maxCorrectAnswers }, geminiKey);
73053
+ generatedResult = await generateMRQQuestion({ ...baseClientInput, numberOfOptions: 5, minCorrectAnswers: 2, maxCorrectAnswers: 3 }, geminiKey);
73027
73054
  break;
73028
73055
  case "short_answer":
73029
- generatedResult = await generateShortAnswerQuestion({ ...baseClientInput, isCaseSensitive }, geminiKey);
73056
+ generatedResult = await generateShortAnswerQuestion({ ...baseClientInput, isCaseSensitive: false }, geminiKey);
73030
73057
  break;
73031
73058
  case "numeric":
73032
73059
  generatedResult = await generateNumericQuestion({ ...baseClientInput, allowDecimals: true, tolerance: 0 }, geminiKey);
73033
73060
  break;
73034
73061
  case "fill_in_the_blanks":
73035
- generatedResult = await generateFillInTheBlanksQuestion({ ...baseClientInput, numberOfBlanks, isCaseSensitive }, geminiKey);
73062
+ generatedResult = await generateFillInTheBlanksQuestion({ ...baseClientInput, numberOfBlanks: 2, isCaseSensitive: false }, geminiKey);
73036
73063
  break;
73037
73064
  case "sequence":
73038
- generatedResult = await generateSequenceQuestion({ ...baseClientInput, numberOfItems: numberOfSequenceItems }, geminiKey);
73065
+ generatedResult = await generateSequenceQuestion({ ...baseClientInput, numberOfItems: 4 }, geminiKey);
73039
73066
  break;
73040
73067
  case "matching":
73041
- generatedResult = await generateMatchingQuestion({ ...baseClientInput, numberOfPairs: numberOfMatchingPairs, shuffleOptions: true }, geminiKey);
73068
+ generatedResult = await generateMatchingQuestion({ ...baseClientInput, numberOfPairs: 4, shuffleOptions: true }, geminiKey);
73042
73069
  break;
73043
73070
  default:
73044
73071
  throw new Error(`AI generation for '${finalQuestionType}' is not implemented in this flow.`);
73045
73072
  }
73046
- if (generatedResult.error) {
73047
- throw new Error(generatedResult.error);
73048
- }
73073
+ if (generatedResult.error) throw new Error(generatedResult.error);
73049
73074
  if (generatedResult.question) {
73050
73075
  const completeQuestion = generatedResult.question;
73051
73076
  completeQuestion.subject = subjectCode;
73052
73077
  completeQuestion.topic = topicCode;
73078
+ completeQuestion.category = categoryCode;
73053
73079
  completeQuestion.gradeBand = gradeBand;
73054
73080
  completeQuestion.bloomLevel = bloomLevelCode;
73055
73081
  if (completeQuestion.points === void 0) completeQuestion.points = 10;
@@ -73075,47 +73101,13 @@ var AIQuestionGeneratorModal = ({
73075
73101
  const comboboxOptions = {
73076
73102
  subjects: subjects.map((s2) => ({ value: s2.code, label: s2.name })),
73077
73103
  topics: filteredTopics.map((t2) => ({ value: t2.code, label: t2.name })),
73104
+ categories: filteredCategories.map((c2) => ({ value: c2.code, label: c2.name })),
73078
73105
  gradeLevels: gradeLevels.map((g) => ({ value: g.code, label: g.name })),
73079
73106
  bloomLevels: bloomLevels.map((b) => ({ value: b.code, label: b.name }))
73080
73107
  };
73081
- const renderSpecificParams = () => {
73082
- switch (finalQuestionType) {
73083
- case "multiple_choice":
73084
- case "multiple_response":
73085
- return /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "ai-num-options" }, "Number of Options (2-8)"), /* @__PURE__ */ React119__default.createElement(
73086
- Input,
73087
- {
73088
- id: "ai-num-options",
73089
- type: "number",
73090
- value: numberOfOptions,
73091
- onChange: (e2) => setNumberOfOptions(parseInt(e2.target.value, 10)),
73092
- min: 2,
73093
- max: 8
73094
- }
73095
- ), finalQuestionType === "multiple_response" && /* @__PURE__ */ React119__default.createElement(React119__default.Fragment, null, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "ai-min-correct" }, "Min Correct Answers"), /* @__PURE__ */ React119__default.createElement(Input, { id: "ai-min-correct", type: "number", value: minCorrectAnswers, onChange: (e2) => setMinCorrectAnswers(parseInt(e2.target.value, 10)), min: 1, max: numberOfOptions }), /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "ai-max-correct" }, "Max Correct Answers"), /* @__PURE__ */ React119__default.createElement(Input, { id: "ai-max-correct", type: "number", value: maxCorrectAnswers, onChange: (e2) => setMaxCorrectAnswers(parseInt(e2.target.value, 10)), min: minCorrectAnswers, max: numberOfOptions })));
73096
- case "short_answer":
73097
- case "fill_in_the_blanks":
73098
- return /* @__PURE__ */ React119__default.createElement("div", { className: "flex items-center space-x-2 pt-4 border-t" }, /* @__PURE__ */ React119__default.createElement("input", { type: "checkbox", id: "ai-case-sensitive", checked: isCaseSensitive, onChange: (e2) => setIsCaseSensitive(e2.target.checked), className: "h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary" }), /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "ai-case-sensitive" }, "Case Sensitive Answers"), finalQuestionType === "fill_in_the_blanks" && /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-1 ml-4" }, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "ai-num-blanks" }, "Number of Blanks (1-5)"), /* @__PURE__ */ React119__default.createElement(Input, { id: "ai-num-blanks", type: "number", value: numberOfBlanks, onChange: (e2) => setNumberOfBlanks(parseInt(e2.target.value, 10)), min: 1, max: 5 })));
73099
- case "sequence":
73100
- return /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "ai-num-seq-items" }, "Number of Items to Sequence (2-10)"), /* @__PURE__ */ React119__default.createElement(Input, { id: "ai-num-seq-items", type: "number", value: numberOfSequenceItems, onChange: (e2) => setNumberOfSequenceItems(parseInt(e2.target.value, 10)), min: 2, max: 10 }));
73101
- case "matching":
73102
- return /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "ai-num-match-pairs" }, "Number of Pairs to Match (2-8)"), /* @__PURE__ */ React119__default.createElement(Input, { id: "ai-num-match-pairs", type: "number", value: numberOfMatchingPairs, onChange: (e2) => setNumberOfMatchingPairs(parseInt(e2.target.value, 10)), min: 2, max: 8 }));
73103
- default:
73104
- return null;
73105
- }
73106
- };
73107
73108
  return /* @__PURE__ */ React119__default.createElement(React119__default.Fragment, null, /* @__PURE__ */ React119__default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => {
73108
73109
  if (!open) onClose();
73109
- } }, /* @__PURE__ */ React119__default.createElement(DialogContent2, { className: "sm:max-w-[600px]" }, /* @__PURE__ */ React119__default.createElement(DialogHeader, null, /* @__PURE__ */ React119__default.createElement(DialogTitle2, { className: "flex items-center font-headline text-2xl" }, /* @__PURE__ */ React119__default.createElement(WandSparkles, { className: "mr-2 h-6 w-6 text-primary" }), " AI Question Generator"), /* @__PURE__ */ React119__default.createElement(DialogDescription2, null, "Provide a prompt and metadata to generate a '", finalQuestionType, "' question.")), /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-4 py-4 max-h-[60vh] overflow-y-auto px-2" }, !geminiApiKeyExists && /* @__PURE__ */ React119__default.createElement("div", { className: "p-3 mb-4 border border-amber-500 bg-amber-50 rounded-md text-amber-700" }), !questionTypeProp && /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "ai-q-type-select" }, "Question Type"), /* @__PURE__ */ React119__default.createElement(Select2, { value: selectedQuestionType, onValueChange: (v) => setSelectedQuestionType(v) }, /* @__PURE__ */ React119__default.createElement(SelectTrigger2, { id: "ai-q-type-select" }, /* @__PURE__ */ React119__default.createElement(SelectValue2, null)), /* @__PURE__ */ React119__default.createElement(SelectContent2, null, supportedQuestionTypesForAI.map((type) => /* @__PURE__ */ React119__default.createElement(SelectItem2, { key: type.value, value: type.value }, type.label))))), /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "ai-prompt" }, "Prompt / Topic"), /* @__PURE__ */ React119__default.createElement(
73110
- Textarea,
73111
- {
73112
- id: "ai-prompt",
73113
- value: prompt,
73114
- onChange: (e2) => setPrompt(e2.target.value),
73115
- placeholder: "e.g., The process of photosynthesis, The causes of World War II, Basic Algebra Equations",
73116
- className: "min-h-[100px]"
73117
- }
73118
- )), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, null, "Subject"), /* @__PURE__ */ React119__default.createElement(EditableCombobox, { options: comboboxOptions.subjects, value: subjectCode, onChange: setSubjectCode, placeholder: "Select or type a Subject..." })), /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, null, "Topic"), /* @__PURE__ */ React119__default.createElement(EditableCombobox, { options: comboboxOptions.topics, value: topicCode, onChange: setTopicCode, placeholder: "Select or type a Topic...", disabled: !subjectCode })), /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, null, "Grade Level"), /* @__PURE__ */ React119__default.createElement(EditableCombobox, { options: comboboxOptions.gradeLevels, value: gradeBand, onChange: setGradeBand, placeholder: "Select or type a Grade..." })), /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, null, "Bloom's Level"), /* @__PURE__ */ React119__default.createElement(EditableCombobox, { options: comboboxOptions.bloomLevels, value: bloomLevelCode, onChange: setBloomLevelCode, placeholder: "Select a Bloom's Level..." }))), renderSpecificParams(), error && /* @__PURE__ */ React119__default.createElement("p", { className: "text-sm text-destructive flex items-center mt-2" }, /* @__PURE__ */ React119__default.createElement(TriangleAlert, { className: "mr-1 h-4 w-4" }), " ", error)), /* @__PURE__ */ React119__default.createElement(DialogFooter, null, /* @__PURE__ */ React119__default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React119__default.createElement(Button, { type: "button", variant: "outline" }, "Cancel")), /* @__PURE__ */ React119__default.createElement(Button, { type: "button", onClick: handleSubmit, disabled: isLoading || !prompt.trim() || !geminiApiKeyExists }, isLoading ? /* @__PURE__ */ React119__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React119__default.createElement(WandSparkles, { className: "mr-2 h-4 w-4" }), "Generate Question")))), /* @__PURE__ */ React119__default.createElement(APIKeyManagerModal, { isOpen: isApiKeyManagerModalOpen, onClose: handleApiKeyModalClose }));
73110
+ } }, /* @__PURE__ */ React119__default.createElement(DialogContent2, { className: "sm:max-w-[700px]" }, /* @__PURE__ */ React119__default.createElement(DialogHeader, null, /* @__PURE__ */ React119__default.createElement(DialogTitle2, { className: "flex items-center font-headline text-2xl" }, /* @__PURE__ */ React119__default.createElement(WandSparkles, { className: "mr-2 h-6 w-6 text-primary" }), " AI Question Generator"), /* @__PURE__ */ React119__default.createElement(DialogDescription2, null, "Provide metadata and optional info to generate a '", finalQuestionType, "' question.")), /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-4 py-4 max-h-[60vh] overflow-y-auto px-2" }, /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-2 gap-4" }, !questionTypeProp && /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, null, "Question Type"), /* @__PURE__ */ React119__default.createElement(Select2, { value: selectedQuestionType, onValueChange: (v) => setSelectedQuestionType(v) }, /* @__PURE__ */ React119__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React119__default.createElement(SelectValue2, null)), /* @__PURE__ */ React119__default.createElement(SelectContent2, null, supportedQuestionTypesForAI.map((type) => /* @__PURE__ */ React119__default.createElement(SelectItem2, { key: type.value, value: type.value }, type.label))))), /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, null, "Language"), /* @__PURE__ */ React119__default.createElement(Select2, { value: selectedLanguage, onValueChange: setSelectedLanguage }, /* @__PURE__ */ React119__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React119__default.createElement(SelectValue2, null)), /* @__PURE__ */ React119__default.createElement(SelectContent2, null, availableLanguages.map((lang) => /* @__PURE__ */ React119__default.createElement(SelectItem2, { key: lang.value, value: lang.value }, lang.label)))))), /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "ai-additional-info" }, "Additional Info (Optional)"), /* @__PURE__ */ React119__default.createElement(Textarea, { id: "ai-additional-info", value: additionalInfo, onChange: (e2) => setAdditionalInfo(e2.target.value), placeholder: "Provide extra context, a specific topic, or a detailed prompt for the AI...", className: "min-h-[100px]" })), /* @__PURE__ */ React119__default.createElement("div", { className: "grid grid-cols-2 gap-4" }, /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, null, "Subject *"), /* @__PURE__ */ React119__default.createElement(EditableCombobox, { options: comboboxOptions.subjects, value: subjectCode, onChange: handleSubjectChange, placeholder: "Select Subject..." })), /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, null, "Category *"), /* @__PURE__ */ React119__default.createElement(EditableCombobox, { options: comboboxOptions.categories, value: categoryCode, onChange: handleCategoryChange, placeholder: "Select Category...", disabled: !subjectCode })), /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, null, "Topic *"), /* @__PURE__ */ React119__default.createElement(EditableCombobox, { options: comboboxOptions.topics, value: topicCode, onChange: setTopicCode, placeholder: "Select Topic...", disabled: !categoryCode })), /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, null, "Grade Level *"), /* @__PURE__ */ React119__default.createElement(EditableCombobox, { options: comboboxOptions.gradeLevels, value: gradeBand, onChange: setGradeBand, placeholder: "Select Grade..." })), /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React119__default.createElement(Label2, null, "Bloom's Level *"), /* @__PURE__ */ React119__default.createElement(EditableCombobox, { options: comboboxOptions.bloomLevels, value: bloomLevelCode, onChange: setBloomLevelCode, placeholder: "Select Bloom's Level..." }))), finalQuestionType === "multiple_choice" && /* @__PURE__ */ React119__default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React119__default.createElement(Label2, { htmlFor: "ai-num-options" }, "Number of Options (2-8)"), /* @__PURE__ */ React119__default.createElement(Input, { id: "ai-num-options", type: "number", value: numberOfOptions, onChange: (e2) => setNumberOfOptions(parseInt(e2.target.value, 10)), min: 2, max: 8 })), error && /* @__PURE__ */ React119__default.createElement("p", { className: "text-sm text-destructive flex items-center mt-2" }, /* @__PURE__ */ React119__default.createElement(TriangleAlert, { className: "mr-1 h-4 w-4" }), " ", error)), /* @__PURE__ */ React119__default.createElement(DialogFooter, null, /* @__PURE__ */ React119__default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React119__default.createElement(Button, { type: "button", variant: "outline" }, "Cancel")), /* @__PURE__ */ React119__default.createElement(Button, { type: "button", onClick: handleSubmit, disabled: isLoading || !geminiApiKeyExists || !subjectCode || !categoryCode || !topicCode || !gradeBand || !bloomLevelCode }, isLoading ? /* @__PURE__ */ React119__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React119__default.createElement(WandSparkles, { className: "mr-2 h-4 w-4" }), "Generate Question")))), /* @__PURE__ */ React119__default.createElement(APIKeyManagerModal, { isOpen: isApiKeyManagerModalOpen, onClose: handleApiKeyModalClose }));
73119
73111
  };
73120
73112
 
73121
73113
  // src/react-ui/components/authoring/AIFullQuizGeneratorModal.tsx
package/dist/react-ui.cjs CHANGED
@@ -98269,21 +98269,30 @@ var EditableCombobox = ({
98269
98269
  disabled = false
98270
98270
  }) => {
98271
98271
  const [open, setOpen] = React169__namespace.useState(false);
98272
- const [inputValue, setInputValue] = React169__namespace.useState(value);
98272
+ const [inputValue, setInputValue] = React169__namespace.useState("");
98273
98273
  React169__namespace.useEffect(() => {
98274
- setInputValue(value);
98275
- }, [value]);
98276
- const handleSelect = (currentValue) => {
98277
- const newValue = currentValue === value ? "" : currentValue;
98278
- onChange(newValue);
98279
- setInputValue(newValue);
98274
+ if (value) {
98275
+ const selectedOption = options.find((option) => option.value.toLowerCase() === value.toLowerCase());
98276
+ setInputValue(selectedOption ? selectedOption.label : value);
98277
+ } else {
98278
+ setInputValue("");
98279
+ }
98280
+ }, [value, options, open]);
98281
+ const handleSelect = (selectedValue) => {
98282
+ onChange(selectedValue);
98280
98283
  setOpen(false);
98281
98284
  };
98282
- const handleBlur = () => {
98283
- onChange(inputValue);
98285
+ const handleOpenChange = (isOpen) => {
98286
+ if (!isOpen) {
98287
+ const match2 = options.find((option) => option.label.toLowerCase() === inputValue.toLowerCase());
98288
+ if (!match2 && inputValue !== (options.find((opt) => opt.value === value)?.label || value)) {
98289
+ onChange(inputValue);
98290
+ }
98291
+ }
98292
+ setOpen(isOpen);
98284
98293
  };
98285
98294
  const displayLabel = options.find((option) => option.value.toLowerCase() === value?.toLowerCase())?.label || value;
98286
- return /* @__PURE__ */ React169__namespace.createElement(Popover2, { open, onOpenChange: setOpen }, /* @__PURE__ */ React169__namespace.createElement(PopoverTrigger2, { asChild: true }, /* @__PURE__ */ React169__namespace.createElement(
98295
+ return /* @__PURE__ */ React169__namespace.createElement(Popover2, { open, onOpenChange: handleOpenChange }, /* @__PURE__ */ React169__namespace.createElement(PopoverTrigger2, { asChild: true }, /* @__PURE__ */ React169__namespace.createElement(
98287
98296
  Button,
98288
98297
  {
98289
98298
  variant: "outline",
@@ -98299,8 +98308,7 @@ var EditableCombobox = ({
98299
98308
  {
98300
98309
  placeholder: searchPlaceholder,
98301
98310
  value: inputValue,
98302
- onValueChange: setInputValue,
98303
- onBlur: handleBlur
98311
+ onValueChange: setInputValue
98304
98312
  }
98305
98313
  ), /* @__PURE__ */ React169__namespace.createElement(CommandList, null, /* @__PURE__ */ React169__namespace.createElement(CommandEmpty, null, noResultsMessage), /* @__PURE__ */ React169__namespace.createElement(CommandGroup, null, options.map((option) => /* @__PURE__ */ React169__namespace.createElement(
98306
98314
  CommandItem,
@@ -101237,6 +101245,10 @@ var supportedQuestionTypesForAI = [
101237
101245
  { value: "sequence", label: "Sequence" },
101238
101246
  { value: "matching", label: "Matching" }
101239
101247
  ];
101248
+ var availableLanguages = [
101249
+ { value: "English", label: "English" },
101250
+ { value: "Vietnamese", label: "Ti\u1EBFng Vi\u1EC7t" }
101251
+ ];
101240
101252
  var AIQuestionGeneratorModal = ({
101241
101253
  isOpen,
101242
101254
  onClose,
@@ -101246,51 +101258,65 @@ var AIQuestionGeneratorModal = ({
101246
101258
  subjects = [],
101247
101259
  topics = [],
101248
101260
  gradeLevels = [],
101249
- bloomLevels = []
101261
+ bloomLevels = [],
101262
+ categories = []
101250
101263
  }) => {
101251
- const [prompt, setPrompt] = React169.useState("");
101264
+ const [additionalInfo, setAdditionalInfo] = React169.useState("");
101252
101265
  const [isLoading, setIsLoading] = React169.useState(false);
101253
101266
  const [error, setError] = React169.useState(null);
101254
101267
  const { toast: toast2 } = useToast();
101255
101268
  const [subjectCode, setSubjectCode] = React169.useState("");
101269
+ const [categoryCode, setCategoryCode] = React169.useState("");
101256
101270
  const [topicCode, setTopicCode] = React169.useState("");
101257
101271
  const [gradeBand, setGradeBand] = React169.useState("");
101258
101272
  const [bloomLevelCode, setBloomLevelCode] = React169.useState("");
101259
101273
  const [selectedQuestionType, setSelectedQuestionType] = React169.useState("multiple_choice");
101274
+ const [selectedLanguage, setSelectedLanguage] = React169.useState(language3);
101260
101275
  const [numberOfOptions, setNumberOfOptions] = React169.useState(4);
101261
- const [minCorrectAnswers, setMinCorrectAnswers] = React169.useState(2);
101262
- const [maxCorrectAnswers, setMaxCorrectAnswers] = React169.useState(3);
101263
- const [isCaseSensitive, setIsCaseSensitive] = React169.useState(false);
101264
- const [numberOfBlanks, setNumberOfBlanks] = React169.useState(2);
101265
- const [numberOfSequenceItems, setNumberOfSequenceItems] = React169.useState(4);
101266
- const [numberOfMatchingPairs, setNumberOfMatchingPairs] = React169.useState(4);
101267
101276
  const [isApiKeyManagerModalOpen, setIsApiKeyManagerModalOpen] = React169.useState(false);
101268
101277
  const [geminiApiKeyExists, setGeminiApiKeyExists] = React169.useState(false);
101269
101278
  const finalQuestionType = questionTypeProp || selectedQuestionType;
101270
101279
  React169.useEffect(() => {
101271
101280
  if (isOpen) {
101272
- setPrompt("");
101281
+ setAdditionalInfo("");
101273
101282
  setError(null);
101274
101283
  setIsLoading(false);
101275
101284
  setSubjectCode("");
101285
+ setCategoryCode("");
101276
101286
  setTopicCode("");
101277
101287
  setGradeBand("");
101278
101288
  setBloomLevelCode("");
101279
101289
  setSelectedQuestionType(questionTypeProp || "multiple_choice");
101290
+ setSelectedLanguage(language3);
101280
101291
  setGeminiApiKeyExists(APIKeyService.hasAPIKey(GEMINI_API_KEY_SERVICE_NAME));
101281
101292
  }
101282
- }, [isOpen, questionTypeProp]);
101293
+ }, [isOpen, questionTypeProp, language3]);
101294
+ const filteredCategories = React169.useMemo(() => {
101295
+ return categories;
101296
+ }, [categories]);
101283
101297
  const filteredTopics = React169.useMemo(() => {
101284
- if (!subjectCode) return [];
101285
- return topics.filter((t4) => t4.subjectCode === subjectCode);
101286
- }, [subjectCode, topics]);
101298
+ if (!subjectCode || !categoryCode) return [];
101299
+ return topics.filter(
101300
+ (t4) => t4.subjectCode === subjectCode
101301
+ /* && t.categoryCode === categoryCode */
101302
+ );
101303
+ }, [subjectCode, categoryCode, topics]);
101304
+ const handleSubjectChange = (newSubjectCode) => {
101305
+ setSubjectCode(newSubjectCode);
101306
+ setCategoryCode("");
101307
+ setTopicCode("");
101308
+ };
101309
+ const handleCategoryChange = (newCategoryCode) => {
101310
+ setCategoryCode(newCategoryCode);
101311
+ setTopicCode("");
101312
+ };
101287
101313
  const handleApiKeyModalClose = () => {
101288
101314
  setIsApiKeyManagerModalOpen(false);
101289
101315
  setGeminiApiKeyExists(APIKeyService.hasAPIKey(GEMINI_API_KEY_SERVICE_NAME));
101290
101316
  };
101291
101317
  const handleSubmit = async () => {
101292
- if (!prompt.trim()) {
101293
- setError("Please provide a prompt for the question.");
101318
+ if (!subjectCode || !categoryCode || !topicCode || !gradeBand || !bloomLevelCode) {
101319
+ setError("Please fill in all required metadata fields: Subject, Category, Topic, Grade Level, and Bloom's Level.");
101294
101320
  return;
101295
101321
  }
101296
101322
  const geminiKey = APIKeyService.getAPIKey(GEMINI_API_KEY_SERVICE_NAME);
@@ -101304,14 +101330,15 @@ var AIQuestionGeneratorModal = ({
101304
101330
  setIsLoading(true);
101305
101331
  try {
101306
101332
  const quizContext = {
101307
- plannedTopic: prompt,
101333
+ plannedTopic: additionalInfo.trim() || topicCode,
101308
101334
  originalSubject: subjectCode,
101309
101335
  originalTopic: topicCode,
101336
+ originalCategory: categoryCode,
101310
101337
  gradeBand,
101311
101338
  plannedBloomLevel: bloomLevelCode
101312
101339
  };
101313
101340
  const baseClientInput = {
101314
- language: language3,
101341
+ language: selectedLanguage,
101315
101342
  difficulty: "Medium",
101316
101343
  quizContext
101317
101344
  };
@@ -101324,33 +101351,32 @@ var AIQuestionGeneratorModal = ({
101324
101351
  generatedResult = await generateMCQQuestion({ ...baseClientInput, numberOfOptions }, geminiKey);
101325
101352
  break;
101326
101353
  case "multiple_response":
101327
- generatedResult = await generateMRQQuestion({ ...baseClientInput, numberOfOptions, minCorrectAnswers, maxCorrectAnswers }, geminiKey);
101354
+ generatedResult = await generateMRQQuestion({ ...baseClientInput, numberOfOptions: 5, minCorrectAnswers: 2, maxCorrectAnswers: 3 }, geminiKey);
101328
101355
  break;
101329
101356
  case "short_answer":
101330
- generatedResult = await generateShortAnswerQuestion({ ...baseClientInput, isCaseSensitive }, geminiKey);
101357
+ generatedResult = await generateShortAnswerQuestion({ ...baseClientInput, isCaseSensitive: false }, geminiKey);
101331
101358
  break;
101332
101359
  case "numeric":
101333
101360
  generatedResult = await generateNumericQuestion({ ...baseClientInput, allowDecimals: true, tolerance: 0 }, geminiKey);
101334
101361
  break;
101335
101362
  case "fill_in_the_blanks":
101336
- generatedResult = await generateFillInTheBlanksQuestion({ ...baseClientInput, numberOfBlanks, isCaseSensitive }, geminiKey);
101363
+ generatedResult = await generateFillInTheBlanksQuestion({ ...baseClientInput, numberOfBlanks: 2, isCaseSensitive: false }, geminiKey);
101337
101364
  break;
101338
101365
  case "sequence":
101339
- generatedResult = await generateSequenceQuestion({ ...baseClientInput, numberOfItems: numberOfSequenceItems }, geminiKey);
101366
+ generatedResult = await generateSequenceQuestion({ ...baseClientInput, numberOfItems: 4 }, geminiKey);
101340
101367
  break;
101341
101368
  case "matching":
101342
- generatedResult = await generateMatchingQuestion({ ...baseClientInput, numberOfPairs: numberOfMatchingPairs, shuffleOptions: true }, geminiKey);
101369
+ generatedResult = await generateMatchingQuestion({ ...baseClientInput, numberOfPairs: 4, shuffleOptions: true }, geminiKey);
101343
101370
  break;
101344
101371
  default:
101345
101372
  throw new Error(`AI generation for '${finalQuestionType}' is not implemented in this flow.`);
101346
101373
  }
101347
- if (generatedResult.error) {
101348
- throw new Error(generatedResult.error);
101349
- }
101374
+ if (generatedResult.error) throw new Error(generatedResult.error);
101350
101375
  if (generatedResult.question) {
101351
101376
  const completeQuestion = generatedResult.question;
101352
101377
  completeQuestion.subject = subjectCode;
101353
101378
  completeQuestion.topic = topicCode;
101379
+ completeQuestion.category = categoryCode;
101354
101380
  completeQuestion.gradeBand = gradeBand;
101355
101381
  completeQuestion.bloomLevel = bloomLevelCode;
101356
101382
  if (completeQuestion.points === void 0) completeQuestion.points = 10;
@@ -101376,47 +101402,13 @@ var AIQuestionGeneratorModal = ({
101376
101402
  const comboboxOptions = {
101377
101403
  subjects: subjects.map((s4) => ({ value: s4.code, label: s4.name })),
101378
101404
  topics: filteredTopics.map((t4) => ({ value: t4.code, label: t4.name })),
101405
+ categories: filteredCategories.map((c4) => ({ value: c4.code, label: c4.name })),
101379
101406
  gradeLevels: gradeLevels.map((g) => ({ value: g.code, label: g.name })),
101380
101407
  bloomLevels: bloomLevels.map((b2) => ({ value: b2.code, label: b2.name }))
101381
101408
  };
101382
- const renderSpecificParams = () => {
101383
- switch (finalQuestionType) {
101384
- case "multiple_choice":
101385
- case "multiple_response":
101386
- return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "ai-num-options" }, "Number of Options (2-8)"), /* @__PURE__ */ React169__namespace.default.createElement(
101387
- Input,
101388
- {
101389
- id: "ai-num-options",
101390
- type: "number",
101391
- value: numberOfOptions,
101392
- onChange: (e3) => setNumberOfOptions(parseInt(e3.target.value, 10)),
101393
- min: 2,
101394
- max: 8
101395
- }
101396
- ), finalQuestionType === "multiple_response" && /* @__PURE__ */ React169__namespace.default.createElement(React169__namespace.default.Fragment, null, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "ai-min-correct" }, "Min Correct Answers"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "ai-min-correct", type: "number", value: minCorrectAnswers, onChange: (e3) => setMinCorrectAnswers(parseInt(e3.target.value, 10)), min: 1, max: numberOfOptions }), /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "ai-max-correct" }, "Max Correct Answers"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "ai-max-correct", type: "number", value: maxCorrectAnswers, onChange: (e3) => setMaxCorrectAnswers(parseInt(e3.target.value, 10)), min: minCorrectAnswers, max: numberOfOptions })));
101397
- case "short_answer":
101398
- case "fill_in_the_blanks":
101399
- return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "flex items-center space-x-2 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement("input", { type: "checkbox", id: "ai-case-sensitive", checked: isCaseSensitive, onChange: (e3) => setIsCaseSensitive(e3.target.checked), className: "h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary" }), /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "ai-case-sensitive" }, "Case Sensitive Answers"), finalQuestionType === "fill_in_the_blanks" && /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-1 ml-4" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "ai-num-blanks" }, "Number of Blanks (1-5)"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "ai-num-blanks", type: "number", value: numberOfBlanks, onChange: (e3) => setNumberOfBlanks(parseInt(e3.target.value, 10)), min: 1, max: 5 })));
101400
- case "sequence":
101401
- return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "ai-num-seq-items" }, "Number of Items to Sequence (2-10)"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "ai-num-seq-items", type: "number", value: numberOfSequenceItems, onChange: (e3) => setNumberOfSequenceItems(parseInt(e3.target.value, 10)), min: 2, max: 10 }));
101402
- case "matching":
101403
- return /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "ai-num-match-pairs" }, "Number of Pairs to Match (2-8)"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "ai-num-match-pairs", type: "number", value: numberOfMatchingPairs, onChange: (e3) => setNumberOfMatchingPairs(parseInt(e3.target.value, 10)), min: 2, max: 8 }));
101404
- default:
101405
- return null;
101406
- }
101407
- };
101408
101409
  return /* @__PURE__ */ React169__namespace.default.createElement(React169__namespace.default.Fragment, null, /* @__PURE__ */ React169__namespace.default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => {
101409
101410
  if (!open) onClose();
101410
- } }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-[600px]" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, { className: "flex items-center font-headline text-2xl" }, /* @__PURE__ */ React169__namespace.default.createElement(WandSparkles, { className: "mr-2 h-6 w-6 text-primary" }), " AI Question Generator"), /* @__PURE__ */ React169__namespace.default.createElement(DialogDescription2, null, "Provide a prompt and metadata to generate a '", finalQuestionType, "' question.")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 py-4 max-h-[60vh] overflow-y-auto px-2" }, !geminiApiKeyExists && /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "p-3 mb-4 border border-amber-500 bg-amber-50 rounded-md text-amber-700" }), !questionTypeProp && /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "ai-q-type-select" }, "Question Type"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: selectedQuestionType, onValueChange: (v) => setSelectedQuestionType(v) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, { id: "ai-q-type-select" }, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, supportedQuestionTypesForAI.map((type) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: type.value, value: type.value }, type.label))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "ai-prompt" }, "Prompt / Topic"), /* @__PURE__ */ React169__namespace.default.createElement(
101411
- Textarea,
101412
- {
101413
- id: "ai-prompt",
101414
- value: prompt,
101415
- onChange: (e3) => setPrompt(e3.target.value),
101416
- placeholder: "e.g., The process of photosynthesis, The causes of World War II, Basic Algebra Equations",
101417
- className: "min-h-[100px]"
101418
- }
101419
- )), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, null, "Subject"), /* @__PURE__ */ React169__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.subjects, value: subjectCode, onChange: setSubjectCode, placeholder: "Select or type a Subject..." })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, null, "Topic"), /* @__PURE__ */ React169__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.topics, value: topicCode, onChange: setTopicCode, placeholder: "Select or type a Topic...", disabled: !subjectCode })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, null, "Grade Level"), /* @__PURE__ */ React169__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.gradeLevels, value: gradeBand, onChange: setGradeBand, placeholder: "Select or type a Grade..." })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, null, "Bloom's Level"), /* @__PURE__ */ React169__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.bloomLevels, value: bloomLevelCode, onChange: setBloomLevelCode, placeholder: "Select a Bloom's Level..." }))), renderSpecificParams(), error && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-destructive flex items-center mt-2" }, /* @__PURE__ */ React169__namespace.default.createElement(TriangleAlert, { className: "mr-1 h-4 w-4" }), " ", error)), /* @__PURE__ */ React169__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "outline" }, "Cancel")), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", onClick: handleSubmit, disabled: isLoading || !prompt.trim() || !geminiApiKeyExists }, isLoading ? /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React169__namespace.default.createElement(WandSparkles, { className: "mr-2 h-4 w-4" }), "Generate Question")))), /* @__PURE__ */ React169__namespace.default.createElement(APIKeyManagerModal, { isOpen: isApiKeyManagerModalOpen, onClose: handleApiKeyModalClose }));
101411
+ } }, /* @__PURE__ */ React169__namespace.default.createElement(DialogContent2, { className: "sm:max-w-[700px]" }, /* @__PURE__ */ React169__namespace.default.createElement(DialogHeader, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogTitle2, { className: "flex items-center font-headline text-2xl" }, /* @__PURE__ */ React169__namespace.default.createElement(WandSparkles, { className: "mr-2 h-6 w-6 text-primary" }), " AI Question Generator"), /* @__PURE__ */ React169__namespace.default.createElement(DialogDescription2, null, "Provide metadata and optional info to generate a '", finalQuestionType, "' question.")), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-4 py-4 max-h-[60vh] overflow-y-auto px-2" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-4" }, !questionTypeProp && /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, null, "Question Type"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: selectedQuestionType, onValueChange: (v) => setSelectedQuestionType(v) }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, supportedQuestionTypesForAI.map((type) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: type.value, value: type.value }, type.label))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, null, "Language"), /* @__PURE__ */ React169__namespace.default.createElement(Select2, { value: selectedLanguage, onValueChange: setSelectedLanguage }, /* @__PURE__ */ React169__namespace.default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__namespace.default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__namespace.default.createElement(SelectContent2, null, availableLanguages.map((lang) => /* @__PURE__ */ React169__namespace.default.createElement(SelectItem2, { key: lang.value, value: lang.value }, lang.label)))))), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "ai-additional-info" }, "Additional Info (Optional)"), /* @__PURE__ */ React169__namespace.default.createElement(Textarea, { id: "ai-additional-info", value: additionalInfo, onChange: (e3) => setAdditionalInfo(e3.target.value), placeholder: "Provide extra context, a specific topic, or a detailed prompt for the AI...", className: "min-h-[100px]" })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "grid grid-cols-2 gap-4" }, /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, null, "Subject *"), /* @__PURE__ */ React169__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.subjects, value: subjectCode, onChange: handleSubjectChange, placeholder: "Select Subject..." })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, null, "Category *"), /* @__PURE__ */ React169__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.categories, value: categoryCode, onChange: handleCategoryChange, placeholder: "Select Category...", disabled: !subjectCode })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, null, "Topic *"), /* @__PURE__ */ React169__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.topics, value: topicCode, onChange: setTopicCode, placeholder: "Select Topic...", disabled: !categoryCode })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, null, "Grade Level *"), /* @__PURE__ */ React169__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.gradeLevels, value: gradeBand, onChange: setGradeBand, placeholder: "Select Grade..." })), /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, null, "Bloom's Level *"), /* @__PURE__ */ React169__namespace.default.createElement(EditableCombobox, { options: comboboxOptions.bloomLevels, value: bloomLevelCode, onChange: setBloomLevelCode, placeholder: "Select Bloom's Level..." }))), finalQuestionType === "multiple_choice" && /* @__PURE__ */ React169__namespace.default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React169__namespace.default.createElement(Label2, { htmlFor: "ai-num-options" }, "Number of Options (2-8)"), /* @__PURE__ */ React169__namespace.default.createElement(Input, { id: "ai-num-options", type: "number", value: numberOfOptions, onChange: (e3) => setNumberOfOptions(parseInt(e3.target.value, 10)), min: 2, max: 8 })), error && /* @__PURE__ */ React169__namespace.default.createElement("p", { className: "text-sm text-destructive flex items-center mt-2" }, /* @__PURE__ */ React169__namespace.default.createElement(TriangleAlert, { className: "mr-1 h-4 w-4" }), " ", error)), /* @__PURE__ */ React169__namespace.default.createElement(DialogFooter, null, /* @__PURE__ */ React169__namespace.default.createElement(DialogClose2, { asChild: true }, /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", variant: "outline" }, "Cancel")), /* @__PURE__ */ React169__namespace.default.createElement(Button, { type: "button", onClick: handleSubmit, disabled: isLoading || !geminiApiKeyExists || !subjectCode || !categoryCode || !topicCode || !gradeBand || !bloomLevelCode }, isLoading ? /* @__PURE__ */ React169__namespace.default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React169__namespace.default.createElement(WandSparkles, { className: "mr-2 h-4 w-4" }), "Generate Question")))), /* @__PURE__ */ React169__namespace.default.createElement(APIKeyManagerModal, { isOpen: isApiKeyManagerModalOpen, onClose: handleApiKeyModalClose }));
101420
101412
  };
101421
101413
 
101422
101414
  // src/react-ui/components/authoring/AIFullQuizGeneratorModal.tsx
@@ -5,7 +5,7 @@ import { Q as QuizResultType, U as UserAnswerType, n as PracticeSession, o as Pr
5
5
  export { j as AchievementDefinition, r as ActivityCalendarData, u as AnalysisReport, A as AnswerDetail, x as ChatContext, C as ChatMessage, v as DashboardCardConfig, D as DashboardCardId, w as DashboardLayout, y as Goal, G as GoalType, t as ImageContextItem, I as ImportError, K as KnowledgeCard, L as LearningAnalysis, e as PerformanceByBloomLevel, b as PerformanceByCategory, d as PerformanceByDifficulty, P as PerformanceByLearningObjective, c as PerformanceByTopic, f as PerformanceMetric, s as PerformanceSummary, k as PracticeDifficulty, q as PracticeTopicSummary, g as QuestionReview, R as RoadmapItem, T as TestCaseResult, a as UserAnswers, W as WeeklyRoadmap } from './ai-ecosystem-DyQYZbyX.cjs';
6
6
  import * as React$1 from 'react';
7
7
  import React__default, { ReactNode } from 'react';
8
- export { c as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, e as APIKeyManagerModal, f as ApiKeySettings, m as ApproachManager, B as BloomLevelManager, C as CategoryManager, l as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, n as MetadataImportControls, M as MetadataTabs, h as QuestionFilters, i as QuestionFormDialog, g as QuestionList, a as QuestionPreviewModal, k as QuestionTypeManager, Q as QuizAuthoringTool, b as QuizSettingsForm, d as SCORMExportModal, S as SelectedQuestionsPanel, j as SubjectManager, o as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-6AR8w2TO.cjs';
8
+ export { c as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, e as APIKeyManagerModal, f as ApiKeySettings, m as ApproachManager, B as BloomLevelManager, C as CategoryManager, l as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, n as MetadataImportControls, M as MetadataTabs, h as QuestionFilters, i as QuestionFormDialog, g as QuestionList, a as QuestionPreviewModal, k as QuestionTypeManager, Q as QuizAuthoringTool, b as QuizSettingsForm, d as SCORMExportModal, S as SelectedQuestionsPanel, j as SubjectManager, o as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-Bvhmyef9.cjs';
9
9
  import * as class_variance_authority_types from 'class-variance-authority/types';
10
10
  import { VariantProps } from 'class-variance-authority';
11
11
  import * as LabelPrimitive from '@radix-ui/react-label';
@@ -5,7 +5,7 @@ import { Q as QuizResultType, U as UserAnswerType, n as PracticeSession, o as Pr
5
5
  export { j as AchievementDefinition, r as ActivityCalendarData, u as AnalysisReport, A as AnswerDetail, x as ChatContext, C as ChatMessage, v as DashboardCardConfig, D as DashboardCardId, w as DashboardLayout, y as Goal, G as GoalType, t as ImageContextItem, I as ImportError, K as KnowledgeCard, L as LearningAnalysis, e as PerformanceByBloomLevel, b as PerformanceByCategory, d as PerformanceByDifficulty, P as PerformanceByLearningObjective, c as PerformanceByTopic, f as PerformanceMetric, s as PerformanceSummary, k as PracticeDifficulty, q as PracticeTopicSummary, g as QuestionReview, R as RoadmapItem, T as TestCaseResult, a as UserAnswers, W as WeeklyRoadmap } from './ai-ecosystem-Qa_SdE2T.js';
6
6
  import * as React$1 from 'react';
7
7
  import React__default, { ReactNode } from 'react';
8
- export { c as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, e as APIKeyManagerModal, f as ApiKeySettings, m as ApproachManager, B as BloomLevelManager, C as CategoryManager, l as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, n as MetadataImportControls, M as MetadataTabs, h as QuestionFilters, i as QuestionFormDialog, g as QuestionList, a as QuestionPreviewModal, k as QuestionTypeManager, Q as QuizAuthoringTool, b as QuizSettingsForm, d as SCORMExportModal, S as SelectedQuestionsPanel, j as SubjectManager, o as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-DAXYZdrz.js';
8
+ export { c as AIFullQuizGeneratorModal, A as AIQuestionGeneratorModal, e as APIKeyManagerModal, f as ApiKeySettings, m as ApproachManager, B as BloomLevelManager, C as CategoryManager, l as ContextManager, E as EditQuestionModal, G as GradeLevelManager, I as ImportQuestionsModal, L as LearningObjectiveManager, n as MetadataImportControls, M as MetadataTabs, h as QuestionFilters, i as QuestionFormDialog, g as QuestionList, a as QuestionPreviewModal, k as QuestionTypeManager, Q as QuizAuthoringTool, b as QuizSettingsForm, d as SCORMExportModal, S as SelectedQuestionsPanel, j as SubjectManager, o as Toaster, T as TopicManager, t as toast, u as useToast } from './toaster-B2MPZYhi.js';
9
9
  import * as class_variance_authority_types from 'class-variance-authority/types';
10
10
  import { VariantProps } from 'class-variance-authority';
11
11
  import * as LabelPrimitive from '@radix-ui/react-label';
package/dist/react-ui.mjs CHANGED
@@ -98203,21 +98203,30 @@ var EditableCombobox = ({
98203
98203
  disabled = false
98204
98204
  }) => {
98205
98205
  const [open, setOpen] = React169.useState(false);
98206
- const [inputValue, setInputValue] = React169.useState(value);
98206
+ const [inputValue, setInputValue] = React169.useState("");
98207
98207
  React169.useEffect(() => {
98208
- setInputValue(value);
98209
- }, [value]);
98210
- const handleSelect = (currentValue) => {
98211
- const newValue = currentValue === value ? "" : currentValue;
98212
- onChange(newValue);
98213
- setInputValue(newValue);
98208
+ if (value) {
98209
+ const selectedOption = options.find((option) => option.value.toLowerCase() === value.toLowerCase());
98210
+ setInputValue(selectedOption ? selectedOption.label : value);
98211
+ } else {
98212
+ setInputValue("");
98213
+ }
98214
+ }, [value, options, open]);
98215
+ const handleSelect = (selectedValue) => {
98216
+ onChange(selectedValue);
98214
98217
  setOpen(false);
98215
98218
  };
98216
- const handleBlur = () => {
98217
- onChange(inputValue);
98219
+ const handleOpenChange = (isOpen) => {
98220
+ if (!isOpen) {
98221
+ const match2 = options.find((option) => option.label.toLowerCase() === inputValue.toLowerCase());
98222
+ if (!match2 && inputValue !== (options.find((opt) => opt.value === value)?.label || value)) {
98223
+ onChange(inputValue);
98224
+ }
98225
+ }
98226
+ setOpen(isOpen);
98218
98227
  };
98219
98228
  const displayLabel = options.find((option) => option.value.toLowerCase() === value?.toLowerCase())?.label || value;
98220
- return /* @__PURE__ */ React169.createElement(Popover2, { open, onOpenChange: setOpen }, /* @__PURE__ */ React169.createElement(PopoverTrigger2, { asChild: true }, /* @__PURE__ */ React169.createElement(
98229
+ return /* @__PURE__ */ React169.createElement(Popover2, { open, onOpenChange: handleOpenChange }, /* @__PURE__ */ React169.createElement(PopoverTrigger2, { asChild: true }, /* @__PURE__ */ React169.createElement(
98221
98230
  Button,
98222
98231
  {
98223
98232
  variant: "outline",
@@ -98233,8 +98242,7 @@ var EditableCombobox = ({
98233
98242
  {
98234
98243
  placeholder: searchPlaceholder,
98235
98244
  value: inputValue,
98236
- onValueChange: setInputValue,
98237
- onBlur: handleBlur
98245
+ onValueChange: setInputValue
98238
98246
  }
98239
98247
  ), /* @__PURE__ */ React169.createElement(CommandList, null, /* @__PURE__ */ React169.createElement(CommandEmpty, null, noResultsMessage), /* @__PURE__ */ React169.createElement(CommandGroup, null, options.map((option) => /* @__PURE__ */ React169.createElement(
98240
98248
  CommandItem,
@@ -101171,6 +101179,10 @@ var supportedQuestionTypesForAI = [
101171
101179
  { value: "sequence", label: "Sequence" },
101172
101180
  { value: "matching", label: "Matching" }
101173
101181
  ];
101182
+ var availableLanguages = [
101183
+ { value: "English", label: "English" },
101184
+ { value: "Vietnamese", label: "Ti\u1EBFng Vi\u1EC7t" }
101185
+ ];
101174
101186
  var AIQuestionGeneratorModal = ({
101175
101187
  isOpen,
101176
101188
  onClose,
@@ -101180,51 +101192,65 @@ var AIQuestionGeneratorModal = ({
101180
101192
  subjects = [],
101181
101193
  topics = [],
101182
101194
  gradeLevels = [],
101183
- bloomLevels = []
101195
+ bloomLevels = [],
101196
+ categories = []
101184
101197
  }) => {
101185
- const [prompt, setPrompt] = useState("");
101198
+ const [additionalInfo, setAdditionalInfo] = useState("");
101186
101199
  const [isLoading, setIsLoading] = useState(false);
101187
101200
  const [error, setError] = useState(null);
101188
101201
  const { toast: toast2 } = useToast();
101189
101202
  const [subjectCode, setSubjectCode] = useState("");
101203
+ const [categoryCode, setCategoryCode] = useState("");
101190
101204
  const [topicCode, setTopicCode] = useState("");
101191
101205
  const [gradeBand, setGradeBand] = useState("");
101192
101206
  const [bloomLevelCode, setBloomLevelCode] = useState("");
101193
101207
  const [selectedQuestionType, setSelectedQuestionType] = useState("multiple_choice");
101208
+ const [selectedLanguage, setSelectedLanguage] = useState(language3);
101194
101209
  const [numberOfOptions, setNumberOfOptions] = useState(4);
101195
- const [minCorrectAnswers, setMinCorrectAnswers] = useState(2);
101196
- const [maxCorrectAnswers, setMaxCorrectAnswers] = useState(3);
101197
- const [isCaseSensitive, setIsCaseSensitive] = useState(false);
101198
- const [numberOfBlanks, setNumberOfBlanks] = useState(2);
101199
- const [numberOfSequenceItems, setNumberOfSequenceItems] = useState(4);
101200
- const [numberOfMatchingPairs, setNumberOfMatchingPairs] = useState(4);
101201
101210
  const [isApiKeyManagerModalOpen, setIsApiKeyManagerModalOpen] = useState(false);
101202
101211
  const [geminiApiKeyExists, setGeminiApiKeyExists] = useState(false);
101203
101212
  const finalQuestionType = questionTypeProp || selectedQuestionType;
101204
101213
  useEffect(() => {
101205
101214
  if (isOpen) {
101206
- setPrompt("");
101215
+ setAdditionalInfo("");
101207
101216
  setError(null);
101208
101217
  setIsLoading(false);
101209
101218
  setSubjectCode("");
101219
+ setCategoryCode("");
101210
101220
  setTopicCode("");
101211
101221
  setGradeBand("");
101212
101222
  setBloomLevelCode("");
101213
101223
  setSelectedQuestionType(questionTypeProp || "multiple_choice");
101224
+ setSelectedLanguage(language3);
101214
101225
  setGeminiApiKeyExists(APIKeyService.hasAPIKey(GEMINI_API_KEY_SERVICE_NAME));
101215
101226
  }
101216
- }, [isOpen, questionTypeProp]);
101227
+ }, [isOpen, questionTypeProp, language3]);
101228
+ const filteredCategories = useMemo(() => {
101229
+ return categories;
101230
+ }, [categories]);
101217
101231
  const filteredTopics = useMemo(() => {
101218
- if (!subjectCode) return [];
101219
- return topics.filter((t4) => t4.subjectCode === subjectCode);
101220
- }, [subjectCode, topics]);
101232
+ if (!subjectCode || !categoryCode) return [];
101233
+ return topics.filter(
101234
+ (t4) => t4.subjectCode === subjectCode
101235
+ /* && t.categoryCode === categoryCode */
101236
+ );
101237
+ }, [subjectCode, categoryCode, topics]);
101238
+ const handleSubjectChange = (newSubjectCode) => {
101239
+ setSubjectCode(newSubjectCode);
101240
+ setCategoryCode("");
101241
+ setTopicCode("");
101242
+ };
101243
+ const handleCategoryChange = (newCategoryCode) => {
101244
+ setCategoryCode(newCategoryCode);
101245
+ setTopicCode("");
101246
+ };
101221
101247
  const handleApiKeyModalClose = () => {
101222
101248
  setIsApiKeyManagerModalOpen(false);
101223
101249
  setGeminiApiKeyExists(APIKeyService.hasAPIKey(GEMINI_API_KEY_SERVICE_NAME));
101224
101250
  };
101225
101251
  const handleSubmit = async () => {
101226
- if (!prompt.trim()) {
101227
- setError("Please provide a prompt for the question.");
101252
+ if (!subjectCode || !categoryCode || !topicCode || !gradeBand || !bloomLevelCode) {
101253
+ setError("Please fill in all required metadata fields: Subject, Category, Topic, Grade Level, and Bloom's Level.");
101228
101254
  return;
101229
101255
  }
101230
101256
  const geminiKey = APIKeyService.getAPIKey(GEMINI_API_KEY_SERVICE_NAME);
@@ -101238,14 +101264,15 @@ var AIQuestionGeneratorModal = ({
101238
101264
  setIsLoading(true);
101239
101265
  try {
101240
101266
  const quizContext = {
101241
- plannedTopic: prompt,
101267
+ plannedTopic: additionalInfo.trim() || topicCode,
101242
101268
  originalSubject: subjectCode,
101243
101269
  originalTopic: topicCode,
101270
+ originalCategory: categoryCode,
101244
101271
  gradeBand,
101245
101272
  plannedBloomLevel: bloomLevelCode
101246
101273
  };
101247
101274
  const baseClientInput = {
101248
- language: language3,
101275
+ language: selectedLanguage,
101249
101276
  difficulty: "Medium",
101250
101277
  quizContext
101251
101278
  };
@@ -101258,33 +101285,32 @@ var AIQuestionGeneratorModal = ({
101258
101285
  generatedResult = await generateMCQQuestion({ ...baseClientInput, numberOfOptions }, geminiKey);
101259
101286
  break;
101260
101287
  case "multiple_response":
101261
- generatedResult = await generateMRQQuestion({ ...baseClientInput, numberOfOptions, minCorrectAnswers, maxCorrectAnswers }, geminiKey);
101288
+ generatedResult = await generateMRQQuestion({ ...baseClientInput, numberOfOptions: 5, minCorrectAnswers: 2, maxCorrectAnswers: 3 }, geminiKey);
101262
101289
  break;
101263
101290
  case "short_answer":
101264
- generatedResult = await generateShortAnswerQuestion({ ...baseClientInput, isCaseSensitive }, geminiKey);
101291
+ generatedResult = await generateShortAnswerQuestion({ ...baseClientInput, isCaseSensitive: false }, geminiKey);
101265
101292
  break;
101266
101293
  case "numeric":
101267
101294
  generatedResult = await generateNumericQuestion({ ...baseClientInput, allowDecimals: true, tolerance: 0 }, geminiKey);
101268
101295
  break;
101269
101296
  case "fill_in_the_blanks":
101270
- generatedResult = await generateFillInTheBlanksQuestion({ ...baseClientInput, numberOfBlanks, isCaseSensitive }, geminiKey);
101297
+ generatedResult = await generateFillInTheBlanksQuestion({ ...baseClientInput, numberOfBlanks: 2, isCaseSensitive: false }, geminiKey);
101271
101298
  break;
101272
101299
  case "sequence":
101273
- generatedResult = await generateSequenceQuestion({ ...baseClientInput, numberOfItems: numberOfSequenceItems }, geminiKey);
101300
+ generatedResult = await generateSequenceQuestion({ ...baseClientInput, numberOfItems: 4 }, geminiKey);
101274
101301
  break;
101275
101302
  case "matching":
101276
- generatedResult = await generateMatchingQuestion({ ...baseClientInput, numberOfPairs: numberOfMatchingPairs, shuffleOptions: true }, geminiKey);
101303
+ generatedResult = await generateMatchingQuestion({ ...baseClientInput, numberOfPairs: 4, shuffleOptions: true }, geminiKey);
101277
101304
  break;
101278
101305
  default:
101279
101306
  throw new Error(`AI generation for '${finalQuestionType}' is not implemented in this flow.`);
101280
101307
  }
101281
- if (generatedResult.error) {
101282
- throw new Error(generatedResult.error);
101283
- }
101308
+ if (generatedResult.error) throw new Error(generatedResult.error);
101284
101309
  if (generatedResult.question) {
101285
101310
  const completeQuestion = generatedResult.question;
101286
101311
  completeQuestion.subject = subjectCode;
101287
101312
  completeQuestion.topic = topicCode;
101313
+ completeQuestion.category = categoryCode;
101288
101314
  completeQuestion.gradeBand = gradeBand;
101289
101315
  completeQuestion.bloomLevel = bloomLevelCode;
101290
101316
  if (completeQuestion.points === void 0) completeQuestion.points = 10;
@@ -101310,47 +101336,13 @@ var AIQuestionGeneratorModal = ({
101310
101336
  const comboboxOptions = {
101311
101337
  subjects: subjects.map((s4) => ({ value: s4.code, label: s4.name })),
101312
101338
  topics: filteredTopics.map((t4) => ({ value: t4.code, label: t4.name })),
101339
+ categories: filteredCategories.map((c4) => ({ value: c4.code, label: c4.name })),
101313
101340
  gradeLevels: gradeLevels.map((g) => ({ value: g.code, label: g.name })),
101314
101341
  bloomLevels: bloomLevels.map((b2) => ({ value: b2.code, label: b2.name }))
101315
101342
  };
101316
- const renderSpecificParams = () => {
101317
- switch (finalQuestionType) {
101318
- case "multiple_choice":
101319
- case "multiple_response":
101320
- return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "ai-num-options" }, "Number of Options (2-8)"), /* @__PURE__ */ React169__default.createElement(
101321
- Input,
101322
- {
101323
- id: "ai-num-options",
101324
- type: "number",
101325
- value: numberOfOptions,
101326
- onChange: (e3) => setNumberOfOptions(parseInt(e3.target.value, 10)),
101327
- min: 2,
101328
- max: 8
101329
- }
101330
- ), finalQuestionType === "multiple_response" && /* @__PURE__ */ React169__default.createElement(React169__default.Fragment, null, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "ai-min-correct" }, "Min Correct Answers"), /* @__PURE__ */ React169__default.createElement(Input, { id: "ai-min-correct", type: "number", value: minCorrectAnswers, onChange: (e3) => setMinCorrectAnswers(parseInt(e3.target.value, 10)), min: 1, max: numberOfOptions }), /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "ai-max-correct" }, "Max Correct Answers"), /* @__PURE__ */ React169__default.createElement(Input, { id: "ai-max-correct", type: "number", value: maxCorrectAnswers, onChange: (e3) => setMaxCorrectAnswers(parseInt(e3.target.value, 10)), min: minCorrectAnswers, max: numberOfOptions })));
101331
- case "short_answer":
101332
- case "fill_in_the_blanks":
101333
- return /* @__PURE__ */ React169__default.createElement("div", { className: "flex items-center space-x-2 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement("input", { type: "checkbox", id: "ai-case-sensitive", checked: isCaseSensitive, onChange: (e3) => setIsCaseSensitive(e3.target.checked), className: "h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary" }), /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "ai-case-sensitive" }, "Case Sensitive Answers"), finalQuestionType === "fill_in_the_blanks" && /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-1 ml-4" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "ai-num-blanks" }, "Number of Blanks (1-5)"), /* @__PURE__ */ React169__default.createElement(Input, { id: "ai-num-blanks", type: "number", value: numberOfBlanks, onChange: (e3) => setNumberOfBlanks(parseInt(e3.target.value, 10)), min: 1, max: 5 })));
101334
- case "sequence":
101335
- return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "ai-num-seq-items" }, "Number of Items to Sequence (2-10)"), /* @__PURE__ */ React169__default.createElement(Input, { id: "ai-num-seq-items", type: "number", value: numberOfSequenceItems, onChange: (e3) => setNumberOfSequenceItems(parseInt(e3.target.value, 10)), min: 2, max: 10 }));
101336
- case "matching":
101337
- return /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "ai-num-match-pairs" }, "Number of Pairs to Match (2-8)"), /* @__PURE__ */ React169__default.createElement(Input, { id: "ai-num-match-pairs", type: "number", value: numberOfMatchingPairs, onChange: (e3) => setNumberOfMatchingPairs(parseInt(e3.target.value, 10)), min: 2, max: 8 }));
101338
- default:
101339
- return null;
101340
- }
101341
- };
101342
101343
  return /* @__PURE__ */ React169__default.createElement(React169__default.Fragment, null, /* @__PURE__ */ React169__default.createElement(Dialog2, { open: isOpen, onOpenChange: (open) => {
101343
101344
  if (!open) onClose();
101344
- } }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-[600px]" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, { className: "flex items-center font-headline text-2xl" }, /* @__PURE__ */ React169__default.createElement(WandSparkles, { className: "mr-2 h-6 w-6 text-primary" }), " AI Question Generator"), /* @__PURE__ */ React169__default.createElement(DialogDescription2, null, "Provide a prompt and metadata to generate a '", finalQuestionType, "' question.")), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 py-4 max-h-[60vh] overflow-y-auto px-2" }, !geminiApiKeyExists && /* @__PURE__ */ React169__default.createElement("div", { className: "p-3 mb-4 border border-amber-500 bg-amber-50 rounded-md text-amber-700" }), !questionTypeProp && /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "ai-q-type-select" }, "Question Type"), /* @__PURE__ */ React169__default.createElement(Select2, { value: selectedQuestionType, onValueChange: (v) => setSelectedQuestionType(v) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, { id: "ai-q-type-select" }, /* @__PURE__ */ React169__default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, supportedQuestionTypesForAI.map((type) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: type.value, value: type.value }, type.label))))), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "ai-prompt" }, "Prompt / Topic"), /* @__PURE__ */ React169__default.createElement(
101345
- Textarea,
101346
- {
101347
- id: "ai-prompt",
101348
- value: prompt,
101349
- onChange: (e3) => setPrompt(e3.target.value),
101350
- placeholder: "e.g., The process of photosynthesis, The causes of World War II, Basic Algebra Equations",
101351
- className: "min-h-[100px]"
101352
- }
101353
- )), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, null, "Subject"), /* @__PURE__ */ React169__default.createElement(EditableCombobox, { options: comboboxOptions.subjects, value: subjectCode, onChange: setSubjectCode, placeholder: "Select or type a Subject..." })), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, null, "Topic"), /* @__PURE__ */ React169__default.createElement(EditableCombobox, { options: comboboxOptions.topics, value: topicCode, onChange: setTopicCode, placeholder: "Select or type a Topic...", disabled: !subjectCode })), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, null, "Grade Level"), /* @__PURE__ */ React169__default.createElement(EditableCombobox, { options: comboboxOptions.gradeLevels, value: gradeBand, onChange: setGradeBand, placeholder: "Select or type a Grade..." })), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, null, "Bloom's Level"), /* @__PURE__ */ React169__default.createElement(EditableCombobox, { options: comboboxOptions.bloomLevels, value: bloomLevelCode, onChange: setBloomLevelCode, placeholder: "Select a Bloom's Level..." }))), renderSpecificParams(), error && /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-destructive flex items-center mt-2" }, /* @__PURE__ */ React169__default.createElement(TriangleAlert, { className: "mr-1 h-4 w-4" }), " ", error)), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__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: handleSubmit, disabled: isLoading || !prompt.trim() || !geminiApiKeyExists }, isLoading ? /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React169__default.createElement(WandSparkles, { className: "mr-2 h-4 w-4" }), "Generate Question")))), /* @__PURE__ */ React169__default.createElement(APIKeyManagerModal, { isOpen: isApiKeyManagerModalOpen, onClose: handleApiKeyModalClose }));
101345
+ } }, /* @__PURE__ */ React169__default.createElement(DialogContent2, { className: "sm:max-w-[700px]" }, /* @__PURE__ */ React169__default.createElement(DialogHeader, null, /* @__PURE__ */ React169__default.createElement(DialogTitle2, { className: "flex items-center font-headline text-2xl" }, /* @__PURE__ */ React169__default.createElement(WandSparkles, { className: "mr-2 h-6 w-6 text-primary" }), " AI Question Generator"), /* @__PURE__ */ React169__default.createElement(DialogDescription2, null, "Provide metadata and optional info to generate a '", finalQuestionType, "' question.")), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-4 py-4 max-h-[60vh] overflow-y-auto px-2" }, /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-2 gap-4" }, !questionTypeProp && /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, null, "Question Type"), /* @__PURE__ */ React169__default.createElement(Select2, { value: selectedQuestionType, onValueChange: (v) => setSelectedQuestionType(v) }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, supportedQuestionTypesForAI.map((type) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: type.value, value: type.value }, type.label))))), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, null, "Language"), /* @__PURE__ */ React169__default.createElement(Select2, { value: selectedLanguage, onValueChange: setSelectedLanguage }, /* @__PURE__ */ React169__default.createElement(SelectTrigger2, null, /* @__PURE__ */ React169__default.createElement(SelectValue2, null)), /* @__PURE__ */ React169__default.createElement(SelectContent2, null, availableLanguages.map((lang) => /* @__PURE__ */ React169__default.createElement(SelectItem2, { key: lang.value, value: lang.value }, lang.label)))))), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "ai-additional-info" }, "Additional Info (Optional)"), /* @__PURE__ */ React169__default.createElement(Textarea, { id: "ai-additional-info", value: additionalInfo, onChange: (e3) => setAdditionalInfo(e3.target.value), placeholder: "Provide extra context, a specific topic, or a detailed prompt for the AI...", className: "min-h-[100px]" })), /* @__PURE__ */ React169__default.createElement("div", { className: "grid grid-cols-2 gap-4" }, /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, null, "Subject *"), /* @__PURE__ */ React169__default.createElement(EditableCombobox, { options: comboboxOptions.subjects, value: subjectCode, onChange: handleSubjectChange, placeholder: "Select Subject..." })), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, null, "Category *"), /* @__PURE__ */ React169__default.createElement(EditableCombobox, { options: comboboxOptions.categories, value: categoryCode, onChange: handleCategoryChange, placeholder: "Select Category...", disabled: !subjectCode })), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, null, "Topic *"), /* @__PURE__ */ React169__default.createElement(EditableCombobox, { options: comboboxOptions.topics, value: topicCode, onChange: setTopicCode, placeholder: "Select Topic...", disabled: !categoryCode })), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, null, "Grade Level *"), /* @__PURE__ */ React169__default.createElement(EditableCombobox, { options: comboboxOptions.gradeLevels, value: gradeBand, onChange: setGradeBand, placeholder: "Select Grade..." })), /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2" }, /* @__PURE__ */ React169__default.createElement(Label2, null, "Bloom's Level *"), /* @__PURE__ */ React169__default.createElement(EditableCombobox, { options: comboboxOptions.bloomLevels, value: bloomLevelCode, onChange: setBloomLevelCode, placeholder: "Select Bloom's Level..." }))), finalQuestionType === "multiple_choice" && /* @__PURE__ */ React169__default.createElement("div", { className: "space-y-2 pt-4 border-t" }, /* @__PURE__ */ React169__default.createElement(Label2, { htmlFor: "ai-num-options" }, "Number of Options (2-8)"), /* @__PURE__ */ React169__default.createElement(Input, { id: "ai-num-options", type: "number", value: numberOfOptions, onChange: (e3) => setNumberOfOptions(parseInt(e3.target.value, 10)), min: 2, max: 8 })), error && /* @__PURE__ */ React169__default.createElement("p", { className: "text-sm text-destructive flex items-center mt-2" }, /* @__PURE__ */ React169__default.createElement(TriangleAlert, { className: "mr-1 h-4 w-4" }), " ", error)), /* @__PURE__ */ React169__default.createElement(DialogFooter, null, /* @__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: handleSubmit, disabled: isLoading || !geminiApiKeyExists || !subjectCode || !categoryCode || !topicCode || !gradeBand || !bloomLevelCode }, isLoading ? /* @__PURE__ */ React169__default.createElement(LoaderCircle, { className: "mr-2 h-4 w-4 animate-spin" }) : /* @__PURE__ */ React169__default.createElement(WandSparkles, { className: "mr-2 h-4 w-4" }), "Generate Question")))), /* @__PURE__ */ React169__default.createElement(APIKeyManagerModal, { isOpen: isApiKeyManagerModalOpen, onClose: handleApiKeyModalClose }));
101354
101346
  };
101355
101347
 
101356
101348
  // src/react-ui/components/authoring/AIFullQuizGeneratorModal.tsx
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import React__default from 'react';
3
3
  import { s as QuizConfig, g as QuizQuestion, Q as QuestionTypeStrings, r as QuizSettings } from './quiz-config-CwaP-pBs.js';
4
- import { Subject, Topic, GradeLevel, BloomLevelType, QuestionInBank, QuestionFilters as QuestionFilters$1, Category, QuestionTypeType, LearningObjective, Context, Approach } from './index.js';
4
+ import { Subject, Topic, GradeLevel, BloomLevelType, Category, QuestionInBank, QuestionFilters as QuestionFilters$1, QuestionTypeType, LearningObjective, Context, Approach } from './index.js';
5
5
  import * as class_variance_authority_types from 'class-variance-authority/types';
6
6
  import * as ToastPrimitives from '@radix-ui/react-toast';
7
7
  import { VariantProps } from 'class-variance-authority';
@@ -23,6 +23,7 @@ interface AIQuestionGeneratorModalProps {
23
23
  topics?: Topic[];
24
24
  gradeLevels?: GradeLevel[];
25
25
  bloomLevels?: BloomLevelType[];
26
+ categories?: Category[];
26
27
  }
27
28
  declare const AIQuestionGeneratorModal: React__default.FC<AIQuestionGeneratorModalProps>;
28
29
 
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import React__default from 'react';
3
3
  import { s as QuizConfig, g as QuizQuestion, Q as QuestionTypeStrings, r as QuizSettings } from './quiz-config-CwaP-pBs.cjs';
4
- import { Subject, Topic, GradeLevel, BloomLevelType, QuestionInBank, QuestionFilters as QuestionFilters$1, Category, QuestionTypeType, LearningObjective, Context, Approach } from './index.cjs';
4
+ import { Subject, Topic, GradeLevel, BloomLevelType, Category, QuestionInBank, QuestionFilters as QuestionFilters$1, QuestionTypeType, LearningObjective, Context, Approach } from './index.cjs';
5
5
  import * as class_variance_authority_types from 'class-variance-authority/types';
6
6
  import * as ToastPrimitives from '@radix-ui/react-toast';
7
7
  import { VariantProps } from 'class-variance-authority';
@@ -23,6 +23,7 @@ interface AIQuestionGeneratorModalProps {
23
23
  topics?: Topic[];
24
24
  gradeLevels?: GradeLevel[];
25
25
  bloomLevels?: BloomLevelType[];
26
+ categories?: Category[];
26
27
  }
27
28
  declare const AIQuestionGeneratorModal: React__default.FC<AIQuestionGeneratorModalProps>;
28
29
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thanh01.pmt/interactive-quiz-kit",
3
- "version": "1.0.73",
3
+ "version": "1.0.74",
4
4
  "description": "A comprehensive library for creating, managing, and playing interactive quizzes, with AI generation and SCORM support.",
5
5
  "keywords": [
6
6
  "react",