@tinyweb_dev/oe-exam-sdk 0.1.1 → 0.1.3

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.
Files changed (514) hide show
  1. package/dist/api/exam-create.js +1 -179
  2. package/dist/api/exam-create.types.js +1 -1
  3. package/dist/api/exam-questions.d.ts +1 -1
  4. package/dist/api/exam-questions.js +1 -98
  5. package/dist/api/exam-questions.types.d.ts +45 -1
  6. package/dist/api/exam-questions.types.js +1 -1
  7. package/dist/api/exam-taking.js +1 -73
  8. package/dist/api/exam-taking.types.js +1 -1
  9. package/dist/api/index.js +1 -6
  10. package/dist/api/result-review.js +1 -50
  11. package/dist/api/result-review.types.js +1 -1
  12. package/dist/components/CueCardEditor.js +1 -58
  13. package/dist/components/common/ResolvedImage.js +1 -15
  14. package/dist/components/exams/CompletionDialog.d.ts +8 -0
  15. package/dist/components/exams/CompletionDialog.js +1 -0
  16. package/dist/components/exams/CreateExamInfoForm.d.ts +4 -1
  17. package/dist/components/exams/CreateExamInfoForm.js +1 -35
  18. package/dist/components/exams/CreateExamPageContainer.d.ts +3 -0
  19. package/dist/components/exams/CreateExamPageContainer.js +1 -103
  20. package/dist/components/exams/ExamCreator.d.ts +9 -3
  21. package/dist/components/exams/ExamCreator.js +1 -89
  22. package/dist/components/exams/ExamPartTabs.d.ts +1 -1
  23. package/dist/components/exams/ExamPartTabs.js +1 -40
  24. package/dist/components/exams/ExamPreviewDialog.d.ts +20 -0
  25. package/dist/components/exams/ExamPreviewDialog.js +1 -0
  26. package/dist/components/exams/ExamQuestionGrid.d.ts +1 -1
  27. package/dist/components/exams/ExamQuestionGrid.js +1 -18
  28. package/dist/components/exams/ExamQuestionsPageContainer.d.ts +3 -0
  29. package/dist/components/exams/ExamQuestionsPageContainer.js +1 -90
  30. package/dist/components/exams/ExamViewDialog.d.ts +24 -0
  31. package/dist/components/exams/ExamViewDialog.js +1 -0
  32. package/dist/components/exams/PartAudioUploader.js +1 -9
  33. package/dist/components/exams/TemplateSelector.js +1 -66
  34. package/dist/components/exams/UnsavedChangesDialog.d.ts +8 -0
  35. package/dist/components/exams/UnsavedChangesDialog.js +1 -0
  36. package/dist/components/exams/api.d.ts +1 -1
  37. package/dist/components/exams/api.js +1 -3
  38. package/dist/components/exams/create-exam.texts.d.ts +58 -0
  39. package/dist/components/exams/create-exam.texts.js +1 -0
  40. package/dist/components/exams/create-exam.validation.js +1 -18
  41. package/dist/components/exams/exam-question-status.d.ts +9 -0
  42. package/dist/components/exams/exam-question-status.js +1 -0
  43. package/dist/components/exams/exam-template.utils.js +1 -18
  44. package/dist/components/exams/index.d.ts +11 -1
  45. package/dist/components/exams/index.js +1 -10
  46. package/dist/components/exams/take/ExamTakingPageContainer.js +1 -153
  47. package/dist/components/exams/take/GenericQuestionRenderer.js +1 -14
  48. package/dist/components/exams/take/exam-taking.utils.js +1 -88
  49. package/dist/components/exams/take/hooks/useSpeakingRecorder.js +1 -24
  50. package/dist/components/exams/take/index.js +1 -2
  51. package/dist/components/exams/take/types.js +1 -1
  52. package/dist/components/index.js +1 -42
  53. package/dist/components/questions/_shared/config/question-types.config.js +1 -333
  54. package/dist/components/questions/_shared/constants/color-palette.js +1 -21
  55. package/dist/components/questions/_shared/hooks/useAnswerGroupQuestionGroup.js +1 -105
  56. package/dist/components/questions/_shared/hooks/useBasicQuestionGroup.js +1 -222
  57. package/dist/components/questions/_shared/hooks/useCompareImagesGroup.js +1 -140
  58. package/dist/components/questions/_shared/hooks/useImageQuestionGroup.js +1 -123
  59. package/dist/components/questions/_shared/hooks/useInfoExchangeGroup.js +1 -50
  60. package/dist/components/questions/_shared/hooks/useQuestionFormState.js +1 -54
  61. package/dist/components/questions/_shared/hooks/useQuestionInitialization.js +1 -123
  62. package/dist/components/questions/_shared/hooks/useQuestionListGroup.js +1 -121
  63. package/dist/components/questions/_shared/hooks/useQuestionOnChange.js +1 -70
  64. package/dist/components/questions/_shared/hooks/useSceneQuestionGroup.js +1 -194
  65. package/dist/components/questions/_shared/index.js +1 -7
  66. package/dist/components/questions/_shared/types/answer-the-question.type.js +1 -1
  67. package/dist/components/questions/_shared/types/arrange-letters-into-words.type.js +1 -1
  68. package/dist/components/questions/_shared/types/choose-correct-adjective.type.js +1 -3
  69. package/dist/components/questions/_shared/types/color-region.config.js +1 -1
  70. package/dist/components/questions/_shared/types/fill-in-blank.type.js +1 -1
  71. package/dist/components/questions/_shared/types/fill-missing-words-in-grid.type.js +1 -1
  72. package/dist/components/questions/_shared/types/gn-speaking-interview.type.js +1 -1
  73. package/dist/components/questions/_shared/types/index.js +1 -12
  74. package/dist/components/questions/_shared/types/label-the-picture.type.js +1 -1
  75. package/dist/components/questions/_shared/types/listen-and-choose-from-answer-group.type.js +1 -1
  76. package/dist/components/questions/_shared/types/listen-and-choose-objects-in-scene.type.js +1 -1
  77. package/dist/components/questions/_shared/types/listen-and-drag-objects-into-scene.type.js +1 -1
  78. package/dist/components/questions/_shared/types/listen-and-speak-answer.type.js +1 -1
  79. package/dist/components/questions/_shared/types/listen-and-speak-compare-images.type.js +1 -1
  80. package/dist/components/questions/_shared/types/listen-and-speak-image-group.type.js +1 -1
  81. package/dist/components/questions/_shared/types/listen-and-speak-info-exchange.type.js +1 -1
  82. package/dist/components/questions/_shared/types/listen-and-speak-odd-one-out.type.js +1 -3
  83. package/dist/components/questions/_shared/types/listen-and-speak-question-list.type.js +1 -1
  84. package/dist/components/questions/_shared/types/listen-and-speak-with-story-images.type.js +1 -3
  85. package/dist/components/questions/_shared/types/listen-and-tick-answer.type.js +1 -1
  86. package/dist/components/questions/_shared/types/listening-drawline.type.js +1 -1
  87. package/dist/components/questions/_shared/types/look-and-choose-answer.type.js +1 -1
  88. package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.js +1 -1
  89. package/dist/components/questions/_shared/types/match-by-writing-answer.type.js +1 -1
  90. package/dist/components/questions/_shared/types/multiple-choice.type.js +1 -1
  91. package/dist/components/questions/_shared/types/question-group.type.js +1 -11
  92. package/dist/components/questions/_shared/types/read-and-color-objects.type.js +1 -1
  93. package/dist/components/questions/_shared/types/read-displayed-content.type.js +1 -1
  94. package/dist/components/questions/_shared/types/read-passage-and-answer-questions.type.js +1 -1
  95. package/dist/components/questions/_shared/types/speaking-describe-image.type.js +1 -1
  96. package/dist/components/questions/_shared/types/spontaneous-qa.type.js +1 -1
  97. package/dist/components/questions/_shared/types/word-fill-paragraph-with-options.type.js +1 -1
  98. package/dist/components/questions/_shared/types/word-fill-paragraph.type.js +1 -1
  99. package/dist/components/questions/_shared/types/word-fill-structured-form.type.js +1 -1
  100. package/dist/components/questions/_shared/types/word-ordering.type.js +1 -1
  101. package/dist/components/questions/_shared/types/write-a-short-letter.type.js +1 -1
  102. package/dist/components/questions/_shared/types/write-correct-verb-form.type.js +1 -3
  103. package/dist/components/questions/_shared/types/write-sentences.type.js +1 -1
  104. package/dist/components/questions/_shared/types/write-short-paragraph.type.js +1 -1
  105. package/dist/components/questions/_shared/utils/answer-builder.js +1 -79
  106. package/dist/components/questions/_shared/utils/createColorRegionRegistration.js +1 -39
  107. package/dist/components/questions/_shared/utils/id-generator.js +1 -3
  108. package/dist/components/questions/_shared/utils/question-validation.js +1 -21
  109. package/dist/components/questions/components/ColorNode.js +1 -85
  110. package/dist/components/questions/components/ColorRegionClient.js +1 -545
  111. package/dist/components/questions/components/ColorRegionCreator.js +1 -420
  112. package/dist/components/questions/components/ColorRegionNode.js +1 -59
  113. package/dist/components/questions/components/CreatorGuide.js +1 -103
  114. package/dist/components/questions/components/NameNode.js +1 -26
  115. package/dist/components/questions/components/QuestionBankOption.js +1 -46
  116. package/dist/components/questions/components/QuestionBasicInfoForm.js +1 -9
  117. package/dist/components/questions/components/QuestionCommonFields.js +1 -33
  118. package/dist/components/questions/components/QuestionSearchDropdown.js +1 -258
  119. package/dist/components/questions/components/QuestionTypeSelector.js +1 -32
  120. package/dist/components/questions/components/QuestionTypeSpecificForms.js +1 -6
  121. package/dist/components/questions/components/RegionNode.js +1 -94
  122. package/dist/components/questions/components/index.js +1 -14
  123. package/dist/components/questions/creator/QuestionCreator.js +1 -90
  124. package/dist/components/questions/creator/QuestionGroupCreator.js +1 -119
  125. package/dist/components/questions/creator/dedicated-component-router.js +1 -79
  126. package/dist/components/questions/creator/index.js +1 -3
  127. package/dist/components/questions/creator/question-type-registry.js +1 -80
  128. package/dist/components/questions/groups/ArticlesGroupCard.js +1 -121
  129. package/dist/components/questions/groups/BasicQuestionGroupCard.js +1 -50
  130. package/dist/components/questions/groups/DocumentGroupCard.js +1 -114
  131. package/dist/components/questions/groups/MatchAnswerGroupCard.js +1 -25
  132. package/dist/components/questions/index.js +1 -10
  133. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +1 -37
  134. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionCreator.js +1 -351
  135. package/dist/components/questions/types/answer-the-question/register.js +1 -67
  136. package/dist/components/questions/types/answer-the-question/transform.js +1 -36
  137. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +1 -141
  138. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsCreator.js +1 -118
  139. package/dist/components/questions/types/arrange-letters-into-words/index.js +1 -2
  140. package/dist/components/questions/types/arrange-letters-into-words/register.js +1 -4
  141. package/dist/components/questions/types/arrange-letters-into-words/transform.js +1 -24
  142. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +1 -64
  143. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js +1 -169
  144. package/dist/components/questions/types/choose-correct-adjective/index.js +1 -2
  145. package/dist/components/questions/types/choose-correct-adjective/register.js +1 -55
  146. package/dist/components/questions/types/choose-correct-adjective/transform.js +1 -16
  147. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +1 -131
  148. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +1 -581
  149. package/dist/components/questions/types/choose-the-correct-answer/index.js +1 -2
  150. package/dist/components/questions/types/choose-the-correct-answer/register.js +1 -101
  151. package/dist/components/questions/types/choose-the-correct-answer/transform.js +1 -43
  152. package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +1 -275
  153. package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +1 -448
  154. package/dist/components/questions/types/fill-in-blank/index.js +1 -2
  155. package/dist/components/questions/types/fill-in-blank/register.js +1 -138
  156. package/dist/components/questions/types/fill-in-blank/transform.js +1 -59
  157. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +1 -117
  158. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridCreator.js +1 -671
  159. package/dist/components/questions/types/fill-missing-words-in-grid/index.js +1 -2
  160. package/dist/components/questions/types/fill-missing-words-in-grid/register.js +1 -37
  161. package/dist/components/questions/types/fill-missing-words-in-grid/transform.js +1 -15
  162. package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.js +1 -262
  163. package/dist/components/questions/types/gn-speaking-interview/register.js +1 -121
  164. package/dist/components/questions/types/gn-speaking-interview/transform.js +1 -48
  165. package/dist/components/questions/types/image-object-matching/ImageObjectMatchingClient.js +1 -16
  166. package/dist/components/questions/types/image-object-matching/ImageObjectMatchingCreator.js +1 -27
  167. package/dist/components/questions/types/image-object-matching/index.js +1 -2
  168. package/dist/components/questions/types/image-object-matching/register.js +1 -3
  169. package/dist/components/questions/types/image-object-matching/transform.js +1 -2
  170. package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +1 -102
  171. package/dist/components/questions/types/label-the-picture/LabelThePictureCreator.js +1 -344
  172. package/dist/components/questions/types/label-the-picture/index.js +1 -2
  173. package/dist/components/questions/types/label-the-picture/register.js +1 -54
  174. package/dist/components/questions/types/label-the-picture/transform.js +1 -28
  175. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +1 -78
  176. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupCreator.js +1 -232
  177. package/dist/components/questions/types/listen-and-choose-from-answer-group/index.js +1 -2
  178. package/dist/components/questions/types/listen-and-choose-from-answer-group/register.js +1 -82
  179. package/dist/components/questions/types/listen-and-choose-from-answer-group/transform.js +1 -27
  180. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneClient.js +1 -70
  181. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneCreator.js +1 -386
  182. package/dist/components/questions/types/listen-and-choose-objects-in-scene/index.js +1 -2
  183. package/dist/components/questions/types/listen-and-choose-objects-in-scene/register.js +1 -100
  184. package/dist/components/questions/types/listen-and-choose-objects-in-scene/transform.js +1 -33
  185. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneClient.js +1 -106
  186. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneCreator.js +1 -457
  187. package/dist/components/questions/types/listen-and-drag-objects-into-scene/index.js +1 -2
  188. package/dist/components/questions/types/listen-and-drag-objects-into-scene/register.js +1 -110
  189. package/dist/components/questions/types/listen-and-drag-objects-into-scene/transform.js +1 -35
  190. package/dist/components/questions/types/listen-and-speak-answer/ArrowIndicator.js +1 -8
  191. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +1 -22
  192. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerCreator.js +1 -291
  193. package/dist/components/questions/types/listen-and-speak-answer/index.js +1 -2
  194. package/dist/components/questions/types/listen-and-speak-answer/register.js +1 -84
  195. package/dist/components/questions/types/listen-and-speak-answer/transform.js +1 -27
  196. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +1 -32
  197. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesCreator.js +1 -295
  198. package/dist/components/questions/types/listen-and-speak-compare-images/register.js +1 -79
  199. package/dist/components/questions/types/listen-and-speak-compare-images/transform.js +1 -27
  200. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +1 -34
  201. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupCreator.js +1 -285
  202. package/dist/components/questions/types/listen-and-speak-image-group/register.js +1 -81
  203. package/dist/components/questions/types/listen-and-speak-image-group/transform.js +1 -26
  204. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +1 -38
  205. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeCreator.js +1 -385
  206. package/dist/components/questions/types/listen-and-speak-info-exchange/register.js +1 -87
  207. package/dist/components/questions/types/listen-and-speak-info-exchange/transform.js +1 -32
  208. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +1 -26
  209. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutCreator.js +1 -247
  210. package/dist/components/questions/types/listen-and-speak-odd-one-out/register.js +1 -59
  211. package/dist/components/questions/types/listen-and-speak-odd-one-out/transform.js +1 -18
  212. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +1 -26
  213. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListCreator.js +1 -256
  214. package/dist/components/questions/types/listen-and-speak-question-list/register.js +1 -81
  215. package/dist/components/questions/types/listen-and-speak-question-list/transform.js +1 -26
  216. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +1 -26
  217. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesCreator.js +1 -230
  218. package/dist/components/questions/types/listen-and-speak-with-story-images/register.js +1 -56
  219. package/dist/components/questions/types/listen-and-speak-with-story-images/transform.js +1 -16
  220. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.js +1 -72
  221. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.js +1 -230
  222. package/dist/components/questions/types/look-picture-choose-correct-answer/index.js +1 -1
  223. package/dist/components/questions/types/look-picture-choose-correct-answer/register.js +1 -66
  224. package/dist/components/questions/types/look-picture-choose-correct-answer/transform.js +1 -42
  225. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.js +1 -96
  226. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.js +1 -238
  227. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.js +1 -2
  228. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.js +1 -76
  229. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.js +1 -19
  230. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.js +1 -134
  231. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.js +1 -617
  232. package/dist/components/questions/types/look-picture-fill-word-hint/index.js +1 -2
  233. package/dist/components/questions/types/look-picture-fill-word-hint/register.js +1 -82
  234. package/dist/components/questions/types/look-picture-fill-word-hint/transform.js +1 -29
  235. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +1 -38
  236. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerCreator.js +1 -359
  237. package/dist/components/questions/types/match-by-writing-answer/index.js +1 -3
  238. package/dist/components/questions/types/match-by-writing-answer/register.js +1 -58
  239. package/dist/components/questions/types/match-by-writing-answer/transform.js +1 -61
  240. package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsClient.js +1 -16
  241. package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsCreator.js +1 -23
  242. package/dist/components/questions/types/read-and-color-objects/index.js +1 -2
  243. package/dist/components/questions/types/read-and-color-objects/register.js +1 -3
  244. package/dist/components/questions/types/read-and-color-objects/transform.js +1 -36
  245. package/dist/components/questions/types/read-displayed-content/ReadDisplayedContentCreator.js +1 -125
  246. package/dist/components/questions/types/read-displayed-content/register.js +1 -64
  247. package/dist/components/questions/types/read-displayed-content/transform.js +1 -12
  248. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +1 -64
  249. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsCreator.js +1 -511
  250. package/dist/components/questions/types/read-passage-and-answer-questions/index.js +1 -2
  251. package/dist/components/questions/types/read-passage-and-answer-questions/register.js +1 -58
  252. package/dist/components/questions/types/read-passage-and-answer-questions/transform.js +1 -28
  253. package/dist/components/questions/types/speaking-conversation/SpeakingConversationCreator.js +1 -373
  254. package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +1 -41
  255. package/dist/components/questions/types/speaking-conversation/register.js +1 -110
  256. package/dist/components/questions/types/speaking-conversation/transform.js +1 -34
  257. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +1 -74
  258. package/dist/components/questions/types/speaking-cue-card/register.js +1 -52
  259. package/dist/components/questions/types/speaking-cue-card/transform.js +1 -12
  260. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +1 -10
  261. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageCreator.js +1 -161
  262. package/dist/components/questions/types/speaking-describe-image/index.js +1 -2
  263. package/dist/components/questions/types/speaking-describe-image/register.js +1 -69
  264. package/dist/components/questions/types/speaking-describe-image/transform.js +1 -16
  265. package/dist/components/questions/types/spontaneous-qa/SpontaneousQACreator.js +1 -234
  266. package/dist/components/questions/types/spontaneous-qa/register.js +1 -93
  267. package/dist/components/questions/types/spontaneous-qa/transform.js +1 -34
  268. package/dist/components/questions/types/true-false/TrueFalseClient.js +1 -75
  269. package/dist/components/questions/types/true-false/TrueFalseCreator.js +1 -244
  270. package/dist/components/questions/types/true-false/index.js +1 -2
  271. package/dist/components/questions/types/true-false/register.js +1 -77
  272. package/dist/components/questions/types/true-false/transform.js +1 -32
  273. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +1 -233
  274. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphCreator.js +1 -631
  275. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphWrapper.js +1 -28
  276. package/dist/components/questions/types/word-fill-paragraph/index.js +1 -2
  277. package/dist/components/questions/types/word-fill-paragraph/register.js +1 -136
  278. package/dist/components/questions/types/word-fill-paragraph/transform.js +1 -56
  279. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -138
  280. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +1 -261
  281. package/dist/components/questions/types/word-fill-structured-form/index.js +1 -2
  282. package/dist/components/questions/types/word-fill-structured-form/register.js +1 -67
  283. package/dist/components/questions/types/word-fill-structured-form/transform.js +1 -40
  284. package/dist/components/questions/types/word-ordering/WordOrderingClient.js +1 -84
  285. package/dist/components/questions/types/word-ordering/WordOrderingCreator.js +1 -192
  286. package/dist/components/questions/types/word-ordering/index.js +1 -2
  287. package/dist/components/questions/types/word-ordering/register.js +1 -46
  288. package/dist/components/questions/types/word-ordering/transform.js +1 -24
  289. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +1 -98
  290. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +1 -320
  291. package/dist/components/questions/types/write-a-short-letter/index.js +1 -2
  292. package/dist/components/questions/types/write-a-short-letter/register.js +1 -68
  293. package/dist/components/questions/types/write-a-short-letter/transform.js +1 -25
  294. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +1 -61
  295. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js +1 -196
  296. package/dist/components/questions/types/write-correct-verb-form/index.js +1 -2
  297. package/dist/components/questions/types/write-correct-verb-form/register.js +1 -62
  298. package/dist/components/questions/types/write-correct-verb-form/transform.js +1 -17
  299. package/dist/components/questions/types/write-sentences/WriteSentencesClient.js +1 -22
  300. package/dist/components/questions/types/write-sentences/WriteSentencesCreator.js +1 -174
  301. package/dist/components/questions/types/write-sentences/index.js +1 -2
  302. package/dist/components/questions/types/write-sentences/register.js +1 -58
  303. package/dist/components/questions/types/write-sentences/transform.js +1 -28
  304. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphClient.js +1 -96
  305. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphCreator.js +1 -161
  306. package/dist/components/questions/types/write-short-paragraph/index.js +1 -2
  307. package/dist/components/questions/types/write-short-paragraph/register.js +1 -4
  308. package/dist/components/questions/types/write-short-paragraph/transform.js +1 -21
  309. package/dist/components/questions/viewer/QuestionGroupViewer.js +1 -36
  310. package/dist/components/questions/viewer/QuestionViewer.js +1 -446
  311. package/dist/components/questions/viewer/index.js +1 -2
  312. package/dist/components/results/ResultReviewPageContainer.js +1 -98
  313. package/dist/components/results/ReviewQuestionRenderer.js +1 -72
  314. package/dist/components/results/index.js +1 -2
  315. package/dist/components/results/result-review.utils.js +1 -6
  316. package/dist/components/results/review-data.js +1 -150
  317. package/dist/components/results/review-renderer.utils.js +1 -97
  318. package/dist/components/results/review-types.js +1 -1
  319. package/dist/components/themes/cambridge-yle/CambridgeYleAudioPlayer.js +1 -138
  320. package/dist/components/themes/cambridge-yle/CambridgeYleBottomNav.js +1 -12
  321. package/dist/components/themes/cambridge-yle/CambridgeYleExamLayout.js +1 -18
  322. package/dist/components/themes/cambridge-yle/CambridgeYleExampleText.js +1 -11
  323. package/dist/components/themes/cambridge-yle/CambridgeYleHeader.js +1 -11
  324. package/dist/components/themes/cambridge-yle/CambridgeYleInstructionBanner.js +1 -9
  325. package/dist/components/themes/cambridge-yle/CambridgeYleNavButton.js +1 -13
  326. package/dist/components/themes/cambridge-yle/CambridgeYlePartBanner.js +1 -8
  327. package/dist/components/themes/cambridge-yle/CambridgeYleProgressBar.js +1 -6
  328. package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCard.js +1 -5
  329. package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCardFullWidth.js +1 -9
  330. package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.js +1 -41
  331. package/dist/components/themes/cambridge-yle/CambridgeYleTimer.js +1 -25
  332. package/dist/components/themes/cambridge-yle/index.js +1 -13
  333. package/dist/components/themes/english-certification/EcAnswerTheQuestion.js +1 -24
  334. package/dist/components/themes/english-certification/EcMatchByWritingAnswer.js +1 -88
  335. package/dist/components/themes/english-certification/EcWordFillParagraph.js +1 -55
  336. package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -156
  337. package/dist/components/themes/english-certification/EcWritingTask.js +1 -34
  338. package/dist/components/themes/english-certification/EnglishCertificationAudioPlayer.js +1 -114
  339. package/dist/components/themes/english-certification/EnglishCertificationBrand.js +1 -11
  340. package/dist/components/themes/english-certification/EnglishCertificationExamLayout.js +1 -21
  341. package/dist/components/themes/english-certification/EnglishCertificationFlagButton.js +1 -15
  342. package/dist/components/themes/english-certification/EnglishCertificationFooterBar.js +1 -19
  343. package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.js +1 -148
  344. package/dist/components/themes/english-certification/EnglishCertificationHeader.js +1 -31
  345. package/dist/components/themes/english-certification/EnglishCertificationNavigationPanel.js +1 -71
  346. package/dist/components/themes/english-certification/EnglishCertificationOptionSelector.js +1 -33
  347. package/dist/components/themes/english-certification/EnglishCertificationPassagePanel.js +1 -16
  348. package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.js +1 -22
  349. package/dist/components/themes/english-certification/EnglishCertificationQuestionItem.js +1 -37
  350. package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -72
  351. package/dist/components/themes/english-certification/EnglishCertificationReadingSection.js +1 -90
  352. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestion.js +1 -18
  353. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js +1 -29
  354. package/dist/components/themes/english-certification/english-certification-theme.js +1 -58
  355. package/dist/components/themes/english-certification/grouped-question-utils.js +1 -218
  356. package/dist/components/themes/english-certification/index.js +1 -21
  357. package/dist/components/themes/index.js +1 -6
  358. package/dist/components/themes/summer-sky/SummerSkyAudioPlayer.js +1 -170
  359. package/dist/components/themes/summer-sky/SummerSkyLayout.js +1 -221
  360. package/dist/components/themes/summer-sky/SummerSkySubmitModal.js +1 -18
  361. package/dist/components/themes/summer-sky/SummerSkyWaitingRoom.js +1 -194
  362. package/dist/components/themes/types.js +1 -1
  363. package/dist/components/ui/alert-dialog.js +1 -26
  364. package/dist/components/ui/alert.js +1 -22
  365. package/dist/components/ui/avatar.js +1 -12
  366. package/dist/components/ui/badge.js +1 -38
  367. package/dist/components/ui/button.js +1 -35
  368. package/dist/components/ui/calendar.js +1 -76
  369. package/dist/components/ui/card.js +1 -16
  370. package/dist/components/ui/carousel.js +1 -91
  371. package/dist/components/ui/checkbox.js +1 -9
  372. package/dist/components/ui/collapsible.js +1 -13
  373. package/dist/components/ui/command.js +1 -34
  374. package/dist/components/ui/confirm-dialog.js +1 -49
  375. package/dist/components/ui/dialog.js +1 -23
  376. package/dist/components/ui/drawer.js +1 -35
  377. package/dist/components/ui/dropdown-menu.js +1 -33
  378. package/dist/components/ui/file-upload.js +1 -155
  379. package/dist/components/ui/form.js +1 -62
  380. package/dist/components/ui/hover-card.js +1 -10
  381. package/dist/components/ui/image-preview.js +1 -29
  382. package/dist/components/ui/input.js +1 -8
  383. package/dist/components/ui/label.js +1 -9
  384. package/dist/components/ui/language-switcher.js +1 -15
  385. package/dist/components/ui/multi-select.js +1 -90
  386. package/dist/components/ui/points-input.js +1 -33
  387. package/dist/components/ui/popover.js +1 -26
  388. package/dist/components/ui/progress.js +1 -16
  389. package/dist/components/ui/radio-group.js +1 -12
  390. package/dist/components/ui/scroll-area.js +1 -11
  391. package/dist/components/ui/select.js +1 -38
  392. package/dist/components/ui/separator.js +1 -8
  393. package/dist/components/ui/sheet.js +1 -40
  394. package/dist/components/ui/single-select.js +1 -76
  395. package/dist/components/ui/skeleton.js +1 -6
  396. package/dist/components/ui/switch.js +1 -8
  397. package/dist/components/ui/table.js +1 -20
  398. package/dist/components/ui/tabs.js +1 -17
  399. package/dist/components/ui/textarea.js +1 -8
  400. package/dist/components/ui/tooltip.js +1 -11
  401. package/dist/index.d.ts +3 -3
  402. package/dist/index.js +1 -19
  403. package/dist/mcp/config.js +1 -32
  404. package/dist/mcp/http-client.js +1 -48
  405. package/dist/mcp/index.js +1 -29
  406. package/dist/mcp/tools/_helpers.js +1 -25
  407. package/dist/mcp/tools/exams.js +1 -439
  408. package/dist/mcp/tools/index.js +1 -6
  409. package/dist/mcp/tools/results.js +1 -19
  410. package/dist/shared/constants/ApiConstant.js +1 -276
  411. package/dist/shared/constants/QueryKeyConstant.js +1 -112
  412. package/dist/shared/constants/exam-level.enum.js +1 -41
  413. package/dist/shared/constants/landings/placement-test.constants.js +1 -431
  414. package/dist/shared/constants/question-skills.js +1 -267
  415. package/dist/shared/constants/routes.js +1 -81
  416. package/dist/shared/index.d.ts +3 -0
  417. package/dist/shared/index.js +1 -7
  418. package/dist/shared/lib/hooks/index.js +1 -10
  419. package/dist/shared/lib/hooks/useAlertDialog.js +1 -57
  420. package/dist/shared/lib/hooks/useAudioPlayCounter.js +1 -30
  421. package/dist/shared/lib/hooks/useAudioPreview.js +1 -81
  422. package/dist/shared/lib/hooks/useAudioUpload.js +1 -24
  423. package/dist/shared/lib/hooks/useConfirmDialog.js +1 -89
  424. package/dist/shared/lib/hooks/useDebouncedCallback.js +1 -32
  425. package/dist/shared/lib/hooks/useDelayedAutoPlay.js +1 -12
  426. package/dist/shared/lib/hooks/useFileUpload.js +1 -24
  427. package/dist/shared/lib/hooks/useImageUrl.js +1 -5
  428. package/dist/shared/lib/hooks/usePresignedFileUrl.js +1 -10
  429. package/dist/shared/lib/hooks/useReactHookForm.js +1 -31
  430. package/dist/shared/lib/hooks/useToast.js +1 -62
  431. package/dist/shared/lib/i18n/index.js +1 -54
  432. package/dist/shared/lib/i18n/messages/en/admin.js +1 -2104
  433. package/dist/shared/lib/i18n/messages/en/auth.js +1 -86
  434. package/dist/shared/lib/i18n/messages/en/common.js +1 -140
  435. package/dist/shared/lib/i18n/messages/en/file-upload.js +1 -18
  436. package/dist/shared/lib/i18n/messages/en/student.js +1 -133
  437. package/dist/shared/lib/i18n/messages/en/terms.js +1 -37
  438. package/dist/shared/lib/i18n/messages/en.js +1 -15
  439. package/dist/shared/lib/i18n/messages/vi/admin.js +1 -2104
  440. package/dist/shared/lib/i18n/messages/vi/auth.js +1 -86
  441. package/dist/shared/lib/i18n/messages/vi/common.js +1 -140
  442. package/dist/shared/lib/i18n/messages/vi/file-upload.js +1 -18
  443. package/dist/shared/lib/i18n/messages/vi/student.js +1 -133
  444. package/dist/shared/lib/i18n/messages/vi/terms.js +1 -37
  445. package/dist/shared/lib/i18n/messages/vi.js +1 -15
  446. package/dist/shared/lib/i18n/types.js +1 -1
  447. package/dist/shared/lib/stores/examQuestionStore.js +1 -212
  448. package/dist/shared/lib/stores/localeStore.js +1 -10
  449. package/dist/shared/lib/utils/public-page.js +1 -44
  450. package/dist/shared/lib/utils/question-reverse-transform.d.ts +6 -0
  451. package/dist/shared/lib/utils/question-reverse-transform.js +1 -0
  452. package/dist/shared/lib/utils/question-transform-types.js +1 -1
  453. package/dist/shared/lib/utils/question-transform-validation.d.ts +6 -0
  454. package/dist/shared/lib/utils/question-transform-validation.js +1 -0
  455. package/dist/shared/lib/utils/question-transform.d.ts +6 -2
  456. package/dist/shared/lib/utils/question-transform.js +1 -174
  457. package/dist/shared/lib/utils.js +1 -168
  458. package/dist/shared/lib/validation/choose-correct-answer.validation.js +1 -111
  459. package/dist/shared/lib/validation/label-the-picture.validation.js +1 -19
  460. package/dist/shared/lib/validation/listen-and-choose-from-answer-group.validation.js +1 -46
  461. package/dist/shared/lib/validation/listen-and-choose-objects-in-scene.validation.js +1 -21
  462. package/dist/shared/lib/validation/listen-and-drag-objects-into-scene.validation.js +1 -34
  463. package/dist/shared/lib/validation/listen-and-speak-answer.validation.js +1 -40
  464. package/dist/shared/lib/validation/listen-and-speak-compare-images.validation.js +1 -45
  465. package/dist/shared/lib/validation/listen-and-speak-image-group.validation.js +1 -19
  466. package/dist/shared/lib/validation/listen-and-speak-info-exchange.validation.js +1 -39
  467. package/dist/shared/lib/validation/listen-and-speak-odd-one-out.validation.js +1 -32
  468. package/dist/shared/lib/validation/listen-and-speak-question-list.validation.js +1 -19
  469. package/dist/shared/lib/validation/listen-and-speak-with-story-images.validation.js +1 -28
  470. package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.js +1 -12
  471. package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.js +1 -47
  472. package/dist/shared/lib/validation/read-and-color-objects.validation.js +1 -29
  473. package/dist/shared/lib/validation/read-displayed-content.validation.js +1 -28
  474. package/dist/shared/lib/validation/speaking-conversation.validation.js +1 -75
  475. package/dist/shared/lib/validation/speaking-describe-image.validation.js +1 -31
  476. package/dist/shared/lib/validation/spontaneous-qa.validation.js +1 -48
  477. package/dist/shared/lib/validation/word-fill-paragraph-default.validation.js +1 -38
  478. package/dist/shared/lib/validation/word-fill-paragraph-with-options.validation.js +1 -39
  479. package/dist/shared/lib/validation/word-fill-paragraph.validation.js +1 -43
  480. package/dist/shared/lib/validation/word-ordering.validation.js +1 -33
  481. package/dist/shared/types/branch.types.js +1 -6
  482. package/dist/shared/types/common.types.js +1 -50
  483. package/dist/shared/types/entities/exam-schedule.types.js +1 -5
  484. package/dist/shared/types/entities/exam.types.js +1 -1
  485. package/dist/shared/types/entities/question.types.js +1 -4
  486. package/dist/shared/types/entities/result.types.js +1 -4
  487. package/dist/shared/types/entities/user.types.js +1 -4
  488. package/dist/shared/types/exam-taking.types.js +1 -2
  489. package/dist/shared/types/history.types.js +1 -34
  490. package/dist/shared/types/index.js +1 -1
  491. package/dist/shared/types/questions/choose-correct-adjective.js +1 -4
  492. package/dist/shared/types/questions/choose-the-correct-answer.js +1 -9
  493. package/dist/shared/types/questions/fill-missing-words-in-grid.js +1 -11
  494. package/dist/shared/types/questions/index.js +1 -40
  495. package/dist/shared/types/questions/listen-and-speak-answer.js +1 -1
  496. package/dist/shared/types/questions/listen-and-speak-compare-images.js +1 -1
  497. package/dist/shared/types/questions/listen-and-speak-image-group.js +1 -1
  498. package/dist/shared/types/questions/listen-and-speak-info-exchange.js +1 -3
  499. package/dist/shared/types/questions/listen-and-speak-odd-one-out.js +1 -3
  500. package/dist/shared/types/questions/listen-and-speak-question-list.js +1 -1
  501. package/dist/shared/types/questions/listen-and-speak-with-story-images.js +1 -3
  502. package/dist/shared/types/questions/look-picture-choose-correct-answer.js +1 -5
  503. package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.js +1 -9
  504. package/dist/shared/types/questions/look-picture-fill-word-hint.js +1 -7
  505. package/dist/shared/types/questions/read-displayed-content.js +1 -1
  506. package/dist/shared/types/questions/speaking-conversation.js +1 -7
  507. package/dist/shared/types/questions/speaking-describe-image.js +1 -1
  508. package/dist/shared/types/questions/spontaneous-qa.js +1 -1
  509. package/dist/shared/types/questions/write-correct-verb-form.js +1 -12
  510. package/dist/shared/types/role.types.js +1 -1
  511. package/dist/shared/types/structure-management.js +1 -28
  512. package/dist/shared/types/student.types.js +1 -54
  513. package/dist/shared/types/teacher-dashboard-rooms.js +1 -2
  514. package/package.json +12 -3
@@ -1,103 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState } from 'react';
4
- import { Lightbulb, ChevronDown } from 'lucide-react';
5
- import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '../../../components/ui/collapsible';
6
- import { cn } from '../../../shared/lib/utils';
7
- // ─── Color Scheme Map ─────────────────────────────────────────────────────────
8
- const colorSchemes = {
9
- blue: {
10
- border: 'border-blue-200',
11
- bg: 'bg-gradient-to-r from-blue-50 to-indigo-50',
12
- icon: 'bg-blue-100 text-blue-600',
13
- title: 'text-blue-800',
14
- dot: 'bg-blue-400',
15
- text: 'text-blue-700',
16
- tipBg: 'bg-blue-100/60',
17
- tipText: 'text-blue-700',
18
- hoverBg: 'hover:from-blue-100/80 hover:to-indigo-100/60',
19
- },
20
- purple: {
21
- border: 'border-purple-200',
22
- bg: 'bg-gradient-to-r from-purple-50 to-violet-50',
23
- icon: 'bg-purple-100 text-purple-600',
24
- title: 'text-purple-800',
25
- dot: 'bg-purple-400',
26
- text: 'text-purple-700',
27
- tipBg: 'bg-purple-100/60',
28
- tipText: 'text-purple-700',
29
- hoverBg: 'hover:from-purple-100/80 hover:to-violet-100/60',
30
- },
31
- emerald: {
32
- border: 'border-emerald-200',
33
- bg: 'bg-gradient-to-r from-emerald-50 to-teal-50',
34
- icon: 'bg-emerald-100 text-emerald-600',
35
- title: 'text-emerald-800',
36
- dot: 'bg-emerald-400',
37
- text: 'text-emerald-700',
38
- tipBg: 'bg-emerald-100/60',
39
- tipText: 'text-emerald-700',
40
- hoverBg: 'hover:from-emerald-100/80 hover:to-teal-100/60',
41
- },
42
- amber: {
43
- border: 'border-amber-200',
44
- bg: 'bg-gradient-to-r from-amber-50 to-orange-50',
45
- icon: 'bg-amber-100 text-amber-600',
46
- title: 'text-amber-800',
47
- dot: 'bg-amber-400',
48
- text: 'text-amber-700',
49
- tipBg: 'bg-amber-100/60',
50
- tipText: 'text-amber-700',
51
- hoverBg: 'hover:from-amber-100/80 hover:to-orange-100/60',
52
- },
53
- cyan: {
54
- border: 'border-cyan-200',
55
- bg: 'bg-gradient-to-r from-cyan-50 to-sky-50',
56
- icon: 'bg-cyan-100 text-cyan-600',
57
- title: 'text-cyan-800',
58
- dot: 'bg-cyan-400',
59
- text: 'text-cyan-700',
60
- tipBg: 'bg-cyan-100/60',
61
- tipText: 'text-cyan-700',
62
- hoverBg: 'hover:from-cyan-100/80 hover:to-sky-100/60',
63
- },
64
- rose: {
65
- border: 'border-rose-200',
66
- bg: 'bg-gradient-to-r from-rose-50 to-pink-50',
67
- icon: 'bg-rose-100 text-rose-600',
68
- title: 'text-rose-800',
69
- dot: 'bg-rose-400',
70
- text: 'text-rose-700',
71
- tipBg: 'bg-rose-100/60',
72
- tipText: 'text-rose-700',
73
- hoverBg: 'hover:from-rose-100/80 hover:to-pink-100/60',
74
- },
75
- teal: {
76
- border: 'border-teal-200',
77
- bg: 'bg-gradient-to-r from-teal-50 to-emerald-50',
78
- icon: 'bg-teal-100 text-teal-600',
79
- title: 'text-teal-800',
80
- dot: 'bg-teal-400',
81
- text: 'text-teal-700',
82
- tipBg: 'bg-teal-100/60',
83
- tipText: 'text-teal-700',
84
- hoverBg: 'hover:from-teal-100/80 hover:to-emerald-100/60',
85
- },
86
- orange: {
87
- border: 'border-orange-200',
88
- bg: 'bg-gradient-to-r from-orange-50 to-amber-50',
89
- icon: 'bg-orange-100 text-orange-600',
90
- title: 'text-orange-800',
91
- dot: 'bg-orange-400',
92
- text: 'text-orange-700',
93
- tipBg: 'bg-orange-100/60',
94
- tipText: 'text-orange-700',
95
- hoverBg: 'hover:from-orange-100/80 hover:to-amber-100/60',
96
- },
97
- };
98
- // ─── Component ────────────────────────────────────────────────────────────────
99
- export function CreatorGuide({ steps, tips = [], colorScheme = 'blue' }) {
100
- const [isOpen, setIsOpen] = useState(false);
101
- const colors = colorSchemes[colorScheme];
102
- return (_jsx(Collapsible, { open: isOpen, onOpenChange: setIsOpen, children: _jsxs("div", { className: cn('rounded-xl border shadow-sm overflow-hidden', colors.border, colors.bg), children: [_jsx(CollapsibleTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: cn('flex w-full items-center gap-3 px-5 py-3.5 transition-colors cursor-pointer', colors.bg, colors.hoverBg), children: [_jsx("div", { className: cn('flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg', colors.icon), children: _jsx(Lightbulb, { className: "h-4 w-4" }) }), _jsx("span", { className: cn('text-sm font-semibold flex-1 text-left', colors.title), children: "H\u01B0\u1EDBng d\u1EABn t\u1EA1o c\u00E2u h\u1ECFi" }), _jsx(ChevronDown, { className: cn('h-4 w-4 transition-transform duration-200', colors.text, isOpen && 'rotate-180') })] }) }), _jsx(CollapsibleContent, { children: _jsx("div", { className: "px-5 pb-4 pt-0", children: _jsxs("div", { className: "ml-11 space-y-1.5", children: [steps.map((step, index) => (_jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("span", { className: cn('mt-1.5 h-1.5 w-1.5 flex-shrink-0 rounded-full', colors.dot) }), _jsx("span", { className: cn('text-sm leading-relaxed', colors.text, step.highlight && 'font-semibold'), children: step.text })] }, index))), tips.length > 0 && (_jsx("div", { className: cn('mt-3 rounded-lg px-3 py-2', colors.tipBg), children: tips.map((tip, index) => (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("span", { className: "text-sm", children: "\uD83D\uDCA1" }), _jsxs("span", { className: cn('text-sm font-medium', colors.tipText), children: [_jsx("strong", { children: "M\u1EB9o:" }), " ", tip] })] }, index))) }))] }) }) })] }) }));
103
- }
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as r}from"react";import{Lightbulb as o,ChevronDown as a}from"lucide-react";import{Collapsible as l,CollapsibleTrigger as i,CollapsibleContent as n}from"../../../components/ui/collapsible";import{cn as d}from"../../../shared/lib/utils";const g={blue:{border:"border-blue-200",bg:"bg-gradient-to-r from-blue-50 to-indigo-50",icon:"bg-blue-100 text-blue-600",title:"text-blue-800",dot:"bg-blue-400",text:"text-blue-700",tipBg:"bg-blue-100/60",tipText:"text-blue-700",hoverBg:"hover:from-blue-100/80 hover:to-indigo-100/60"},purple:{border:"border-purple-200",bg:"bg-gradient-to-r from-purple-50 to-violet-50",icon:"bg-purple-100 text-purple-600",title:"text-purple-800",dot:"bg-purple-400",text:"text-purple-700",tipBg:"bg-purple-100/60",tipText:"text-purple-700",hoverBg:"hover:from-purple-100/80 hover:to-violet-100/60"},emerald:{border:"border-emerald-200",bg:"bg-gradient-to-r from-emerald-50 to-teal-50",icon:"bg-emerald-100 text-emerald-600",title:"text-emerald-800",dot:"bg-emerald-400",text:"text-emerald-700",tipBg:"bg-emerald-100/60",tipText:"text-emerald-700",hoverBg:"hover:from-emerald-100/80 hover:to-teal-100/60"},amber:{border:"border-amber-200",bg:"bg-gradient-to-r from-amber-50 to-orange-50",icon:"bg-amber-100 text-amber-600",title:"text-amber-800",dot:"bg-amber-400",text:"text-amber-700",tipBg:"bg-amber-100/60",tipText:"text-amber-700",hoverBg:"hover:from-amber-100/80 hover:to-orange-100/60"},cyan:{border:"border-cyan-200",bg:"bg-gradient-to-r from-cyan-50 to-sky-50",icon:"bg-cyan-100 text-cyan-600",title:"text-cyan-800",dot:"bg-cyan-400",text:"text-cyan-700",tipBg:"bg-cyan-100/60",tipText:"text-cyan-700",hoverBg:"hover:from-cyan-100/80 hover:to-sky-100/60"},rose:{border:"border-rose-200",bg:"bg-gradient-to-r from-rose-50 to-pink-50",icon:"bg-rose-100 text-rose-600",title:"text-rose-800",dot:"bg-rose-400",text:"text-rose-700",tipBg:"bg-rose-100/60",tipText:"text-rose-700",hoverBg:"hover:from-rose-100/80 hover:to-pink-100/60"},teal:{border:"border-teal-200",bg:"bg-gradient-to-r from-teal-50 to-emerald-50",icon:"bg-teal-100 text-teal-600",title:"text-teal-800",dot:"bg-teal-400",text:"text-teal-700",tipBg:"bg-teal-100/60",tipText:"text-teal-700",hoverBg:"hover:from-teal-100/80 hover:to-emerald-100/60"},orange:{border:"border-orange-200",bg:"bg-gradient-to-r from-orange-50 to-amber-50",icon:"bg-orange-100 text-orange-600",title:"text-orange-800",dot:"bg-orange-400",text:"text-orange-700",tipBg:"bg-orange-100/60",tipText:"text-orange-700",hoverBg:"hover:from-orange-100/80 hover:to-amber-100/60"}};export function CreatorGuide({steps:b,tips:m=[],colorScheme:s="blue"}){const[p,x]=r(!1),c=g[s];return e(l,{open:p,onOpenChange:x,children:t("div",{className:d("rounded-xl border shadow-sm overflow-hidden",c.border,c.bg),children:[e(i,{asChild:!0,children:t("button",{type:"button",className:d("flex w-full items-center gap-3 px-5 py-3.5 transition-colors cursor-pointer",c.bg,c.hoverBg),children:[e("div",{className:d("flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg",c.icon),children:e(o,{className:"h-4 w-4"})}),e("span",{className:d("text-sm font-semibold flex-1 text-left",c.title),children:"Hướng dẫn tạo câu hỏi"}),e(a,{className:d("h-4 w-4 transition-transform duration-200",c.text,p&&"rotate-180")})]})}),e(n,{children:e("div",{className:"px-5 pb-4 pt-0",children:t("div",{className:"ml-11 space-y-1.5",children:[b.map((r,o)=>t("div",{className:"flex items-start gap-2.5",children:[e("span",{className:d("mt-1.5 h-1.5 w-1.5 flex-shrink-0 rounded-full",c.dot)}),e("span",{className:d("text-sm leading-relaxed",c.text,r.highlight&&"font-semibold"),children:r.text})]},o)),m.length>0&&e("div",{className:d("mt-3 rounded-lg px-3 py-2",c.tipBg),children:m.map((r,o)=>t("div",{className:"flex items-start gap-2",children:[e("span",{className:"text-sm",children:"💡"}),t("span",{className:d("text-sm font-medium",c.tipText),children:[e("strong",{children:"Mẹo:"})," ",r]})]},o))})]})})})]})})}
@@ -1,26 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button } from '../../../components/ui/button';
3
- import { Badge } from '../../../components/ui/badge';
4
- import { X } from 'lucide-react';
5
- export function NameNode({ data, variant = 'creator' }) {
6
- const isClientMode = variant === 'client';
7
- const isCompact = data.displayMode === 'compact';
8
- const textClass = isCompact ? 'text-[11px]' : 'text-[13px]';
9
- if (isClientMode) {
10
- const baseClass = data.isConnected
11
- ? 'relative flex h-full w-full items-center justify-center overflow-hidden rounded-2xl bg-white transition-all duration-200 ease-out'
12
- : 'relative inline-flex min-w-[110px] items-center justify-center overflow-hidden rounded-2xl border border-gray-300 bg-white px-3 py-2 transition-all duration-200 ease-out hover:border-blue-400 cursor-move';
13
- return (_jsxs("div", { className: `${baseClass} ${data.highlightClass ?? ''}`, style: data.highlightStyle, children: [data.isHighlighted && (_jsx("div", { className: "pointer-events-none absolute inset-0 z-[1] rounded-2xl bg-black/40" })), _jsx("span", { className: `relative ${data.isHighlighted ? 'z-[2]' : 'z-[1]'} font-medium text-black ${textClass}`, children: data.name })] }));
14
- }
15
- const isConnectedCreator = data.isConnected;
16
- const baseClassesCreator = isCompact
17
- ? 'relative inline-flex min-w-[110px] items-center justify-between rounded-2xl border px-3 py-2 text-xs transition-all'
18
- : 'relative flex min-w-[180px] items-center justify-between rounded-2xl border-2 px-3 py-2 text-sm transition-all';
19
- const creatorClass = isConnectedCreator
20
- ? `${baseClassesCreator} border-green-500 bg-green-50 ring-2 ring-green-200`
21
- : `${baseClassesCreator} border-gray-200 bg-white hover:border-blue-300`;
22
- return (_jsxs("div", { className: creatorClass, children: [_jsx("span", { className: `font-medium text-gray-900 ${textClass}`, children: data.name }), _jsxs("div", { className: "flex items-center gap-2", children: [data.isConnected && (_jsx(Badge, { variant: "outline", className: "bg-green-50 text-xs text-green-700", children: "\u2713" })), data.isEditMode && (_jsx(Button, { size: "icon", variant: "ghost", className: "h-6 w-6", onClick: (e) => {
23
- e.stopPropagation();
24
- data.onRemove();
25
- }, children: _jsx(X, { className: "h-3 w-3" }) }))] })] }));
26
- }
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import{Button as i}from"../../../components/ui/button";import{Badge as n}from"../../../components/ui/badge";import{X as r}from"lucide-react";export function NameNode({data:o,variant:a="creator"}){const s="client"===a,l="compact"===o.displayMode,d=l?"text-[11px]":"text-[13px]";if(s){const i=o.isConnected?"relative flex h-full w-full items-center justify-center overflow-hidden rounded-2xl bg-white transition-all duration-200 ease-out":"relative inline-flex min-w-[110px] items-center justify-center overflow-hidden rounded-2xl border border-gray-300 bg-white px-3 py-2 transition-all duration-200 ease-out hover:border-blue-400 cursor-move";return t("div",{className:`${i} ${o.highlightClass??""}`,style:o.highlightStyle,children:[o.isHighlighted&&e("div",{className:"pointer-events-none absolute inset-0 z-[1] rounded-2xl bg-black/40"}),e("span",{className:`relative ${o.isHighlighted?"z-[2]":"z-[1]"} font-medium text-black ${d}`,children:o.name})]})}const c=o.isConnected,m=l?"relative inline-flex min-w-[110px] items-center justify-between rounded-2xl border px-3 py-2 text-xs transition-all":"relative flex min-w-[180px] items-center justify-between rounded-2xl border-2 px-3 py-2 text-sm transition-all";return t("div",{className:c?`${m} border-green-500 bg-green-50 ring-2 ring-green-200`:`${m} border-gray-200 bg-white hover:border-blue-300`,children:[e("span",{className:`font-medium text-gray-900 ${d}`,children:o.name}),t("div",{className:"flex items-center gap-2",children:[o.isConnected&&e(n,{variant:"outline",className:"bg-green-50 text-xs text-green-700",children:"✓"}),o.isEditMode&&e(i,{size:"icon",variant:"ghost",className:"h-6 w-6",onClick:e=>{e.stopPropagation(),o.onRemove()},children:e(r,{className:"h-3 w-3"})})]})]})}
@@ -1,46 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { Label } from '../../../components/ui/label';
4
- import { Input } from '../../../components/ui/input';
5
- import { Card, CardContent } from '../../../components/ui/card';
6
- import { Alert, AlertDescription } from '../../../components/ui/alert';
7
- import { Database, CheckCircle2, ExternalLink } from 'lucide-react';
8
- import Link from 'next/link';
9
- // Validation constants
10
- const CODE_MAX_LENGTH = 100;
11
- const TITLE_MAX_LENGTH = 255;
12
- // Pattern: only alphanumeric characters, underscore, and hyphen
13
- const CODE_PATTERN = /^[a-zA-Z0-9_-]*$/;
14
- /**
15
- * Shared component for "Add to Question Bank" option.
16
- *
17
- * Has two modes:
18
- * 1. NEW: When existingBank is null - shows editable code/title inputs
19
- * 2. EXISTING: When existingBank has data - shows read-only info with link to edit
20
- *
21
- * Validation rules:
22
- * - Code: Required, max 100 chars, only letters, numbers, underscore (_), hyphen (-)
23
- * - Title: Required, max 255 chars
24
- *
25
- * Used by all question type creators to allow adding questions to the question bank.
26
- */
27
- export function QuestionBankOption({ checked, onCheckedChange, code, onCodeChange, title, onTitleChange, error, codeError, existingBank, disabled = false, }) {
28
- // Handle code change with pattern validation
29
- const handleCodeChange = (value) => {
30
- // Only allow valid characters (alphanumeric, underscore, hyphen)
31
- if (CODE_PATTERN.test(value)) {
32
- onCodeChange(value.slice(0, CODE_MAX_LENGTH));
33
- }
34
- };
35
- // Handle title change with max length
36
- const handleTitleChange = (value) => {
37
- onTitleChange(value.slice(0, TITLE_MAX_LENGTH));
38
- };
39
- // If existing bank data exists, show read-only mode
40
- const isExistingBank = existingBank && existingBank.id;
41
- return (_jsx(Card, { className: `border-dashed ${isExistingBank ? 'border-green-300 bg-green-50/50' : checked ? 'border-blue-300 bg-blue-50/50' : 'border-gray-300 bg-gray-50/50'}`, children: _jsx(CardContent, { className: "pt-4", children: isExistingBank ? (
42
- // EXISTING BANK MODE - Read-only display with edit link
43
- _jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-full bg-green-100", children: _jsx(CheckCircle2, { className: "h-5 w-5 text-green-600" }) }), _jsx("div", { children: _jsx("span", { className: "text-sm font-medium text-green-700", children: "\u0110\u00E3 th\u00EAm v\u00E0o ng\u00E2n h\u00E0ng c\u00E2u h\u1ECFi" }) })] }), _jsxs("div", { className: "mt-4 pl-11 space-y-4", children: [_jsxs("div", { children: [_jsx(Label, { htmlFor: "questionCode", className: "text-sm font-medium text-gray-600", children: "M\u00E3 c\u00E2u h\u1ECFi" }), _jsx(Input, { id: "questionCode", value: existingBank.code, readOnly: true, disabled: true, className: "mt-1.5 bg-gray-100 text-gray-900 cursor-not-allowed" })] }), _jsxs("div", { children: [_jsx(Label, { htmlFor: "questionTitle", className: "text-sm font-medium text-gray-600", children: "Ti\u00EAu \u0111\u1EC1 c\u00E2u h\u1ECFi" }), _jsx(Input, { id: "questionTitle", value: existingBank.title, readOnly: true, disabled: true, className: "mt-1.5 bg-gray-100 text-gray-900 cursor-not-allowed" })] }), _jsxs(Alert, { className: "border-blue-200 bg-blue-50", children: [_jsx(Database, { className: "h-4 w-4 text-blue-600" }), _jsx(AlertDescription, { className: "text-sm text-blue-800", children: _jsxs(Link, { href: `/manage/question-banks?code=${encodeURIComponent(existingBank.code)}`, target: "_blank", rel: "noopener noreferrer", className: "inline-flex items-center gap-1.5 text-blue-600 hover:text-blue-800 font-medium hover:underline", children: ["Ng\u00E2n h\u00E0ng c\u00E2u h\u1ECFi", _jsx(ExternalLink, { className: "h-3.5 w-3.5" })] }) })] })] })] })) : (
44
- // NEW BANK MODE - Editable inputs
45
- _jsxs(_Fragment, { children: [_jsxs("label", { className: `flex items-center gap-3 ${disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'}`, children: [_jsx("input", { type: "checkbox", checked: checked, onChange: (e) => !disabled && onCheckedChange(e.target.checked), disabled: disabled, className: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 disabled:cursor-not-allowed" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Database, { className: `h-4 w-4 ${checked ? 'text-blue-600' : 'text-gray-500'}` }), _jsx("span", { className: `text-sm font-medium ${checked ? 'text-blue-700' : 'text-gray-700'}`, children: "Th\u00EAm v\u00E0o ng\u00E2n h\u00E0ng c\u00E2u h\u1ECFi" })] })] }), checked && (_jsxs("div", { className: "mt-4 pl-7 space-y-4", children: [_jsxs("div", { children: [_jsxs(Label, { htmlFor: "questionCode", className: "text-sm font-medium", children: ["M\u00E3 c\u00E2u h\u1ECFi ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { id: "questionCode", value: code, onChange: (e) => handleCodeChange(e.target.value), placeholder: 'VD: "Q001", "GRID_001", "MC-PAST-01"...', className: `mt-1.5 ${codeError ? 'border-red-500 focus:ring-red-500' : ''}`, disabled: disabled, maxLength: CODE_MAX_LENGTH }), _jsxs("div", { className: "mt-1 flex justify-between", children: [codeError ? (_jsx("p", { className: "text-sm text-red-500", children: codeError })) : (_jsx("p", { className: "text-xs text-gray-500", children: "Ch\u1EC9 ch\u1EEF c\u00E1i, s\u1ED1, d\u1EA5u g\u1EA1ch d\u01B0\u1EDBi (_) v\u00E0 g\u1EA1ch ngang (-)" })), _jsxs("span", { className: "text-xs text-gray-400", children: [code.length, "/", CODE_MAX_LENGTH] })] })] }), _jsxs("div", { children: [_jsxs(Label, { htmlFor: "questionTitle", className: "text-sm font-medium", children: ["Ti\u00EAu \u0111\u1EC1 c\u00E2u h\u1ECFi ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { id: "questionTitle", value: title, onChange: (e) => handleTitleChange(e.target.value), placeholder: 'VD: "Grid \u0111i\u1EC1n t\u1EEB v\u1EC1 \u0111\u1ED9ng v\u1EADt", "Tr\u1EAFc nghi\u1EC7m th\u00EC qu\u00E1 kh\u1EE9"...', className: `mt-1.5 ${error ? 'border-red-500 focus:ring-red-500' : ''}`, disabled: disabled, maxLength: TITLE_MAX_LENGTH }), _jsxs("div", { className: "mt-1 flex justify-between", children: [error ? (_jsx("p", { className: "text-sm text-red-500", children: error })) : (_jsx("p", { className: "text-xs text-gray-500", children: "M\u00E3 v\u00E0 ti\u00EAu \u0111\u1EC1 gi\u00FAp t\u00ECm ki\u1EBFm c\u00E2u h\u1ECFi trong \u0111\u1EC1 thi kh\u00E1c" })), _jsxs("span", { className: "text-xs text-gray-400", children: [title.length, "/", TITLE_MAX_LENGTH] })] })] })] }))] })) }) }));
46
- }
1
+ "use client";import{jsx as e,jsxs as t,Fragment as r}from"react/jsx-runtime";import{Label as a}from"../../../components/ui/label";import{Input as n}from"../../../components/ui/input";import{Card as l,CardContent as s}from"../../../components/ui/card";import{Alert as i,AlertDescription as c}from"../../../components/ui/alert";import{Database as d,CheckCircle2 as o,ExternalLink as m}from"lucide-react";import h from"next/link";const u=/^[a-zA-Z0-9_-]*$/;export function QuestionBankOption({checked:g,onCheckedChange:x,code:b,onCodeChange:p,title:N,onTitleChange:f,error:v,codeError:y,existingBank:C,disabled:k=!1}){const w=C&&C.id;return e(l,{className:"border-dashed "+(w?"border-green-300 bg-green-50/50":g?"border-blue-300 bg-blue-50/50":"border-gray-300 bg-gray-50/50"),children:e(s,{className:"pt-4",children:t(r,w?{children:[t("div",{className:"flex items-center gap-3",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-full bg-green-100",children:e(o,{className:"h-5 w-5 text-green-600"})}),e("div",{children:e("span",{className:"text-sm font-medium text-green-700",children:"Đã thêm vào ngân hàng câu hỏi"})})]}),t("div",{className:"mt-4 pl-11 space-y-4",children:[t("div",{children:[e(a,{htmlFor:"questionCode",className:"text-sm font-medium text-gray-600",children:"Mã câu hỏi"}),e(n,{id:"questionCode",value:C.code,readOnly:!0,disabled:!0,className:"mt-1.5 bg-gray-100 text-gray-900 cursor-not-allowed"})]}),t("div",{children:[e(a,{htmlFor:"questionTitle",className:"text-sm font-medium text-gray-600",children:"Tiêu đề câu hỏi"}),e(n,{id:"questionTitle",value:C.title,readOnly:!0,disabled:!0,className:"mt-1.5 bg-gray-100 text-gray-900 cursor-not-allowed"})]}),t(i,{className:"border-blue-200 bg-blue-50",children:[e(d,{className:"h-4 w-4 text-blue-600"}),e(c,{className:"text-sm text-blue-800",children:t(h,{href:`/manage/question-banks?code=${encodeURIComponent(C.code)}`,target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1.5 text-blue-600 hover:text-blue-800 font-medium hover:underline",children:["Ngân hàng câu hỏi",e(m,{className:"h-3.5 w-3.5"})]})})]})]})]}:{children:[t("label",{className:"flex items-center gap-3 "+(k?"cursor-not-allowed opacity-50":"cursor-pointer"),children:[e("input",{type:"checkbox",checked:g,onChange:e=>!k&&x(e.target.checked),disabled:k,className:"h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 disabled:cursor-not-allowed"}),t("div",{className:"flex items-center gap-2",children:[e(d,{className:"h-4 w-4 "+(g?"text-blue-600":"text-gray-500")}),e("span",{className:"text-sm font-medium "+(g?"text-blue-700":"text-gray-700"),children:"Thêm vào ngân hàng câu hỏi"})]})]}),g&&t("div",{className:"mt-4 pl-7 space-y-4",children:[t("div",{children:[t(a,{htmlFor:"questionCode",className:"text-sm font-medium",children:["Mã câu hỏi ",e("span",{className:"text-red-500",children:"*"})]}),e(n,{id:"questionCode",value:b,onChange:e=>{return t=e.target.value,void(u.test(t)&&p(t.slice(0,100)));var t},placeholder:'VD: "Q001", "GRID_001", "MC-PAST-01"...',className:"mt-1.5 "+(y?"border-red-500 focus:ring-red-500":""),disabled:k,maxLength:100}),t("div",{className:"mt-1 flex justify-between",children:[e("p",y?{className:"text-sm text-red-500",children:y}:{className:"text-xs text-gray-500",children:"Chỉ chữ cái, số, dấu gạch dưới (_) và gạch ngang (-)"}),t("span",{className:"text-xs text-gray-400",children:[b.length,"/",100]})]})]}),t("div",{children:[t(a,{htmlFor:"questionTitle",className:"text-sm font-medium",children:["Tiêu đề câu hỏi ",e("span",{className:"text-red-500",children:"*"})]}),e(n,{id:"questionTitle",value:N,onChange:e=>{return t=e.target.value,void f(t.slice(0,255));var t},placeholder:'VD: "Grid điền từ về động vật", "Trắc nghiệm thì quá khứ"...',className:"mt-1.5 "+(v?"border-red-500 focus:ring-red-500":""),disabled:k,maxLength:255}),t("div",{className:"mt-1 flex justify-between",children:[e("p",v?{className:"text-sm text-red-500",children:v}:{className:"text-xs text-gray-500",children:"Mã và tiêu đề giúp tìm kiếm câu hỏi trong đề thi khác"}),t("span",{className:"text-xs text-gray-400",children:[N.length,"/",255]})]})]})]})]})})})}
@@ -1,9 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Label } from '../../../components/ui/label';
3
- import { Input } from '../../../components/ui/input';
4
- import { Textarea } from '../../../components/ui/textarea';
5
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../../components/ui/select';
6
- import { QuestionTypeSelector } from './QuestionTypeSelector';
7
- export function QuestionBasicInfoForm({ questionType, content, level, difficulty, skill, points, isEmbedded, prefilledType, onQuestionTypeChange, onContentChange, onLevelChange, onDifficultyChange, onSkillChange, onPointsChange, }) {
8
- return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx(Label, { htmlFor: "questionType", children: "Lo\u1EA1i c\u00E2u h\u1ECFi *" }), _jsx(QuestionTypeSelector, { value: questionType, onValueChange: onQuestionTypeChange, disabled: isEmbedded && !!prefilledType })] }), questionType !== 'CHOOSE_THE_CORRECT_ANSWER' && (_jsxs("div", { children: [_jsx(Label, { htmlFor: "content", children: "N\u1ED9i dung c\u00E2u h\u1ECFi *" }), _jsx(Textarea, { id: "content", value: content, onChange: (e) => onContentChange(e.target.value), placeholder: "Nh\u1EADp n\u1ED9i dung c\u00E2u h\u1ECFi...", className: "mt-1", rows: 3 })] })), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { children: [_jsx(Label, { htmlFor: "level", children: "C\u1EA5p \u0111\u1ED9 *" }), _jsxs(Select, { value: level, onValueChange: (value) => onLevelChange(value), children: [_jsx(SelectTrigger, { id: "level", className: "mt-1", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "A1", children: "A1" }), _jsx(SelectItem, { value: "A2", children: "A2" }), _jsx(SelectItem, { value: "B1", children: "B1" }), _jsx(SelectItem, { value: "B2", children: "B2" }), _jsx(SelectItem, { value: "C1", children: "C1" }), _jsx(SelectItem, { value: "C2", children: "C2" })] })] })] }), _jsxs("div", { children: [_jsx(Label, { htmlFor: "difficulty", children: "\u0110\u1ED9 kh\u00F3 *" }), _jsxs(Select, { value: difficulty, onValueChange: (value) => onDifficultyChange(value), children: [_jsx(SelectTrigger, { id: "difficulty", className: "mt-1", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "EASY", children: "D\u1EC5" }), _jsx(SelectItem, { value: "MEDIUM", children: "Trung b\u00ECnh" }), _jsx(SelectItem, { value: "HARD", children: "Kh\u00F3" })] })] })] }), _jsxs("div", { children: [_jsx(Label, { htmlFor: "skill", children: "K\u1EF9 n\u0103ng *" }), _jsxs(Select, { value: skill, onValueChange: (value) => onSkillChange(value), children: [_jsx(SelectTrigger, { id: "skill", className: "mt-1", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "LISTENING", children: "Listening" }), _jsx(SelectItem, { value: "READING", children: "Reading" }), _jsx(SelectItem, { value: "WRITING", children: "Writing" }), _jsx(SelectItem, { value: "SPEAKING", children: "Speaking" })] })] })] }), _jsxs("div", { children: [_jsx(Label, { htmlFor: "points", children: "\u0110i\u1EC3m *" }), _jsx(Input, { id: "points", type: "number", value: points, onChange: (e) => onPointsChange(Number(e.target.value)), className: "mt-1", min: 1 })] })] })] }));
9
- }
1
+ import{jsx as e,jsxs as n}from"react/jsx-runtime";import{Label as i}from"../../../components/ui/label";import{Input as l}from"../../../components/ui/input";import{Textarea as r}from"../../../components/ui/textarea";import{Select as a,SelectContent as c,SelectItem as d,SelectTrigger as h,SelectValue as o}from"../../../components/ui/select";import{QuestionTypeSelector as t}from"./QuestionTypeSelector";export function QuestionBasicInfoForm({questionType:u,content:s,level:m,difficulty:v,skill:p,points:g,isEmbedded:C,prefilledType:f,onQuestionTypeChange:N,onContentChange:y,onLevelChange:E,onDifficultyChange:T,onSkillChange:A,onPointsChange:I}){return n("div",{className:"space-y-4",children:[n("div",{children:[e(i,{htmlFor:"questionType",children:"Loại câu hỏi *"}),e(t,{value:u,onValueChange:N,disabled:C&&!!f})]}),"CHOOSE_THE_CORRECT_ANSWER"!==u&&n("div",{children:[e(i,{htmlFor:"content",children:"Nội dung câu hỏi *"}),e(r,{id:"content",value:s,onChange:e=>y(e.target.value),placeholder:"Nhập nội dung câu hỏi...",className:"mt-1",rows:3})]}),n("div",{className:"grid grid-cols-2 gap-4",children:[n("div",{children:[e(i,{htmlFor:"level",children:"Cấp độ *"}),n(a,{value:m,onValueChange:e=>E(e),children:[e(h,{id:"level",className:"mt-1",children:e(o,{})}),n(c,{children:[e(d,{value:"A1",children:"A1"}),e(d,{value:"A2",children:"A2"}),e(d,{value:"B1",children:"B1"}),e(d,{value:"B2",children:"B2"}),e(d,{value:"C1",children:"C1"}),e(d,{value:"C2",children:"C2"})]})]})]}),n("div",{children:[e(i,{htmlFor:"difficulty",children:"Độ khó *"}),n(a,{value:v,onValueChange:e=>T(e),children:[e(h,{id:"difficulty",className:"mt-1",children:e(o,{})}),n(c,{children:[e(d,{value:"EASY",children:"Dễ"}),e(d,{value:"MEDIUM",children:"Trung bình"}),e(d,{value:"HARD",children:"Khó"})]})]})]}),n("div",{children:[e(i,{htmlFor:"skill",children:"Kỹ năng *"}),n(a,{value:p,onValueChange:e=>A(e),children:[e(h,{id:"skill",className:"mt-1",children:e(o,{})}),n(c,{children:[e(d,{value:"LISTENING",children:"Listening"}),e(d,{value:"READING",children:"Reading"}),e(d,{value:"WRITING",children:"Writing"}),e(d,{value:"SPEAKING",children:"Speaking"})]})]})]}),n("div",{children:[e(i,{htmlFor:"points",children:"Điểm *"}),e(l,{id:"points",type:"number",value:g,onChange:e=>I(Number(e.target.value)),className:"mt-1",min:1})]})]})]})}
@@ -1,33 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Label } from '../../../components/ui/label';
4
- import { Textarea } from '../../../components/ui/textarea';
5
- import { Card, CardContent, CardHeader, CardTitle } from '../../../components/ui/card';
6
- import { PointsInput } from '../../../components/ui/points-input';
7
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../../components/ui/select';
8
- /**
9
- * Shared component for common question fields:
10
- * - Points (điểm số)
11
- * - Difficulty (độ khó)
12
- * - Explanation (giải thích)
13
- *
14
- * Used by all question type creators to ensure consistency.
15
- */
16
- export function QuestionCommonFields({ points, onPointsChange, difficulty = 'MEDIUM', onDifficultyChange, showDifficulty = true, explanation = '', onExplanationChange, showExplanation = true, layout = 'horizontal', }) {
17
- const getDifficultyLabel = (diff) => {
18
- switch (diff) {
19
- case 'EASY':
20
- return 'Dễ';
21
- case 'MEDIUM':
22
- return 'Trung bình';
23
- case 'HARD':
24
- return 'Khó';
25
- default:
26
- return diff;
27
- }
28
- };
29
- return (_jsxs(Card, { children: [_jsx(CardHeader, { className: "pb-3", children: _jsx(CardTitle, { className: "text-base", children: "Th\u00F4ng tin c\u01A1 b\u1EA3n" }) }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: layout === 'horizontal' ? 'grid grid-cols-2 gap-4' : 'space-y-4', children: [_jsx("div", { children: _jsx(PointsInput, { defaultValue: points, onChange: (e) => {
30
- const value = Number(e.target.value);
31
- onPointsChange(value || 1);
32
- } }) }), showDifficulty && onDifficultyChange && (_jsxs("div", { children: [_jsx(Label, { htmlFor: "difficulty", className: "text-sm font-medium", children: "\u0110\u1ED9 kh\u00F3" }), _jsxs(Select, { value: difficulty, onValueChange: (value) => onDifficultyChange(value), children: [_jsx(SelectTrigger, { id: "difficulty", className: "mt-1.5", children: _jsx(SelectValue, { placeholder: "Ch\u1ECDn \u0111\u1ED9 kh\u00F3", children: getDifficultyLabel(difficulty) }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "EASY", children: "D\u1EC5" }), _jsx(SelectItem, { value: "MEDIUM", children: "Trung b\u00ECnh" }), _jsx(SelectItem, { value: "HARD", children: "Kh\u00F3" })] })] })] }))] }), showExplanation && onExplanationChange && (_jsxs("div", { children: [_jsx(Label, { htmlFor: "explanation", className: "text-sm font-medium", children: "Gi\u1EA3i th\u00EDch" }), _jsx(Textarea, { id: "explanation", value: explanation, onChange: (e) => onExplanationChange(e.target.value), placeholder: "Nh\u1EADp gi\u1EA3i th\u00EDch cho \u0111\u00E1p \u00E1n \u0111\u00FAng...", className: "mt-1.5", rows: 3 }), _jsx("p", { className: "mt-1 text-xs text-gray-500", children: "Gi\u1EA3i th\u00EDch s\u1EBD \u0111\u01B0\u1EE3c hi\u1EC3n th\u1ECB cho h\u1ECDc sinh sau khi n\u1ED9p b\u00E0i" })] }))] })] }));
33
- }
1
+ "use client";import{jsx as e,jsxs as n}from"react/jsx-runtime";import{Label as i}from"../../../components/ui/label";import{Textarea as t}from"../../../components/ui/textarea";import{Card as a,CardContent as l,CardHeader as c,CardTitle as r}from"../../../components/ui/card";import{PointsInput as o}from"../../../components/ui/points-input";import{Select as h,SelectContent as s,SelectItem as m,SelectTrigger as u,SelectValue as d}from"../../../components/ui/select";export function QuestionCommonFields({points:p,onPointsChange:f,difficulty:g="MEDIUM",onDifficultyChange:x,showDifficulty:v=!0,explanation:N="",onExplanationChange:y,showExplanation:D=!0,layout:b="horizontal"}){return n(a,{children:[e(c,{className:"pb-3",children:e(r,{className:"text-base",children:"Thông tin cơ bản"})}),n(l,{className:"space-y-4",children:[n("div",{className:"horizontal"===b?"grid grid-cols-2 gap-4":"space-y-4",children:[e("div",{children:e(o,{defaultValue:p,onChange:e=>{const n=Number(e.target.value);f(n||1)}})}),v&&x&&n("div",{children:[e(i,{htmlFor:"difficulty",className:"text-sm font-medium",children:"Độ khó"}),n(h,{value:g,onValueChange:e=>x(e),children:[e(u,{id:"difficulty",className:"mt-1.5",children:e(d,{placeholder:"Chọn độ khó",children:(e=>{switch(e){case"EASY":return"Dễ";case"MEDIUM":return"Trung bình";case"HARD":return"Khó";default:return e}})(g)})}),n(s,{children:[e(m,{value:"EASY",children:"Dễ"}),e(m,{value:"MEDIUM",children:"Trung bình"}),e(m,{value:"HARD",children:"Khó"})]})]})]})]}),D&&y&&n("div",{children:[e(i,{htmlFor:"explanation",className:"text-sm font-medium",children:"Giải thích"}),e(t,{id:"explanation",value:N,onChange:e=>y(e.target.value),placeholder:"Nhập giải thích cho đáp án đúng...",className:"mt-1.5",rows:3}),e("p",{className:"mt-1 text-xs text-gray-500",children:"Giải thích sẽ được hiển thị cho học sinh sau khi nộp bài"})]})]})]})}
@@ -1,258 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useEffect, useMemo, useState } from 'react';
4
- import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '../../../components/ui/dropdown-menu';
5
- import { Input } from '../../../components/ui/input';
6
- import { Badge } from '../../../components/ui/badge';
7
- import { Loader2, Search, Image as ImageIcon, FileText, Grid3X3, BookOpen, Library, Sparkles, Hash, BarChart3, Lightbulb, CheckCircle2, } from 'lucide-react';
8
- import { useQuery } from '@tanstack/react-query';
9
- import { ScrollArea } from '../../../components/ui/scroll-area';
10
- import { cn } from '../../../shared/lib/utils';
11
- const truncate = (text, maxLength) => {
12
- if (!text)
13
- return '';
14
- // Convert to string if it's not already
15
- const textStr = typeof text === 'string' ? text : String(text);
16
- if (textStr.length <= maxLength)
17
- return textStr;
18
- return `${textStr.substring(0, maxLength)}...`;
19
- };
20
- // Image-based question types
21
- const IMAGE_BASED_TYPES = [
22
- 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER',
23
- 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER',
24
- 'LOOK_PICTURE_FILL_WORD_HINT',
25
- 'FILL_IN_BLANK',
26
- 'LABEL_THE_PICTURE',
27
- 'READ_AND_COLOR_OBJECTS',
28
- 'IMAGE_OBJECT_MATCHING',
29
- 'FILL_IN_BLANK',
30
- ];
31
- // Passage-based question types
32
- const PASSAGE_BASED_TYPES = [
33
- 'READ_PASSAGE_AND_ANSWER_QUESTIONS',
34
- 'READ_PASSAGE_AND_COMPLETE_STORY',
35
- ];
36
- // Grid-based question types
37
- const GRID_BASED_TYPES = ['FILL_MISSING_WORDS_IN_GRID'];
38
- // Get display icon for question type
39
- const getQuestionTypeIcon = (type) => {
40
- if (IMAGE_BASED_TYPES.includes(type)) {
41
- return _jsx(ImageIcon, { className: "h-4 w-4 text-blue-500" });
42
- }
43
- if (PASSAGE_BASED_TYPES.includes(type)) {
44
- return _jsx(BookOpen, { className: "h-4 w-4 text-green-500" });
45
- }
46
- if (GRID_BASED_TYPES.includes(type)) {
47
- return _jsx(Grid3X3, { className: "h-4 w-4 text-purple-500" });
48
- }
49
- return _jsx(FileText, { className: "h-4 w-4 text-gray-500" });
50
- };
51
- // Get question type display name in Vietnamese
52
- const getQuestionTypeName = (type) => {
53
- const typeMap = {
54
- 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER': 'Nhìn tranh điền chỗ trống',
55
- 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER': 'Nhìn tranh chọn đáp án',
56
- 'LOOK_PICTURE_FILL_WORD_HINT': 'Nhìn tranh điền từ gợi ý',
57
- 'FILL_MISSING_WORDS_IN_GRID': 'Điền chữ trong bảng',
58
- 'CHOOSE_THE_CORRECT_ANSWER': 'Chọn đáp án đúng',
59
- 'LABEL_THE_PICTURE': 'Gắn nhãn hình ảnh',
60
- 'READ_AND_COLOR_OBJECTS': 'Đọc và tô màu',
61
- 'IMAGE_OBJECT_MATCHING': 'Ghép hình ảnh - Đối tượng',
62
- 'WRITE_CORRECT_VERB_FORM': 'Viết dạng động từ',
63
- 'FILL_IN_BLANK': 'Điền vào chỗ trống',
64
- 'READ_PASSAGE_AND_ANSWER_QUESTIONS': 'Đọc hiểu',
65
- };
66
- return type ? typeMap[type] || type.replace(/_/g, ' ').toLowerCase() : 'Chưa xác định';
67
- };
68
- // Enhanced function to extract display text from different question content structures
69
- export const getQuestionDisplayText = (question) => {
70
- return getContentDisplayText(question.content, question.type);
71
- };
72
- // Extract display text from content object (for cases where we have content but not full Question)
73
- export const getContentDisplayText = (content, type) => {
74
- if (!content)
75
- return type || 'Câu hỏi';
76
- // Handle string content directly
77
- if (typeof content === 'string') {
78
- return content;
79
- }
80
- // Handle object content based on question type
81
- if (typeof content === 'object') {
82
- // LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER, LOOK_PICTURE_CHOOSE_CORRECT_ANSWER
83
- if (content.subQuestions && Array.isArray(content.subQuestions)) {
84
- const firstSubQ = content.subQuestions[0];
85
- if (firstSubQ?.question) {
86
- return firstSubQ.question;
87
- }
88
- }
89
- // For content with direct question field (single question format)
90
- if (content.question) {
91
- return content.question;
92
- }
93
- // LOOK_PICTURE_FILL_WORD_HINT - show word pattern
94
- if (content.word) {
95
- return `Điền chữ: ${content.word}`;
96
- }
97
- // READ_PASSAGE_AND_ANSWER_QUESTIONS
98
- if (content.passage) {
99
- return content.passageTitle || truncate(content.passage, 60);
100
- }
101
- // FILL_MISSING_WORDS_IN_GRID
102
- if (content.grid && content.rows && content.columns) {
103
- return `Lưới ${content.rows}x${content.columns}`;
104
- }
105
- // LABEL_THE_PICTURE
106
- if (content.wordBank) {
107
- const words = content.wordBank.map((w) => w.text || w).slice(0, 3).join(', ');
108
- return `Từ vựng: ${words}${content.wordBank.length > 3 ? '...' : ''}`;
109
- }
110
- // READ_AND_COLOR_OBJECTS / IMAGE_OBJECT_MATCHING
111
- if (content.colorNodes || content.regionNodes) {
112
- const regionCount = content.regionNodes?.length || 0;
113
- return `${regionCount} vùng tô màu`;
114
- }
115
- // WRITE_A_SHORT_LETTER
116
- if (content.contexts) {
117
- const firstContext = content.contexts[0];
118
- return firstContext?.text ? truncate(firstContext.text, 50) : 'Viết thư ngắn';
119
- }
120
- // CHOOSE_THE_CORRECT_ANSWER
121
- if (content.options && Array.isArray(content.options)) {
122
- return content.questionText || content.question || 'Câu hỏi trắc nghiệm';
123
- }
124
- // FILL_IN_BLANK
125
- if (content.blanks) {
126
- const firstBlank = content.blanks[0];
127
- return firstBlank?.text || content.sentence || 'Điền vào chỗ trống';
128
- }
129
- // Fallback: try common field names
130
- if (content.instruction)
131
- return content.instruction;
132
- if (content.mainTitle)
133
- return content.mainTitle;
134
- if (content.title)
135
- return content.title;
136
- if (content.text)
137
- return content.text;
138
- }
139
- return type || 'Câu hỏi';
140
- };
141
- // Get difficulty badge color
142
- const getDifficultyBadgeClass = (difficulty) => {
143
- switch (difficulty?.toUpperCase()) {
144
- case 'EASY':
145
- return 'bg-green-100 text-green-700 border-green-200';
146
- case 'HARD':
147
- return 'bg-red-100 text-red-700 border-red-200';
148
- default:
149
- return 'bg-yellow-100 text-yellow-700 border-yellow-200';
150
- }
151
- };
152
- // Get difficulty display name
153
- const getDifficultyName = (difficulty) => {
154
- switch (difficulty?.toUpperCase()) {
155
- case 'EASY':
156
- return 'Dễ';
157
- case 'HARD':
158
- return 'Khó';
159
- case 'MEDIUM':
160
- return 'TB';
161
- default:
162
- return 'TB';
163
- }
164
- };
165
- // Get subquestion count if applicable
166
- const getSubQuestionCount = (question) => {
167
- const content = question.content;
168
- if (!content)
169
- return null;
170
- if (content.subQuestions && Array.isArray(content.subQuestions)) {
171
- return content.subQuestions.length;
172
- }
173
- return null;
174
- };
175
- export function QuestionSearchDropdown({ questionType, onSelect, selectedQuestionLabel, placeholder = 'Tìm câu hỏi từ ngân hàng', disabled = false, buttonClassName, compact = false, searchQuestions, }) {
176
- const [open, setOpen] = useState(false);
177
- const [searchTerm, setSearchTerm] = useState('');
178
- const [debouncedTerm, setDebouncedTerm] = useState('');
179
- useEffect(() => {
180
- const handler = setTimeout(() => {
181
- setDebouncedTerm(searchTerm.trim());
182
- }, 300);
183
- return () => clearTimeout(handler);
184
- }, [searchTerm]);
185
- // Transform QuestionBankItem to Question format with extended info
186
- const transformToQuestion = (item) => ({
187
- id: item.id,
188
- type: item.questionType,
189
- content: item.content,
190
- answer: item.correctAnswer,
191
- points: parseFloat(String(item.points ?? 1)) || 1,
192
- difficulty: item.difficulty?.toUpperCase(),
193
- skill: (item.skill || undefined),
194
- explanation: item.explanation || undefined,
195
- level: 'A1', // Default value
196
- createdAt: item.createdAt,
197
- updatedAt: item.updatedAt,
198
- // Extended info from question bank
199
- code: item.code,
200
- title: item.title || undefined,
201
- usageCount: item.usageCount,
202
- });
203
- // Host app may provide dynamic search directly via component props.
204
- const { data: questionBankData, isFetching } = useQuery({
205
- queryKey: ['questionBanks', 'search', questionType, debouncedTerm],
206
- queryFn: async () => {
207
- if (!searchQuestions)
208
- return { data: [], meta: { totalItems: 0 } };
209
- return searchQuestions({
210
- questionType,
211
- keyword: debouncedTerm || undefined,
212
- page: 1,
213
- size: 10,
214
- });
215
- },
216
- enabled: open && Boolean(questionType) && Boolean(searchQuestions) && (debouncedTerm.length > 0 || !!questionType),
217
- staleTime: 60 * 1000,
218
- refetchOnWindowFocus: false,
219
- });
220
- // Transform API response to Question array
221
- const questions = useMemo(() => {
222
- if (!questionBankData?.data)
223
- return [];
224
- return questionBankData.data.map(transformToQuestion);
225
- }, [questionBankData]);
226
- const totalItems = questionBankData?.meta?.totalItems || 0;
227
- const hasNoResults = !isFetching && questions.length === 0 && debouncedTerm.length > 0;
228
- // Show empty bank message when: API returned (questionBankData exists), no questions, and no search term
229
- const hasEmptyBank = !isFetching && questionBankData && questions.length === 0 && debouncedTerm.length === 0;
230
- // Only show initial tips when: not fetching, no API response yet (first open before any query)
231
- const showInitialMessage = !isFetching && !questionBankData && questions.length === 0 && debouncedTerm.length === 0;
232
- const buttonLabel = useMemo(() => {
233
- if (selectedQuestionLabel) {
234
- return truncate(selectedQuestionLabel, 40);
235
- }
236
- return placeholder;
237
- }, [placeholder, selectedQuestionLabel]);
238
- const handleSelect = (question) => {
239
- onSelect(question);
240
- setOpen(false);
241
- setSearchTerm('');
242
- setDebouncedTerm('');
243
- };
244
- return (_jsxs(DropdownMenu, { open: open, onOpenChange: (value) => setOpen(!disabled && value), children: [_jsx(DropdownMenuTrigger, { asChild: true, disabled: disabled, children: compact ? (_jsxs("button", { type: "button", className: cn('group inline-flex h-8 items-center gap-1.5 rounded-md border px-3 text-sm font-medium transition-all', selectedQuestionLabel
245
- ? 'border-emerald-200 bg-emerald-50 text-emerald-700 hover:bg-emerald-100'
246
- : 'border-indigo-200 text-indigo-600 hover:bg-indigo-50 hover:text-indigo-700', 'focus:outline-none focus:ring-2 focus:ring-indigo-200 focus:ring-offset-1', disabled && 'cursor-not-allowed opacity-50', buttonClassName), children: [selectedQuestionLabel ? (_jsx(CheckCircle2, { className: "h-4 w-4" })) : (_jsx(Library, { className: "h-4 w-4" })), selectedQuestionLabel ? 'Đã chọn' : 'Ngân hàng'] })) : (_jsxs("button", { type: "button", className: cn('group relative flex w-full items-center gap-3 rounded-xl border bg-white p-3 text-left shadow-sm transition-all', selectedQuestionLabel
247
- ? 'border-emerald-200 bg-gradient-to-r from-emerald-50/50 to-teal-50/50'
248
- : 'border-gray-200 hover:border-indigo-200 hover:bg-gradient-to-r hover:from-indigo-50/30 hover:to-purple-50/30', 'focus:outline-none focus:ring-2 focus:ring-indigo-200 focus:ring-offset-1', disabled && 'cursor-not-allowed opacity-50', buttonClassName), children: [_jsx("div", { className: cn('flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg transition-all', selectedQuestionLabel
249
- ? 'bg-gradient-to-br from-emerald-500 to-teal-600 shadow-sm'
250
- : 'bg-gradient-to-br from-indigo-100 to-purple-100 group-hover:from-indigo-500 group-hover:to-purple-600 group-hover:shadow-sm'), children: selectedQuestionLabel ? (_jsx(CheckCircle2, { className: "h-5 w-5 text-white" })) : (_jsx(Library, { className: cn('h-5 w-5 transition-colors', 'text-indigo-500 group-hover:text-white') })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "flex items-center gap-2", children: _jsx("span", { className: cn('text-xs font-medium uppercase tracking-wide', selectedQuestionLabel ? 'text-emerald-600' : 'text-indigo-500'), children: selectedQuestionLabel ? '✓ Đã chọn từ ngân hàng' : 'Ngân hàng câu hỏi' }) }), _jsx("p", { className: cn('mt-0.5 truncate text-sm', selectedQuestionLabel ? 'font-medium text-gray-800' : 'text-gray-500'), children: selectedQuestionLabel
251
- ? truncate(selectedQuestionLabel, 55)
252
- : 'Nhấn để tìm và sử dụng câu hỏi có sẵn' })] }), _jsx("div", { className: cn('flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full transition-all', selectedQuestionLabel
253
- ? 'bg-emerald-100 text-emerald-600'
254
- : 'bg-gray-100 text-gray-400 group-hover:bg-indigo-100 group-hover:text-indigo-600'), children: _jsx(Search, { className: "h-4 w-4" }) })] })) }), _jsxs(DropdownMenuContent, { className: "w-[520px] p-0", align: compact ? "end" : "start", children: [_jsx("div", { className: "border-b border-gray-100 bg-gradient-to-r from-indigo-50 to-purple-50 px-4 py-3", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-9 w-9 items-center justify-center rounded-lg bg-gradient-to-br from-indigo-500 to-purple-600 shadow-sm", children: _jsx(Library, { className: "h-4 w-4 text-white" }) }), _jsxs("div", { className: "flex-1", children: [_jsx("h3", { className: "text-sm font-semibold text-gray-800", children: "Ng\u00E2n h\u00E0ng c\u00E2u h\u1ECFi" }), _jsx("p", { className: "text-xs text-gray-500", children: "Ch\u1ECDn c\u00E2u h\u1ECFi c\u00F3 s\u1EB5n \u0111\u1EC3 \u0111i\u1EC1n nhanh v\u00E0o form" })] })] }) }), _jsxs("div", { className: "border-b border-gray-100 bg-gray-50/50 p-3", children: [_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" }), _jsx(Input, { placeholder: "T\u00ECm theo m\u00E3, ti\u00EAu \u0111\u1EC1 ho\u1EB7c n\u1ED9i dung...", value: searchTerm, onChange: (event) => setSearchTerm(event.target.value), autoFocus: true, className: "border-gray-200 bg-white pl-10 pr-10 transition-all focus:border-indigo-300 focus:ring-indigo-200" }), isFetching && (_jsx(Loader2, { className: "absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-indigo-500" }))] }), _jsxs("div", { className: "mt-2 flex items-center justify-between", children: [_jsx("div", { className: "flex items-center gap-2", children: _jsx(Badge, { variant: "outline", className: "border-indigo-200 bg-indigo-50 text-indigo-700", children: getQuestionTypeName(questionType) }) }), totalItems > 0 && (_jsxs("span", { className: "text-xs text-gray-500", children: ["Hi\u1EC3n th\u1ECB ", questions.length, "/", totalItems, " k\u1EBFt qu\u1EA3"] }))] })] }), _jsx(ScrollArea, { className: "h-80", children: showInitialMessage ? (_jsxs("div", { className: "flex flex-col items-center justify-center p-8 text-center", children: [_jsx("div", { className: "mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-gradient-to-br from-indigo-100 to-purple-100", children: _jsx(Sparkles, { className: "h-8 w-8 text-indigo-500" }) }), _jsx("p", { className: "text-sm font-medium text-gray-700", children: "T\u00ECm c\u00E2u h\u1ECFi t\u1EEB ng\u00E2n h\u00E0ng" }), _jsx("p", { className: "mt-1 text-xs text-gray-500", children: "Nh\u1EADp m\u00E3 c\u00E2u h\u1ECFi, ti\u00EAu \u0111\u1EC1 ho\u1EB7c t\u1EEB kh\u00F3a \u0111\u1EC3 t\u00ECm ki\u1EBFm" }), _jsx("div", { className: "mt-4 rounded-lg border border-blue-200 bg-blue-50 p-3", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Lightbulb, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-blue-500" }), _jsxs("div", { className: "text-left text-xs text-blue-700", children: [_jsx("p", { className: "font-medium", children: "M\u1EB9o t\u00ECm ki\u1EBFm nhanh:" }), _jsxs("ul", { className: "mt-1 list-inside list-disc space-y-0.5 text-blue-600", children: [_jsx("li", { children: "Nh\u1EADp m\u00E3 c\u00E2u h\u1ECFi (VD: M001)" }), _jsx("li", { children: "Nh\u1EADp ti\u00EAu \u0111\u1EC1 ho\u1EB7c m\u1ED9t ph\u1EA7n n\u1ED9i dung" }), _jsx("li", { children: "K\u1EBFt qu\u1EA3 s\u1EBD t\u1EF1 \u0111\u1ED9ng c\u1EADp nh\u1EADt" })] })] })] }) })] })) : hasEmptyBank ? (_jsxs("div", { className: "flex flex-col items-center justify-center p-8 text-center", children: [_jsx("div", { className: "mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-amber-100", children: _jsx(Library, { className: "h-8 w-8 text-amber-500" }) }), _jsx("p", { className: "text-sm font-medium text-gray-700", children: "Ch\u01B0a c\u00F3 c\u00E2u h\u1ECFi trong ng\u00E2n h\u00E0ng" }), _jsxs("p", { className: "mt-1 text-xs text-gray-500", children: ["Ng\u00E2n h\u00E0ng c\u00E2u h\u1ECFi ch\u01B0a c\u00F3 d\u1EEF li\u1EC7u cho lo\u1EA1i: ", _jsx("strong", { children: getQuestionTypeName(questionType) })] }), _jsx("p", { className: "mt-2 text-xs text-gray-400", children: "H\u00E3y th\u00EAm c\u00E2u h\u1ECFi v\u00E0o ng\u00E2n h\u00E0ng ho\u1EB7c t\u1EA1o c\u00E2u h\u1ECFi m\u1EDBi" })] })) : hasNoResults ? (_jsxs("div", { className: "flex flex-col items-center justify-center p-8 text-center", children: [_jsx("div", { className: "mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-gray-100", children: _jsx(Search, { className: "h-8 w-8 text-gray-400" }) }), _jsx("p", { className: "text-sm font-medium text-gray-700", children: "Kh\u00F4ng t\u00ECm th\u1EA5y k\u1EBFt qu\u1EA3" }), _jsxs("p", { className: "mt-1 text-xs text-gray-500", children: ["Th\u1EED t\u00ECm v\u1EDBi t\u1EEB kh\u00F3a kh\u00E1c: \"", debouncedTerm, "\""] })] })) : (_jsx("div", { className: "divide-y divide-gray-100 p-2", children: questions.map((question) => {
255
- const subQuestionCount = getSubQuestionCount(question);
256
- return (_jsxs(DropdownMenuItem, { className: "flex cursor-pointer flex-col items-start gap-2 rounded-xl p-3 transition-all hover:bg-gradient-to-r hover:from-indigo-50 hover:to-purple-50 focus:bg-gradient-to-r focus:from-indigo-50 focus:to-purple-50", onSelect: () => handleSelect(question), children: [_jsxs("div", { className: "flex w-full items-start justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [question.code && (_jsxs("div", { className: "flex items-center gap-1 rounded-md bg-gradient-to-r from-indigo-500 to-purple-500 px-2 py-0.5 text-xs font-bold text-white shadow-sm", children: [_jsx(Hash, { className: "h-3 w-3" }), question.code] })), _jsx("div", { className: "flex-shrink-0", children: getQuestionTypeIcon(question.type) })] }), question.usageCount !== undefined && question.usageCount > 0 && (_jsxs("div", { className: "flex items-center gap-1 text-xs text-gray-500", title: "S\u1ED1 l\u1EA7n s\u1EED d\u1EE5ng", children: [_jsx(BarChart3, { className: "h-3 w-3" }), question.usageCount] }))] }), question.title && (_jsx("p", { className: "text-sm font-semibold text-gray-800", children: truncate(question.title, 60) })), _jsx("p", { className: "text-xs text-gray-600", children: truncate(getQuestionDisplayText(question), 80) }), _jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [_jsx(Badge, { variant: "outline", className: cn('px-2 py-0.5 text-[10px] font-semibold', getDifficultyBadgeClass(question.difficulty)), children: getDifficultyName(question.difficulty) }), _jsxs(Badge, { variant: "outline", className: "border-blue-200 bg-blue-50 px-2 py-0.5 text-[10px] font-semibold text-blue-700", children: [question.points || 1, " \u0111i\u1EC3m"] }), question.skill && (_jsx(Badge, { variant: "outline", className: "border-gray-200 bg-gray-50 px-2 py-0.5 text-[10px] font-semibold text-gray-600", children: question.skill.toLowerCase() })), subQuestionCount && subQuestionCount > 1 && (_jsxs(Badge, { variant: "outline", className: "border-purple-200 bg-purple-50 px-2 py-0.5 text-[10px] font-semibold text-purple-700", children: [subQuestionCount, " c\u00E2u con"] }))] })] }, question.id));
257
- }) })) }), _jsx("div", { className: "border-t border-gray-100 bg-gray-50/50 px-4 py-2", children: _jsx("p", { className: "text-center text-xs text-gray-500", children: "Click \u0111\u1EC3 ch\u1ECDn c\u00E2u h\u1ECFi v\u00E0 t\u1EF1 \u0111\u1ED9ng \u0111i\u1EC1n v\u00E0o form" }) })] })] }));
258
- }
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useEffect as n,useMemo as r,useState as i}from"react";import{DropdownMenu as s,DropdownMenuContent as a,DropdownMenuItem as o,DropdownMenuTrigger as l}from"../../../components/ui/dropdown-menu";import{Input as c}from"../../../components/ui/input";import{Badge as d}from"../../../components/ui/badge";import{Loader2 as m,Search as u,Image as h,FileText as g,Grid3X3 as p,BookOpen as x,Library as f,Sparkles as N,Hash as b,BarChart3 as y,Lightbulb as v,CheckCircle2 as _}from"lucide-react";import{useQuery as w}from"@tanstack/react-query";import{ScrollArea as C}from"../../../components/ui/scroll-area";import{cn as E}from"../../../shared/lib/utils";const A=(e,t)=>{if(!e)return"";const n="string"==typeof e?e:String(e);return n.length<=t?n:`${n.substring(0,t)}...`},T=["LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER","LOOK_PICTURE_CHOOSE_CORRECT_ANSWER","LOOK_PICTURE_FILL_WORD_HINT","FILL_IN_BLANK","LABEL_THE_PICTURE","READ_AND_COLOR_OBJECTS","IMAGE_OBJECT_MATCHING","FILL_IN_BLANK"],O=["READ_PASSAGE_AND_ANSWER_QUESTIONS","READ_PASSAGE_AND_COMPLETE_STORY"],R=["FILL_MISSING_WORDS_IN_GRID"],I=e=>e?{LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER:"Nhìn tranh điền chỗ trống",LOOK_PICTURE_CHOOSE_CORRECT_ANSWER:"Nhìn tranh chọn đáp án",LOOK_PICTURE_FILL_WORD_HINT:"Nhìn tranh điền từ gợi ý",FILL_MISSING_WORDS_IN_GRID:"Điền chữ trong bảng",CHOOSE_THE_CORRECT_ANSWER:"Chọn đáp án đúng",LABEL_THE_PICTURE:"Gắn nhãn hình ảnh",READ_AND_COLOR_OBJECTS:"Đọc và tô màu",IMAGE_OBJECT_MATCHING:"Ghép hình ảnh - Đối tượng",WRITE_CORRECT_VERB_FORM:"Viết dạng động từ",FILL_IN_BLANK:"Điền vào chỗ trống",READ_PASSAGE_AND_ANSWER_QUESTIONS:"Đọc hiểu"}[e]||e.replace(/_/g," ").toLowerCase():"Chưa xác định";export const getQuestionDisplayText=e=>getContentDisplayText(e.content,e.type);export const getContentDisplayText=(e,t)=>{if(!e)return t||"Câu hỏi";if("string"==typeof e)return e;if("object"==typeof e){if(e.subQuestions&&Array.isArray(e.subQuestions)){const t=e.subQuestions[0];if(t?.question)return t.question}if(e.question)return e.question;if(e.word)return`Điền chữ: ${e.word}`;if(e.passage)return e.passageTitle||A(e.passage,60);if(e.grid&&e.rows&&e.columns)return`Lưới ${e.rows}x${e.columns}`;if(e.wordBank){return`Từ vựng: ${e.wordBank.map(e=>e.text||e).slice(0,3).join(", ")}${e.wordBank.length>3?"...":""}`}if(e.colorNodes||e.regionNodes){return`${e.regionNodes?.length||0} vùng tô màu`}if(e.contexts){const t=e.contexts[0];return t?.text?A(t.text,50):"Viết thư ngắn"}if(e.options&&Array.isArray(e.options))return e.questionText||e.question||"Câu hỏi trắc nghiệm";if(e.blanks){const t=e.blanks[0];return t?.text||e.sentence||"Điền vào chỗ trống"}if(e.instruction)return e.instruction;if(e.mainTitle)return e.mainTitle;if(e.title)return e.title;if(e.text)return e.text}return t||"Câu hỏi"};const L=e=>{switch(e?.toUpperCase()){case"EASY":return"bg-green-100 text-green-700 border-green-200";case"HARD":return"bg-red-100 text-red-700 border-red-200";default:return"bg-yellow-100 text-yellow-700 border-yellow-200"}},S=e=>{switch(e?.toUpperCase()){case"EASY":return"Dễ";case"HARD":return"Khó";default:return"TB"}};export function QuestionSearchDropdown({questionType:k,onSelect:D,selectedQuestionLabel:B,placeholder:j="Tìm câu hỏi từ ngân hàng",disabled:q=!1,buttonClassName:H,compact:F=!1,searchQuestions:K}){const[G,Q]=i(!1),[U,W]=i(""),[P,M]=i("");n(()=>{const e=setTimeout(()=>{M(U.trim())},300);return()=>clearTimeout(e)},[U]);const $=e=>({id:e.id,type:e.questionType,content:e.content,answer:e.correctAnswer,points:parseFloat(String(e.points??1))||1,difficulty:e.difficulty?.toUpperCase(),skill:e.skill||void 0,explanation:e.explanation||void 0,level:"A1",createdAt:e.createdAt,updatedAt:e.updatedAt,code:e.code,title:e.title||void 0,usageCount:e.usageCount}),{data:J,isFetching:V}=w({queryKey:["questionBanks","search",k,P],queryFn:async()=>K?K({questionType:k,keyword:P||void 0,page:1,size:10}):{data:[],meta:{totalItems:0}},enabled:G&&Boolean(k)&&Boolean(K)&&(P.length>0||!!k),staleTime:6e4,refetchOnWindowFocus:!1}),Y=r(()=>J?.data?J.data.map($):[],[J]),z=J?.meta?.totalItems||0,X=!V&&0===Y.length&&P.length>0,Z=!V&&J&&0===Y.length&&0===P.length,ee=!V&&!J&&0===Y.length&&0===P.length;r(()=>B?A(B,40):j,[j,B]);return t(s,{open:G,onOpenChange:e=>Q(!q&&e),children:[e(l,{asChild:!0,disabled:q,children:t("button",F?{type:"button",className:E("group inline-flex h-8 items-center gap-1.5 rounded-md border px-3 text-sm font-medium transition-all",B?"border-emerald-200 bg-emerald-50 text-emerald-700 hover:bg-emerald-100":"border-indigo-200 text-indigo-600 hover:bg-indigo-50 hover:text-indigo-700","focus:outline-none focus:ring-2 focus:ring-indigo-200 focus:ring-offset-1",q&&"cursor-not-allowed opacity-50",H),children:[e(B?_:f,{className:"h-4 w-4"}),B?"Đã chọn":"Ngân hàng"]}:{type:"button",className:E("group relative flex w-full items-center gap-3 rounded-xl border bg-white p-3 text-left shadow-sm transition-all",B?"border-emerald-200 bg-gradient-to-r from-emerald-50/50 to-teal-50/50":"border-gray-200 hover:border-indigo-200 hover:bg-gradient-to-r hover:from-indigo-50/30 hover:to-purple-50/30","focus:outline-none focus:ring-2 focus:ring-indigo-200 focus:ring-offset-1",q&&"cursor-not-allowed opacity-50",H),children:[e("div",{className:E("flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg transition-all",B?"bg-gradient-to-br from-emerald-500 to-teal-600 shadow-sm":"bg-gradient-to-br from-indigo-100 to-purple-100 group-hover:from-indigo-500 group-hover:to-purple-600 group-hover:shadow-sm"),children:B?e(_,{className:"h-5 w-5 text-white"}):e(f,{className:E("h-5 w-5 transition-colors","text-indigo-500 group-hover:text-white")})}),t("div",{className:"min-w-0 flex-1",children:[e("div",{className:"flex items-center gap-2",children:e("span",{className:E("text-xs font-medium uppercase tracking-wide",B?"text-emerald-600":"text-indigo-500"),children:B?"✓ Đã chọn từ ngân hàng":"Ngân hàng câu hỏi"})}),e("p",{className:E("mt-0.5 truncate text-sm",B?"font-medium text-gray-800":"text-gray-500"),children:B?A(B,55):"Nhấn để tìm và sử dụng câu hỏi có sẵn"})]}),e("div",{className:E("flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full transition-all",B?"bg-emerald-100 text-emerald-600":"bg-gray-100 text-gray-400 group-hover:bg-indigo-100 group-hover:text-indigo-600"),children:e(u,{className:"h-4 w-4"})})]})}),t(a,{className:"w-[520px] p-0",align:F?"end":"start",children:[e("div",{className:"border-b border-gray-100 bg-gradient-to-r from-indigo-50 to-purple-50 px-4 py-3",children:t("div",{className:"flex items-center gap-3",children:[e("div",{className:"flex h-9 w-9 items-center justify-center rounded-lg bg-gradient-to-br from-indigo-500 to-purple-600 shadow-sm",children:e(f,{className:"h-4 w-4 text-white"})}),t("div",{className:"flex-1",children:[e("h3",{className:"text-sm font-semibold text-gray-800",children:"Ngân hàng câu hỏi"}),e("p",{className:"text-xs text-gray-500",children:"Chọn câu hỏi có sẵn để điền nhanh vào form"})]})]})}),t("div",{className:"border-b border-gray-100 bg-gray-50/50 p-3",children:[t("div",{className:"relative",children:[e(u,{className:"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400"}),e(c,{placeholder:"Tìm theo mã, tiêu đề hoặc nội dung...",value:U,onChange:e=>W(e.target.value),autoFocus:!0,className:"border-gray-200 bg-white pl-10 pr-10 transition-all focus:border-indigo-300 focus:ring-indigo-200"}),V&&e(m,{className:"absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-indigo-500"})]}),t("div",{className:"mt-2 flex items-center justify-between",children:[e("div",{className:"flex items-center gap-2",children:e(d,{variant:"outline",className:"border-indigo-200 bg-indigo-50 text-indigo-700",children:I(k)})}),z>0&&t("span",{className:"text-xs text-gray-500",children:["Hiển thị ",Y.length,"/",z," kết quả"]})]})]}),e(C,{className:"h-80",children:ee?t("div",{className:"flex flex-col items-center justify-center p-8 text-center",children:[e("div",{className:"mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-gradient-to-br from-indigo-100 to-purple-100",children:e(N,{className:"h-8 w-8 text-indigo-500"})}),e("p",{className:"text-sm font-medium text-gray-700",children:"Tìm câu hỏi từ ngân hàng"}),e("p",{className:"mt-1 text-xs text-gray-500",children:"Nhập mã câu hỏi, tiêu đề hoặc từ khóa để tìm kiếm"}),e("div",{className:"mt-4 rounded-lg border border-blue-200 bg-blue-50 p-3",children:t("div",{className:"flex items-start gap-2",children:[e(v,{className:"mt-0.5 h-4 w-4 flex-shrink-0 text-blue-500"}),t("div",{className:"text-left text-xs text-blue-700",children:[e("p",{className:"font-medium",children:"Mẹo tìm kiếm nhanh:"}),t("ul",{className:"mt-1 list-inside list-disc space-y-0.5 text-blue-600",children:[e("li",{children:"Nhập mã câu hỏi (VD: M001)"}),e("li",{children:"Nhập tiêu đề hoặc một phần nội dung"}),e("li",{children:"Kết quả sẽ tự động cập nhật"})]})]})]})})]}):Z?t("div",{className:"flex flex-col items-center justify-center p-8 text-center",children:[e("div",{className:"mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-amber-100",children:e(f,{className:"h-8 w-8 text-amber-500"})}),e("p",{className:"text-sm font-medium text-gray-700",children:"Chưa có câu hỏi trong ngân hàng"}),t("p",{className:"mt-1 text-xs text-gray-500",children:["Ngân hàng câu hỏi chưa có dữ liệu cho loại: ",e("strong",{children:I(k)})]}),e("p",{className:"mt-2 text-xs text-gray-400",children:"Hãy thêm câu hỏi vào ngân hàng hoặc tạo câu hỏi mới"})]}):X?t("div",{className:"flex flex-col items-center justify-center p-8 text-center",children:[e("div",{className:"mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-gray-100",children:e(u,{className:"h-8 w-8 text-gray-400"})}),e("p",{className:"text-sm font-medium text-gray-700",children:"Không tìm thấy kết quả"}),t("p",{className:"mt-1 text-xs text-gray-500",children:['Thử tìm với từ khóa khác: "',P,'"']})]}):e("div",{className:"divide-y divide-gray-100 p-2",children:Y.map(n=>{const r=(e=>{const t=e.content;return t&&t.subQuestions&&Array.isArray(t.subQuestions)?t.subQuestions.length:null})(n);return t(o,{className:"flex cursor-pointer flex-col items-start gap-2 rounded-xl p-3 transition-all hover:bg-gradient-to-r hover:from-indigo-50 hover:to-purple-50 focus:bg-gradient-to-r focus:from-indigo-50 focus:to-purple-50",onSelect:()=>(e=>{D(e),Q(!1),W(""),M("")})(n),children:[t("div",{className:"flex w-full items-start justify-between gap-2",children:[t("div",{className:"flex items-center gap-2",children:[n.code&&t("div",{className:"flex items-center gap-1 rounded-md bg-gradient-to-r from-indigo-500 to-purple-500 px-2 py-0.5 text-xs font-bold text-white shadow-sm",children:[e(b,{className:"h-3 w-3"}),n.code]}),e("div",{className:"flex-shrink-0",children:(i=n.type,T.includes(i)?e(h,{className:"h-4 w-4 text-blue-500"}):O.includes(i)?e(x,{className:"h-4 w-4 text-green-500"}):R.includes(i)?e(p,{className:"h-4 w-4 text-purple-500"}):e(g,{className:"h-4 w-4 text-gray-500"}))})]}),void 0!==n.usageCount&&n.usageCount>0&&t("div",{className:"flex items-center gap-1 text-xs text-gray-500",title:"Số lần sử dụng",children:[e(y,{className:"h-3 w-3"}),n.usageCount]})]}),n.title&&e("p",{className:"text-sm font-semibold text-gray-800",children:A(n.title,60)}),e("p",{className:"text-xs text-gray-600",children:A(getQuestionDisplayText(n),80)}),t("div",{className:"flex flex-wrap items-center gap-1.5",children:[e(d,{variant:"outline",className:E("px-2 py-0.5 text-[10px] font-semibold",L(n.difficulty)),children:S(n.difficulty)}),t(d,{variant:"outline",className:"border-blue-200 bg-blue-50 px-2 py-0.5 text-[10px] font-semibold text-blue-700",children:[n.points||1," điểm"]}),n.skill&&e(d,{variant:"outline",className:"border-gray-200 bg-gray-50 px-2 py-0.5 text-[10px] font-semibold text-gray-600",children:n.skill.toLowerCase()}),r&&r>1&&t(d,{variant:"outline",className:"border-purple-200 bg-purple-50 px-2 py-0.5 text-[10px] font-semibold text-purple-700",children:[r," câu con"]})]})]},n.id);var i})})}),e("div",{className:"border-t border-gray-100 bg-gray-50/50 px-4 py-2",children:e("p",{className:"text-center text-xs text-gray-500",children:"Click để chọn câu hỏi và tự động điền vào form"})})]})]})}