@tinyweb_dev/oe-exam-sdk 0.1.1 → 0.1.2

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 (485) 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.js +1 -98
  4. package/dist/api/exam-questions.types.js +1 -1
  5. package/dist/api/exam-taking.js +1 -73
  6. package/dist/api/exam-taking.types.js +1 -1
  7. package/dist/api/index.js +1 -6
  8. package/dist/api/result-review.js +1 -50
  9. package/dist/api/result-review.types.js +1 -1
  10. package/dist/components/CueCardEditor.js +1 -58
  11. package/dist/components/common/ResolvedImage.js +1 -15
  12. package/dist/components/exams/CreateExamInfoForm.js +1 -35
  13. package/dist/components/exams/CreateExamPageContainer.js +1 -103
  14. package/dist/components/exams/ExamCreator.js +1 -89
  15. package/dist/components/exams/ExamPartTabs.js +1 -40
  16. package/dist/components/exams/ExamQuestionGrid.js +1 -18
  17. package/dist/components/exams/ExamQuestionsPageContainer.js +1 -90
  18. package/dist/components/exams/PartAudioUploader.js +1 -9
  19. package/dist/components/exams/TemplateSelector.js +1 -66
  20. package/dist/components/exams/api.js +1 -3
  21. package/dist/components/exams/create-exam.validation.js +1 -18
  22. package/dist/components/exams/exam-template.utils.js +1 -18
  23. package/dist/components/exams/index.js +1 -10
  24. package/dist/components/exams/take/ExamTakingPageContainer.js +1 -153
  25. package/dist/components/exams/take/GenericQuestionRenderer.js +1 -14
  26. package/dist/components/exams/take/exam-taking.utils.js +1 -88
  27. package/dist/components/exams/take/hooks/useSpeakingRecorder.js +1 -24
  28. package/dist/components/exams/take/index.js +1 -2
  29. package/dist/components/exams/take/types.js +1 -1
  30. package/dist/components/index.js +1 -42
  31. package/dist/components/questions/_shared/config/question-types.config.js +1 -333
  32. package/dist/components/questions/_shared/constants/color-palette.js +1 -21
  33. package/dist/components/questions/_shared/hooks/useAnswerGroupQuestionGroup.js +1 -105
  34. package/dist/components/questions/_shared/hooks/useBasicQuestionGroup.js +1 -222
  35. package/dist/components/questions/_shared/hooks/useCompareImagesGroup.js +1 -140
  36. package/dist/components/questions/_shared/hooks/useImageQuestionGroup.js +1 -123
  37. package/dist/components/questions/_shared/hooks/useInfoExchangeGroup.js +1 -50
  38. package/dist/components/questions/_shared/hooks/useQuestionFormState.js +1 -54
  39. package/dist/components/questions/_shared/hooks/useQuestionInitialization.js +1 -123
  40. package/dist/components/questions/_shared/hooks/useQuestionListGroup.js +1 -121
  41. package/dist/components/questions/_shared/hooks/useQuestionOnChange.js +1 -70
  42. package/dist/components/questions/_shared/hooks/useSceneQuestionGroup.js +1 -194
  43. package/dist/components/questions/_shared/index.js +1 -7
  44. package/dist/components/questions/_shared/types/answer-the-question.type.js +1 -1
  45. package/dist/components/questions/_shared/types/arrange-letters-into-words.type.js +1 -1
  46. package/dist/components/questions/_shared/types/choose-correct-adjective.type.js +1 -3
  47. package/dist/components/questions/_shared/types/color-region.config.js +1 -1
  48. package/dist/components/questions/_shared/types/fill-in-blank.type.js +1 -1
  49. package/dist/components/questions/_shared/types/fill-missing-words-in-grid.type.js +1 -1
  50. package/dist/components/questions/_shared/types/gn-speaking-interview.type.js +1 -1
  51. package/dist/components/questions/_shared/types/index.js +1 -12
  52. package/dist/components/questions/_shared/types/label-the-picture.type.js +1 -1
  53. package/dist/components/questions/_shared/types/listen-and-choose-from-answer-group.type.js +1 -1
  54. package/dist/components/questions/_shared/types/listen-and-choose-objects-in-scene.type.js +1 -1
  55. package/dist/components/questions/_shared/types/listen-and-drag-objects-into-scene.type.js +1 -1
  56. package/dist/components/questions/_shared/types/listen-and-speak-answer.type.js +1 -1
  57. package/dist/components/questions/_shared/types/listen-and-speak-compare-images.type.js +1 -1
  58. package/dist/components/questions/_shared/types/listen-and-speak-image-group.type.js +1 -1
  59. package/dist/components/questions/_shared/types/listen-and-speak-info-exchange.type.js +1 -1
  60. package/dist/components/questions/_shared/types/listen-and-speak-odd-one-out.type.js +1 -3
  61. package/dist/components/questions/_shared/types/listen-and-speak-question-list.type.js +1 -1
  62. package/dist/components/questions/_shared/types/listen-and-speak-with-story-images.type.js +1 -3
  63. package/dist/components/questions/_shared/types/listen-and-tick-answer.type.js +1 -1
  64. package/dist/components/questions/_shared/types/listening-drawline.type.js +1 -1
  65. package/dist/components/questions/_shared/types/look-and-choose-answer.type.js +1 -1
  66. package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.js +1 -1
  67. package/dist/components/questions/_shared/types/match-by-writing-answer.type.js +1 -1
  68. package/dist/components/questions/_shared/types/multiple-choice.type.js +1 -1
  69. package/dist/components/questions/_shared/types/question-group.type.js +1 -11
  70. package/dist/components/questions/_shared/types/read-and-color-objects.type.js +1 -1
  71. package/dist/components/questions/_shared/types/read-displayed-content.type.js +1 -1
  72. package/dist/components/questions/_shared/types/read-passage-and-answer-questions.type.js +1 -1
  73. package/dist/components/questions/_shared/types/speaking-describe-image.type.js +1 -1
  74. package/dist/components/questions/_shared/types/spontaneous-qa.type.js +1 -1
  75. package/dist/components/questions/_shared/types/word-fill-paragraph-with-options.type.js +1 -1
  76. package/dist/components/questions/_shared/types/word-fill-paragraph.type.js +1 -1
  77. package/dist/components/questions/_shared/types/word-fill-structured-form.type.js +1 -1
  78. package/dist/components/questions/_shared/types/word-ordering.type.js +1 -1
  79. package/dist/components/questions/_shared/types/write-a-short-letter.type.js +1 -1
  80. package/dist/components/questions/_shared/types/write-correct-verb-form.type.js +1 -3
  81. package/dist/components/questions/_shared/types/write-sentences.type.js +1 -1
  82. package/dist/components/questions/_shared/types/write-short-paragraph.type.js +1 -1
  83. package/dist/components/questions/_shared/utils/answer-builder.js +1 -79
  84. package/dist/components/questions/_shared/utils/createColorRegionRegistration.js +1 -39
  85. package/dist/components/questions/_shared/utils/id-generator.js +1 -3
  86. package/dist/components/questions/_shared/utils/question-validation.js +1 -21
  87. package/dist/components/questions/components/ColorNode.js +1 -85
  88. package/dist/components/questions/components/ColorRegionClient.js +1 -545
  89. package/dist/components/questions/components/ColorRegionCreator.js +1 -420
  90. package/dist/components/questions/components/ColorRegionNode.js +1 -59
  91. package/dist/components/questions/components/CreatorGuide.js +1 -103
  92. package/dist/components/questions/components/NameNode.js +1 -26
  93. package/dist/components/questions/components/QuestionBankOption.js +1 -46
  94. package/dist/components/questions/components/QuestionBasicInfoForm.js +1 -9
  95. package/dist/components/questions/components/QuestionCommonFields.js +1 -33
  96. package/dist/components/questions/components/QuestionSearchDropdown.js +1 -258
  97. package/dist/components/questions/components/QuestionTypeSelector.js +1 -32
  98. package/dist/components/questions/components/QuestionTypeSpecificForms.js +1 -6
  99. package/dist/components/questions/components/RegionNode.js +1 -94
  100. package/dist/components/questions/components/index.js +1 -14
  101. package/dist/components/questions/creator/QuestionCreator.js +1 -90
  102. package/dist/components/questions/creator/QuestionGroupCreator.js +1 -119
  103. package/dist/components/questions/creator/dedicated-component-router.js +1 -79
  104. package/dist/components/questions/creator/index.js +1 -3
  105. package/dist/components/questions/creator/question-type-registry.js +1 -80
  106. package/dist/components/questions/groups/ArticlesGroupCard.js +1 -121
  107. package/dist/components/questions/groups/BasicQuestionGroupCard.js +1 -50
  108. package/dist/components/questions/groups/DocumentGroupCard.js +1 -114
  109. package/dist/components/questions/groups/MatchAnswerGroupCard.js +1 -25
  110. package/dist/components/questions/index.js +1 -10
  111. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +1 -37
  112. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionCreator.js +1 -351
  113. package/dist/components/questions/types/answer-the-question/register.js +1 -67
  114. package/dist/components/questions/types/answer-the-question/transform.js +1 -36
  115. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +1 -141
  116. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsCreator.js +1 -118
  117. package/dist/components/questions/types/arrange-letters-into-words/index.js +1 -2
  118. package/dist/components/questions/types/arrange-letters-into-words/register.js +1 -4
  119. package/dist/components/questions/types/arrange-letters-into-words/transform.js +1 -24
  120. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +1 -64
  121. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js +1 -169
  122. package/dist/components/questions/types/choose-correct-adjective/index.js +1 -2
  123. package/dist/components/questions/types/choose-correct-adjective/register.js +1 -55
  124. package/dist/components/questions/types/choose-correct-adjective/transform.js +1 -16
  125. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +1 -131
  126. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +1 -581
  127. package/dist/components/questions/types/choose-the-correct-answer/index.js +1 -2
  128. package/dist/components/questions/types/choose-the-correct-answer/register.js +1 -101
  129. package/dist/components/questions/types/choose-the-correct-answer/transform.js +1 -43
  130. package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +1 -275
  131. package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +1 -448
  132. package/dist/components/questions/types/fill-in-blank/index.js +1 -2
  133. package/dist/components/questions/types/fill-in-blank/register.js +1 -138
  134. package/dist/components/questions/types/fill-in-blank/transform.js +1 -59
  135. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +1 -117
  136. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridCreator.js +1 -671
  137. package/dist/components/questions/types/fill-missing-words-in-grid/index.js +1 -2
  138. package/dist/components/questions/types/fill-missing-words-in-grid/register.js +1 -37
  139. package/dist/components/questions/types/fill-missing-words-in-grid/transform.js +1 -15
  140. package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.js +1 -262
  141. package/dist/components/questions/types/gn-speaking-interview/register.js +1 -121
  142. package/dist/components/questions/types/gn-speaking-interview/transform.js +1 -48
  143. package/dist/components/questions/types/image-object-matching/ImageObjectMatchingClient.js +1 -16
  144. package/dist/components/questions/types/image-object-matching/ImageObjectMatchingCreator.js +1 -27
  145. package/dist/components/questions/types/image-object-matching/index.js +1 -2
  146. package/dist/components/questions/types/image-object-matching/register.js +1 -3
  147. package/dist/components/questions/types/image-object-matching/transform.js +1 -2
  148. package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +1 -102
  149. package/dist/components/questions/types/label-the-picture/LabelThePictureCreator.js +1 -344
  150. package/dist/components/questions/types/label-the-picture/index.js +1 -2
  151. package/dist/components/questions/types/label-the-picture/register.js +1 -54
  152. package/dist/components/questions/types/label-the-picture/transform.js +1 -28
  153. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +1 -78
  154. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupCreator.js +1 -232
  155. package/dist/components/questions/types/listen-and-choose-from-answer-group/index.js +1 -2
  156. package/dist/components/questions/types/listen-and-choose-from-answer-group/register.js +1 -82
  157. package/dist/components/questions/types/listen-and-choose-from-answer-group/transform.js +1 -27
  158. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneClient.js +1 -70
  159. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneCreator.js +1 -386
  160. package/dist/components/questions/types/listen-and-choose-objects-in-scene/index.js +1 -2
  161. package/dist/components/questions/types/listen-and-choose-objects-in-scene/register.js +1 -100
  162. package/dist/components/questions/types/listen-and-choose-objects-in-scene/transform.js +1 -33
  163. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneClient.js +1 -106
  164. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneCreator.js +1 -457
  165. package/dist/components/questions/types/listen-and-drag-objects-into-scene/index.js +1 -2
  166. package/dist/components/questions/types/listen-and-drag-objects-into-scene/register.js +1 -110
  167. package/dist/components/questions/types/listen-and-drag-objects-into-scene/transform.js +1 -35
  168. package/dist/components/questions/types/listen-and-speak-answer/ArrowIndicator.js +1 -8
  169. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +1 -22
  170. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerCreator.js +1 -291
  171. package/dist/components/questions/types/listen-and-speak-answer/index.js +1 -2
  172. package/dist/components/questions/types/listen-and-speak-answer/register.js +1 -84
  173. package/dist/components/questions/types/listen-and-speak-answer/transform.js +1 -27
  174. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +1 -32
  175. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesCreator.js +1 -295
  176. package/dist/components/questions/types/listen-and-speak-compare-images/register.js +1 -79
  177. package/dist/components/questions/types/listen-and-speak-compare-images/transform.js +1 -27
  178. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +1 -34
  179. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupCreator.js +1 -285
  180. package/dist/components/questions/types/listen-and-speak-image-group/register.js +1 -81
  181. package/dist/components/questions/types/listen-and-speak-image-group/transform.js +1 -26
  182. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +1 -38
  183. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeCreator.js +1 -385
  184. package/dist/components/questions/types/listen-and-speak-info-exchange/register.js +1 -87
  185. package/dist/components/questions/types/listen-and-speak-info-exchange/transform.js +1 -32
  186. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +1 -26
  187. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutCreator.js +1 -247
  188. package/dist/components/questions/types/listen-and-speak-odd-one-out/register.js +1 -59
  189. package/dist/components/questions/types/listen-and-speak-odd-one-out/transform.js +1 -18
  190. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +1 -26
  191. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListCreator.js +1 -256
  192. package/dist/components/questions/types/listen-and-speak-question-list/register.js +1 -81
  193. package/dist/components/questions/types/listen-and-speak-question-list/transform.js +1 -26
  194. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +1 -26
  195. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesCreator.js +1 -230
  196. package/dist/components/questions/types/listen-and-speak-with-story-images/register.js +1 -56
  197. package/dist/components/questions/types/listen-and-speak-with-story-images/transform.js +1 -16
  198. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.js +1 -72
  199. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.js +1 -230
  200. package/dist/components/questions/types/look-picture-choose-correct-answer/index.js +1 -1
  201. package/dist/components/questions/types/look-picture-choose-correct-answer/register.js +1 -66
  202. package/dist/components/questions/types/look-picture-choose-correct-answer/transform.js +1 -42
  203. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.js +1 -96
  204. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.js +1 -238
  205. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.js +1 -2
  206. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.js +1 -76
  207. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.js +1 -19
  208. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.js +1 -134
  209. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.js +1 -617
  210. package/dist/components/questions/types/look-picture-fill-word-hint/index.js +1 -2
  211. package/dist/components/questions/types/look-picture-fill-word-hint/register.js +1 -82
  212. package/dist/components/questions/types/look-picture-fill-word-hint/transform.js +1 -29
  213. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +1 -38
  214. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerCreator.js +1 -359
  215. package/dist/components/questions/types/match-by-writing-answer/index.js +1 -3
  216. package/dist/components/questions/types/match-by-writing-answer/register.js +1 -58
  217. package/dist/components/questions/types/match-by-writing-answer/transform.js +1 -61
  218. package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsClient.js +1 -16
  219. package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsCreator.js +1 -23
  220. package/dist/components/questions/types/read-and-color-objects/index.js +1 -2
  221. package/dist/components/questions/types/read-and-color-objects/register.js +1 -3
  222. package/dist/components/questions/types/read-and-color-objects/transform.js +1 -36
  223. package/dist/components/questions/types/read-displayed-content/ReadDisplayedContentCreator.js +1 -125
  224. package/dist/components/questions/types/read-displayed-content/register.js +1 -64
  225. package/dist/components/questions/types/read-displayed-content/transform.js +1 -12
  226. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +1 -64
  227. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsCreator.js +1 -511
  228. package/dist/components/questions/types/read-passage-and-answer-questions/index.js +1 -2
  229. package/dist/components/questions/types/read-passage-and-answer-questions/register.js +1 -58
  230. package/dist/components/questions/types/read-passage-and-answer-questions/transform.js +1 -28
  231. package/dist/components/questions/types/speaking-conversation/SpeakingConversationCreator.js +1 -373
  232. package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +1 -41
  233. package/dist/components/questions/types/speaking-conversation/register.js +1 -110
  234. package/dist/components/questions/types/speaking-conversation/transform.js +1 -34
  235. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +1 -74
  236. package/dist/components/questions/types/speaking-cue-card/register.js +1 -52
  237. package/dist/components/questions/types/speaking-cue-card/transform.js +1 -12
  238. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +1 -10
  239. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageCreator.js +1 -161
  240. package/dist/components/questions/types/speaking-describe-image/index.js +1 -2
  241. package/dist/components/questions/types/speaking-describe-image/register.js +1 -69
  242. package/dist/components/questions/types/speaking-describe-image/transform.js +1 -16
  243. package/dist/components/questions/types/spontaneous-qa/SpontaneousQACreator.js +1 -234
  244. package/dist/components/questions/types/spontaneous-qa/register.js +1 -93
  245. package/dist/components/questions/types/spontaneous-qa/transform.js +1 -34
  246. package/dist/components/questions/types/true-false/TrueFalseClient.js +1 -75
  247. package/dist/components/questions/types/true-false/TrueFalseCreator.js +1 -244
  248. package/dist/components/questions/types/true-false/index.js +1 -2
  249. package/dist/components/questions/types/true-false/register.js +1 -77
  250. package/dist/components/questions/types/true-false/transform.js +1 -32
  251. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +1 -233
  252. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphCreator.js +1 -631
  253. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphWrapper.js +1 -28
  254. package/dist/components/questions/types/word-fill-paragraph/index.js +1 -2
  255. package/dist/components/questions/types/word-fill-paragraph/register.js +1 -136
  256. package/dist/components/questions/types/word-fill-paragraph/transform.js +1 -56
  257. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -138
  258. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +1 -261
  259. package/dist/components/questions/types/word-fill-structured-form/index.js +1 -2
  260. package/dist/components/questions/types/word-fill-structured-form/register.js +1 -67
  261. package/dist/components/questions/types/word-fill-structured-form/transform.js +1 -40
  262. package/dist/components/questions/types/word-ordering/WordOrderingClient.js +1 -84
  263. package/dist/components/questions/types/word-ordering/WordOrderingCreator.js +1 -192
  264. package/dist/components/questions/types/word-ordering/index.js +1 -2
  265. package/dist/components/questions/types/word-ordering/register.js +1 -46
  266. package/dist/components/questions/types/word-ordering/transform.js +1 -24
  267. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +1 -98
  268. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +1 -320
  269. package/dist/components/questions/types/write-a-short-letter/index.js +1 -2
  270. package/dist/components/questions/types/write-a-short-letter/register.js +1 -68
  271. package/dist/components/questions/types/write-a-short-letter/transform.js +1 -25
  272. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +1 -61
  273. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js +1 -196
  274. package/dist/components/questions/types/write-correct-verb-form/index.js +1 -2
  275. package/dist/components/questions/types/write-correct-verb-form/register.js +1 -62
  276. package/dist/components/questions/types/write-correct-verb-form/transform.js +1 -17
  277. package/dist/components/questions/types/write-sentences/WriteSentencesClient.js +1 -22
  278. package/dist/components/questions/types/write-sentences/WriteSentencesCreator.js +1 -174
  279. package/dist/components/questions/types/write-sentences/index.js +1 -2
  280. package/dist/components/questions/types/write-sentences/register.js +1 -58
  281. package/dist/components/questions/types/write-sentences/transform.js +1 -28
  282. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphClient.js +1 -96
  283. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphCreator.js +1 -161
  284. package/dist/components/questions/types/write-short-paragraph/index.js +1 -2
  285. package/dist/components/questions/types/write-short-paragraph/register.js +1 -4
  286. package/dist/components/questions/types/write-short-paragraph/transform.js +1 -21
  287. package/dist/components/questions/viewer/QuestionGroupViewer.js +1 -36
  288. package/dist/components/questions/viewer/QuestionViewer.js +1 -446
  289. package/dist/components/questions/viewer/index.js +1 -2
  290. package/dist/components/results/ResultReviewPageContainer.js +1 -98
  291. package/dist/components/results/ReviewQuestionRenderer.js +1 -72
  292. package/dist/components/results/index.js +1 -2
  293. package/dist/components/results/result-review.utils.js +1 -6
  294. package/dist/components/results/review-data.js +1 -150
  295. package/dist/components/results/review-renderer.utils.js +1 -97
  296. package/dist/components/results/review-types.js +1 -1
  297. package/dist/components/themes/cambridge-yle/CambridgeYleAudioPlayer.js +1 -138
  298. package/dist/components/themes/cambridge-yle/CambridgeYleBottomNav.js +1 -12
  299. package/dist/components/themes/cambridge-yle/CambridgeYleExamLayout.js +1 -18
  300. package/dist/components/themes/cambridge-yle/CambridgeYleExampleText.js +1 -11
  301. package/dist/components/themes/cambridge-yle/CambridgeYleHeader.js +1 -11
  302. package/dist/components/themes/cambridge-yle/CambridgeYleInstructionBanner.js +1 -9
  303. package/dist/components/themes/cambridge-yle/CambridgeYleNavButton.js +1 -13
  304. package/dist/components/themes/cambridge-yle/CambridgeYlePartBanner.js +1 -8
  305. package/dist/components/themes/cambridge-yle/CambridgeYleProgressBar.js +1 -6
  306. package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCard.js +1 -5
  307. package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCardFullWidth.js +1 -9
  308. package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.js +1 -41
  309. package/dist/components/themes/cambridge-yle/CambridgeYleTimer.js +1 -25
  310. package/dist/components/themes/cambridge-yle/index.js +1 -13
  311. package/dist/components/themes/english-certification/EcAnswerTheQuestion.js +1 -24
  312. package/dist/components/themes/english-certification/EcMatchByWritingAnswer.js +1 -88
  313. package/dist/components/themes/english-certification/EcWordFillParagraph.js +1 -55
  314. package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -156
  315. package/dist/components/themes/english-certification/EcWritingTask.js +1 -34
  316. package/dist/components/themes/english-certification/EnglishCertificationAudioPlayer.js +1 -114
  317. package/dist/components/themes/english-certification/EnglishCertificationBrand.js +1 -11
  318. package/dist/components/themes/english-certification/EnglishCertificationExamLayout.js +1 -21
  319. package/dist/components/themes/english-certification/EnglishCertificationFlagButton.js +1 -15
  320. package/dist/components/themes/english-certification/EnglishCertificationFooterBar.js +1 -19
  321. package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.js +1 -148
  322. package/dist/components/themes/english-certification/EnglishCertificationHeader.js +1 -31
  323. package/dist/components/themes/english-certification/EnglishCertificationNavigationPanel.js +1 -71
  324. package/dist/components/themes/english-certification/EnglishCertificationOptionSelector.js +1 -33
  325. package/dist/components/themes/english-certification/EnglishCertificationPassagePanel.js +1 -16
  326. package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.js +1 -22
  327. package/dist/components/themes/english-certification/EnglishCertificationQuestionItem.js +1 -37
  328. package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -72
  329. package/dist/components/themes/english-certification/EnglishCertificationReadingSection.js +1 -90
  330. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestion.js +1 -18
  331. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js +1 -29
  332. package/dist/components/themes/english-certification/english-certification-theme.js +1 -58
  333. package/dist/components/themes/english-certification/grouped-question-utils.js +1 -218
  334. package/dist/components/themes/english-certification/index.js +1 -21
  335. package/dist/components/themes/index.js +1 -6
  336. package/dist/components/themes/summer-sky/SummerSkyAudioPlayer.js +1 -170
  337. package/dist/components/themes/summer-sky/SummerSkyLayout.js +1 -221
  338. package/dist/components/themes/summer-sky/SummerSkySubmitModal.js +1 -18
  339. package/dist/components/themes/summer-sky/SummerSkyWaitingRoom.js +1 -194
  340. package/dist/components/themes/types.js +1 -1
  341. package/dist/components/ui/alert-dialog.js +1 -26
  342. package/dist/components/ui/alert.js +1 -22
  343. package/dist/components/ui/avatar.js +1 -12
  344. package/dist/components/ui/badge.js +1 -38
  345. package/dist/components/ui/button.js +1 -35
  346. package/dist/components/ui/calendar.js +1 -76
  347. package/dist/components/ui/card.js +1 -16
  348. package/dist/components/ui/carousel.js +1 -91
  349. package/dist/components/ui/checkbox.js +1 -9
  350. package/dist/components/ui/collapsible.js +1 -13
  351. package/dist/components/ui/command.js +1 -34
  352. package/dist/components/ui/confirm-dialog.js +1 -49
  353. package/dist/components/ui/dialog.js +1 -23
  354. package/dist/components/ui/drawer.js +1 -35
  355. package/dist/components/ui/dropdown-menu.js +1 -33
  356. package/dist/components/ui/file-upload.js +1 -155
  357. package/dist/components/ui/form.js +1 -62
  358. package/dist/components/ui/hover-card.js +1 -10
  359. package/dist/components/ui/image-preview.js +1 -29
  360. package/dist/components/ui/input.js +1 -8
  361. package/dist/components/ui/label.js +1 -9
  362. package/dist/components/ui/language-switcher.js +1 -15
  363. package/dist/components/ui/multi-select.js +1 -90
  364. package/dist/components/ui/points-input.js +1 -33
  365. package/dist/components/ui/popover.js +1 -26
  366. package/dist/components/ui/progress.js +1 -16
  367. package/dist/components/ui/radio-group.js +1 -12
  368. package/dist/components/ui/scroll-area.js +1 -11
  369. package/dist/components/ui/select.js +1 -38
  370. package/dist/components/ui/separator.js +1 -8
  371. package/dist/components/ui/sheet.js +1 -40
  372. package/dist/components/ui/single-select.js +1 -76
  373. package/dist/components/ui/skeleton.js +1 -6
  374. package/dist/components/ui/switch.js +1 -8
  375. package/dist/components/ui/table.js +1 -20
  376. package/dist/components/ui/tabs.js +1 -17
  377. package/dist/components/ui/textarea.js +1 -8
  378. package/dist/components/ui/tooltip.js +1 -11
  379. package/dist/index.js +1 -19
  380. package/dist/mcp/config.js +1 -32
  381. package/dist/mcp/http-client.js +1 -48
  382. package/dist/mcp/index.js +1 -29
  383. package/dist/mcp/tools/_helpers.js +1 -25
  384. package/dist/mcp/tools/exams.js +1 -439
  385. package/dist/mcp/tools/index.js +1 -6
  386. package/dist/mcp/tools/results.js +1 -19
  387. package/dist/shared/constants/ApiConstant.js +1 -276
  388. package/dist/shared/constants/QueryKeyConstant.js +1 -112
  389. package/dist/shared/constants/exam-level.enum.js +1 -41
  390. package/dist/shared/constants/landings/placement-test.constants.js +1 -431
  391. package/dist/shared/constants/question-skills.js +1 -267
  392. package/dist/shared/constants/routes.js +1 -81
  393. package/dist/shared/index.js +1 -7
  394. package/dist/shared/lib/hooks/index.js +1 -10
  395. package/dist/shared/lib/hooks/useAlertDialog.js +1 -57
  396. package/dist/shared/lib/hooks/useAudioPlayCounter.js +1 -30
  397. package/dist/shared/lib/hooks/useAudioPreview.js +1 -81
  398. package/dist/shared/lib/hooks/useAudioUpload.js +1 -24
  399. package/dist/shared/lib/hooks/useConfirmDialog.js +1 -89
  400. package/dist/shared/lib/hooks/useDebouncedCallback.js +1 -32
  401. package/dist/shared/lib/hooks/useDelayedAutoPlay.js +1 -12
  402. package/dist/shared/lib/hooks/useFileUpload.js +1 -24
  403. package/dist/shared/lib/hooks/useImageUrl.js +1 -5
  404. package/dist/shared/lib/hooks/usePresignedFileUrl.js +1 -10
  405. package/dist/shared/lib/hooks/useReactHookForm.js +1 -31
  406. package/dist/shared/lib/hooks/useToast.js +1 -62
  407. package/dist/shared/lib/i18n/index.js +1 -54
  408. package/dist/shared/lib/i18n/messages/en/admin.js +1 -2104
  409. package/dist/shared/lib/i18n/messages/en/auth.js +1 -86
  410. package/dist/shared/lib/i18n/messages/en/common.js +1 -140
  411. package/dist/shared/lib/i18n/messages/en/file-upload.js +1 -18
  412. package/dist/shared/lib/i18n/messages/en/student.js +1 -133
  413. package/dist/shared/lib/i18n/messages/en/terms.js +1 -37
  414. package/dist/shared/lib/i18n/messages/en.js +1 -15
  415. package/dist/shared/lib/i18n/messages/vi/admin.js +1 -2104
  416. package/dist/shared/lib/i18n/messages/vi/auth.js +1 -86
  417. package/dist/shared/lib/i18n/messages/vi/common.js +1 -140
  418. package/dist/shared/lib/i18n/messages/vi/file-upload.js +1 -18
  419. package/dist/shared/lib/i18n/messages/vi/student.js +1 -133
  420. package/dist/shared/lib/i18n/messages/vi/terms.js +1 -37
  421. package/dist/shared/lib/i18n/messages/vi.js +1 -15
  422. package/dist/shared/lib/i18n/types.js +1 -1
  423. package/dist/shared/lib/stores/examQuestionStore.js +1 -212
  424. package/dist/shared/lib/stores/localeStore.js +1 -10
  425. package/dist/shared/lib/utils/public-page.js +1 -44
  426. package/dist/shared/lib/utils/question-transform-types.js +1 -1
  427. package/dist/shared/lib/utils/question-transform.js +1 -174
  428. package/dist/shared/lib/utils.js +1 -168
  429. package/dist/shared/lib/validation/choose-correct-answer.validation.js +1 -111
  430. package/dist/shared/lib/validation/label-the-picture.validation.js +1 -19
  431. package/dist/shared/lib/validation/listen-and-choose-from-answer-group.validation.js +1 -46
  432. package/dist/shared/lib/validation/listen-and-choose-objects-in-scene.validation.js +1 -21
  433. package/dist/shared/lib/validation/listen-and-drag-objects-into-scene.validation.js +1 -34
  434. package/dist/shared/lib/validation/listen-and-speak-answer.validation.js +1 -40
  435. package/dist/shared/lib/validation/listen-and-speak-compare-images.validation.js +1 -45
  436. package/dist/shared/lib/validation/listen-and-speak-image-group.validation.js +1 -19
  437. package/dist/shared/lib/validation/listen-and-speak-info-exchange.validation.js +1 -39
  438. package/dist/shared/lib/validation/listen-and-speak-odd-one-out.validation.js +1 -32
  439. package/dist/shared/lib/validation/listen-and-speak-question-list.validation.js +1 -19
  440. package/dist/shared/lib/validation/listen-and-speak-with-story-images.validation.js +1 -28
  441. package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.js +1 -12
  442. package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.js +1 -47
  443. package/dist/shared/lib/validation/read-and-color-objects.validation.js +1 -29
  444. package/dist/shared/lib/validation/read-displayed-content.validation.js +1 -28
  445. package/dist/shared/lib/validation/speaking-conversation.validation.js +1 -75
  446. package/dist/shared/lib/validation/speaking-describe-image.validation.js +1 -31
  447. package/dist/shared/lib/validation/spontaneous-qa.validation.js +1 -48
  448. package/dist/shared/lib/validation/word-fill-paragraph-default.validation.js +1 -38
  449. package/dist/shared/lib/validation/word-fill-paragraph-with-options.validation.js +1 -39
  450. package/dist/shared/lib/validation/word-fill-paragraph.validation.js +1 -43
  451. package/dist/shared/lib/validation/word-ordering.validation.js +1 -33
  452. package/dist/shared/types/branch.types.js +1 -6
  453. package/dist/shared/types/common.types.js +1 -50
  454. package/dist/shared/types/entities/exam-schedule.types.js +1 -5
  455. package/dist/shared/types/entities/exam.types.js +1 -1
  456. package/dist/shared/types/entities/question.types.js +1 -4
  457. package/dist/shared/types/entities/result.types.js +1 -4
  458. package/dist/shared/types/entities/user.types.js +1 -4
  459. package/dist/shared/types/exam-taking.types.js +1 -2
  460. package/dist/shared/types/history.types.js +1 -34
  461. package/dist/shared/types/index.js +1 -1
  462. package/dist/shared/types/questions/choose-correct-adjective.js +1 -4
  463. package/dist/shared/types/questions/choose-the-correct-answer.js +1 -9
  464. package/dist/shared/types/questions/fill-missing-words-in-grid.js +1 -11
  465. package/dist/shared/types/questions/index.js +1 -40
  466. package/dist/shared/types/questions/listen-and-speak-answer.js +1 -1
  467. package/dist/shared/types/questions/listen-and-speak-compare-images.js +1 -1
  468. package/dist/shared/types/questions/listen-and-speak-image-group.js +1 -1
  469. package/dist/shared/types/questions/listen-and-speak-info-exchange.js +1 -3
  470. package/dist/shared/types/questions/listen-and-speak-odd-one-out.js +1 -3
  471. package/dist/shared/types/questions/listen-and-speak-question-list.js +1 -1
  472. package/dist/shared/types/questions/listen-and-speak-with-story-images.js +1 -3
  473. package/dist/shared/types/questions/look-picture-choose-correct-answer.js +1 -5
  474. package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.js +1 -9
  475. package/dist/shared/types/questions/look-picture-fill-word-hint.js +1 -7
  476. package/dist/shared/types/questions/read-displayed-content.js +1 -1
  477. package/dist/shared/types/questions/speaking-conversation.js +1 -7
  478. package/dist/shared/types/questions/speaking-describe-image.js +1 -1
  479. package/dist/shared/types/questions/spontaneous-qa.js +1 -1
  480. package/dist/shared/types/questions/write-correct-verb-form.js +1 -12
  481. package/dist/shared/types/role.types.js +1 -1
  482. package/dist/shared/types/structure-management.js +1 -28
  483. package/dist/shared/types/student.types.js +1 -54
  484. package/dist/shared/types/teacher-dashboard-rooms.js +1 -2
  485. package/package.json +4 -2
@@ -1,581 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { ImagePreview } from '../../../../components/ui/image-preview';
4
- import { useState, useRef, useEffect, useMemo } from 'react';
5
- import { Button } from '../../../../components/ui/button';
6
- import { Label } from '../../../../components/ui/label';
7
- import { Input } from '../../../../components/ui/input';
8
- import { Textarea } from '../../../../components/ui/textarea';
9
- import { PointsInput } from '../../../../components/ui/points-input';
10
- import { Card, CardContent, CardHeader, CardTitle } from '../../../../components/ui/card';
11
- import { RadioGroup } from '../../../../components/ui/radio-group';
12
- import { Switch } from '../../../../components/ui/switch';
13
- import { usePresignedFileUrl, useDebouncedCallback } from '../../../../shared/lib/hooks';
14
- import { useReactHookForm } from '../../../../shared/lib/hooks/useReactHookForm';
15
- import { Pencil, Eye, Plus, Trash2, HelpCircle, CheckCircle2, Lightbulb, MessageSquare, ImageIcon, Type, Users, BookOpen, Star, ListChecks } from 'lucide-react';
16
- import { FileUpload } from '../../../../components/ui/file-upload';
17
- import { ChooseTheCorrectAnswerClient } from './ChooseTheCorrectAnswerClient';
18
- import { chooseCorrectAnswerFormSchema, } from '../../../../shared/lib/validation/choose-correct-answer.validation';
19
- import { BasicQuestionGroupCard } from '../../groups/BasicQuestionGroupCard';
20
- import { ArticlesGroupCard } from '../../groups/ArticlesGroupCard';
21
- import { DocumentGroupCard } from '../../groups/DocumentGroupCard';
22
- import { useBasicQuestionGroup } from '../../_shared/hooks/useBasicQuestionGroup';
23
- import { z } from 'zod';
24
- // Helper component to resolve presigned URL for option image preview (same pattern as Client's OptionImage)
25
- function OptionImagePreview({ src, alt }) {
26
- const { previewUrl, isLoading } = usePresignedFileUrl(src);
27
- if (isLoading) {
28
- return (_jsx("div", { className: "flex h-24 w-full max-w-[200px] items-center justify-center rounded-lg border border-gray-200 bg-gray-50", children: _jsx("div", { className: "h-5 w-5 animate-spin rounded-full border-2 border-gray-200 border-t-blue-500" }) }));
29
- }
30
- return (_jsx("div", { className: "relative h-24 w-full max-w-[200px] overflow-hidden rounded-lg border border-gray-200 bg-gray-50", children: _jsx("img", { src: previewUrl || src, alt: alt, className: "h-full w-full object-contain", onError: (e) => {
31
- const target = e.target;
32
- target.onerror = null;
33
- target.src = '/images/placeholder-image.svg';
34
- } }) }));
35
- }
36
- function ChooseTheCorrectAnswerCreatorContent({ initialData, onSave, onCancel, onChange, externalErrors, optionCount = 4, optionMode, defaultValue, defaultQuestion, viewMode, onUnsavedChangesChange, validationRef, groups, questionIndexInPart = 0, partId = '', questionConfig, groupType, groupConfig, articleCount = 0, multipleAnswers, headerExtra, }) {
37
- console.log('=== viewMode ===', viewMode);
38
- // Use react-hook-form with Zod validation
39
- // initialData can be in API format (content.question, correctAnswer.answer) or flat format
40
- // Cast to any to support both formats
41
- const apiData = initialData;
42
- const formSchema = useMemo(() => {
43
- return chooseCorrectAnswerFormSchema.superRefine((data, ctx) => {
44
- if (viewMode === 'CONVERSATION') {
45
- if (!data.askerName?.trim()) {
46
- ctx.addIssue({
47
- code: z.ZodIssueCode.custom,
48
- message: 'Vui lòng nhập tên người hỏi!',
49
- path: ['askerName'],
50
- });
51
- }
52
- if (!data.answererName?.trim()) {
53
- ctx.addIssue({
54
- code: z.ZodIssueCode.custom,
55
- message: 'Vui lòng nhập tên người trả lời!',
56
- path: ['answererName'],
57
- });
58
- }
59
- }
60
- });
61
- }, [viewMode]);
62
- const rawCorrectAnswer = apiData?.correctAnswer;
63
- const normalizedInitialCorrectAnswer = Array.isArray(rawCorrectAnswer)
64
- ? rawCorrectAnswer
65
- : (typeof rawCorrectAnswer === 'object' && rawCorrectAnswer !== null)
66
- ? (rawCorrectAnswer?.answer ?? -1)
67
- : (rawCorrectAnswer ?? -1);
68
- const initialMultipleAnswers = Boolean(apiData?.multipleAnswers
69
- ?? apiData?.content?.multipleAnswers
70
- ?? apiData?.questionGroup?.payload?.multipleAnswers
71
- ?? Array.isArray(normalizedInitialCorrectAnswer));
72
- const form = useReactHookForm({
73
- defaultValues: {
74
- // Support both API format (content.question) and flat format (question)
75
- question: apiData?.content?.question || apiData?.question || defaultQuestion || '',
76
- optionType: apiData?.content?.optionType || apiData?.optionType || 'text',
77
- options: (apiData?.content?.options || apiData?.options)?.length > 0
78
- ? (apiData?.content?.options || apiData?.options)
79
- : defaultValue && defaultValue.length > 0
80
- ? defaultValue
81
- : Array.from({ length: optionCount }, () => ''),
82
- // Support both API format (correctAnswer.answer) and flat format (correctAnswer as number/number[])
83
- correctAnswer: initialMultipleAnswers
84
- ? (Array.isArray(normalizedInitialCorrectAnswer)
85
- ? normalizedInitialCorrectAnswer
86
- : normalizedInitialCorrectAnswer === -1
87
- ? []
88
- : [normalizedInitialCorrectAnswer])
89
- : (Array.isArray(normalizedInitialCorrectAnswer)
90
- ? (normalizedInitialCorrectAnswer[0] ?? -1)
91
- : normalizedInitialCorrectAnswer),
92
- multipleAnswers: initialMultipleAnswers || Boolean(multipleAnswers),
93
- imageUrl: apiData?.content?.imageUrl || apiData?.imageUrl || '',
94
- explanation: apiData?.explanation || '',
95
- askerName: apiData?.content?.askerName || apiData?.askerName || '',
96
- answererName: apiData?.content?.answererName || apiData?.answererName || '',
97
- isExample: apiData?.isExample || false,
98
- points: apiData?.points ?? 1,
99
- },
100
- zodSchema: formSchema,
101
- mode: 'onBlur',
102
- });
103
- // UI State
104
- const [isClientMode, setIsClientMode] = useState(false);
105
- const [imagePreviewUrl, setImagePreviewUrl] = useState('');
106
- const [optionPreviewUrls, setOptionPreviewUrls] = useState({});
107
- // ============ GROUP (shared title / content / image) ============
108
- const { isGrouped, currentGroupNumber, isFirstInGroup, groupTitle, groupSubtitle, groupContent, imageUrl: groupImageUrl, articles, setGroupTitle, setGroupSubtitle, setGroupContent, setImageUrl: setGroupImageUrl, setArticles, } = useBasicQuestionGroup({
109
- partId,
110
- groups,
111
- questionIndexInPart,
112
- initialData: {
113
- title: initialData?.groupTitle || initialData?.questionGroup?.payload?.title || initialData?.title || '',
114
- subtitle: initialData?.groupSubtitle || initialData?.questionGroup?.payload?.subtitle || '',
115
- content: initialData?.groupContent || initialData?.questionGroup?.payload?.content || '',
116
- imageUrl: initialData?.groupImageUrl || initialData?.questionGroup?.payload?.imageUrl || '',
117
- articles: initialData?.articles || initialData?.questionGroup?.payload?.articles || undefined,
118
- },
119
- articleCount,
120
- });
121
- // Cache options for each mode to preserve values when switching
122
- const textOptionsCacheRef = useRef(null);
123
- const imageOptionsCacheRef = useRef(null);
124
- // Track previous initialData to detect changes
125
- const previousInitialDataRef = useRef(initialData);
126
- const isInitializingRef = useRef(false);
127
- const onChangeRef = useRef(onChange);
128
- const previousPayloadRef = useRef('');
129
- // Update onChange ref when it changes
130
- useEffect(() => {
131
- onChangeRef.current = onChange;
132
- }, [onChange]);
133
- // Debounced onChange callback to prevent excessive re-renders
134
- const debouncedOnChange = useDebouncedCallback((data) => {
135
- onChangeRef.current?.(data);
136
- }, 300);
137
- // Watch form values - MUST be declared before useEffects that use them
138
- const watchedQuestion = form.watch('question');
139
- const watchedOptionType = form.watch('optionType');
140
- const watchedOptions = form.watch('options');
141
- const watchedCorrectAnswer = form.watch('correctAnswer');
142
- const watchedMultipleAnswers = form.watch('multipleAnswers');
143
- const watchedImageUrl = form.watch('imageUrl');
144
- const watchedExplanation = form.watch('explanation');
145
- const watchedAskerName = form.watch('askerName');
146
- const watchedAnswererName = form.watch('answererName');
147
- const watchedIsExample = form.watch('isExample');
148
- const watchedPoints = form.watch('points');
149
- // Normalize optionMode from template (handle uppercase 'IMAGE', 'TEXT')
150
- // If optionMode is null or undefined, default to 'text' as explicitly requested
151
- const normalizedOptionMode = (optionMode?.toLowerCase() === 'image' ? 'image' : 'text');
152
- // Default group type to 'BASIC' when template does not set group.type
153
- const effectiveGroupType = (groupType || 'BASIC').toUpperCase();
154
- // Whether per-question imageUrl is part of this part's questionConfig.
155
- // When false, per-question image input is hidden and must NOT be saved to content.imageUrl.
156
- const includesImageUrl = !questionConfig || questionConfig.length === 0 || questionConfig.includes('imageUrl');
157
- // Whether group-level imageUrl is part of this part's groupConfig.
158
- // When false, DocumentGroupCard/BasicQuestionGroupCard hide the group image input and
159
- // must NOT be saved to questionGroup.payload.imageUrl.
160
- const includesGroupImageUrl = !groupConfig || groupConfig.length === 0 || groupConfig.includes('imageUrl');
161
- // Force optionMode from template if provided
162
- useEffect(() => {
163
- if (normalizedOptionMode && watchedOptionType !== normalizedOptionMode) {
164
- form.setValue('optionType', normalizedOptionMode);
165
- }
166
- }, [normalizedOptionMode, watchedOptionType, form]);
167
- // Custom hooks for presigned URL
168
- const { previewUrl: generatedPreviewUrl } = usePresignedFileUrl(watchedImageUrl);
169
- const displayPreviewUrl = imagePreviewUrl || generatedPreviewUrl || '';
170
- // NOTE: Status tracking is now handled entirely by ExamCreator via localStorage
171
- // No need to track originalSavedData in Creator component
172
- // NOTE: Unsaved changes tracking has been REMOVED from Creator component
173
- // Status is now managed entirely by ExamCreator via localStorage (exam_question_status_{id})
174
- // The onChange callback triggers handleQuestionDraftChange in ExamCreator which updates localStorage
175
- // Expose validation function and getFormData via ref
176
- useEffect(() => {
177
- if (validationRef) {
178
- validationRef.current = {
179
- triggerValidation: async () => {
180
- const result = await form.trigger();
181
- return result;
182
- },
183
- // Return current form data immediately (not debounced)
184
- getFormData: () => ({
185
- question: watchedQuestion,
186
- optionType: watchedOptionType,
187
- options: watchedOptions,
188
- correctAnswer: watchedCorrectAnswer,
189
- multipleAnswers: watchedMultipleAnswers,
190
- imageUrl: includesImageUrl ? watchedImageUrl : '',
191
- explanation: watchedExplanation,
192
- askerName: watchedAskerName,
193
- answererName: watchedAnswererName,
194
- isExample: watchedIsExample,
195
- points: watchedPoints,
196
- groupTitle,
197
- groupSubtitle,
198
- groupContent,
199
- groupImageUrl: includesGroupImageUrl ? groupImageUrl : '',
200
- groupNumber: currentGroupNumber,
201
- ...(effectiveGroupType === 'ARTICLES' ? { articles } : {}),
202
- }),
203
- };
204
- }
205
- }, [validationRef, form, watchedCorrectAnswer, watchedMultipleAnswers, watchedQuestion, watchedOptionType, watchedOptions, watchedImageUrl, watchedExplanation, watchedAskerName, watchedAnswererName, watchedIsExample, watchedPoints, groupTitle, groupSubtitle, groupContent, groupImageUrl, currentGroupNumber, groupType, articles]);
206
- // Sync state from initialData when it changes from EXTERNAL sources only
207
- // We compare incoming initialData with current FORM values to detect true external changes
208
- useEffect(() => {
209
- // Cast to any to support both API format and flat format
210
- const apiData = initialData;
211
- // Normalize initialData for comparison - support both API and flat format
212
- const normalizedInitialData = {
213
- question: apiData?.content?.question || apiData?.question || defaultQuestion || '',
214
- optionType: (apiData?.content?.optionType || apiData?.optionType || 'text'),
215
- options: (apiData?.content?.options || apiData?.options)?.length > 0
216
- ? (apiData?.content?.options || apiData?.options)
217
- : defaultValue && defaultValue.length > 0
218
- ? defaultValue
219
- : Array.from({ length: optionCount }, () => ''),
220
- correctAnswer: initialMultipleAnswers
221
- ? (Array.isArray(normalizedInitialCorrectAnswer)
222
- ? normalizedInitialCorrectAnswer
223
- : normalizedInitialCorrectAnswer === -1
224
- ? []
225
- : [normalizedInitialCorrectAnswer])
226
- : (Array.isArray(normalizedInitialCorrectAnswer)
227
- ? (normalizedInitialCorrectAnswer[0] ?? -1)
228
- : normalizedInitialCorrectAnswer),
229
- multipleAnswers: initialMultipleAnswers || Boolean(multipleAnswers),
230
- imageUrl: apiData?.content?.imageUrl || apiData?.imageUrl || '',
231
- explanation: apiData?.explanation || '',
232
- askerName: apiData?.content?.askerName || apiData?.askerName || '',
233
- answererName: apiData?.content?.answererName || apiData?.answererName || '',
234
- isExample: apiData?.isExample || false,
235
- points: apiData?.points ?? 1,
236
- groupTitle: apiData?.groupTitle || apiData?.questionGroup?.payload?.title || '',
237
- groupContent: apiData?.groupContent || apiData?.questionGroup?.payload?.content || '',
238
- groupImageUrl: apiData?.groupImageUrl || apiData?.questionGroup?.payload?.imageUrl || '',
239
- };
240
- // Check if initialData actually changed from previous prop
241
- const initialDataChanged = JSON.stringify(previousInitialDataRef.current) !== JSON.stringify(initialData);
242
- if (!initialDataChanged) {
243
- return; // No change, nothing to do
244
- }
245
- // Update ref to track latest prop value
246
- previousInitialDataRef.current = initialData;
247
- // Get current form data to compare
248
- const currentFormData = {
249
- question: watchedQuestion,
250
- optionType: watchedOptionType,
251
- options: watchedOptions,
252
- correctAnswer: watchedCorrectAnswer,
253
- multipleAnswers: watchedMultipleAnswers,
254
- imageUrl: watchedImageUrl,
255
- explanation: watchedExplanation,
256
- askerName: watchedAskerName,
257
- answererName: watchedAnswererName,
258
- isExample: watchedIsExample,
259
- points: watchedPoints,
260
- };
261
- // Check if this is truly new external data (not echoed from our own onChange)
262
- // IMPORTANT: Must check ALL fields including points, explanation, and imageUrl
263
- const isEchoFromOnChange = currentFormData.question === normalizedInitialData.question &&
264
- currentFormData.optionType === normalizedInitialData.optionType &&
265
- JSON.stringify(currentFormData.correctAnswer) === JSON.stringify(normalizedInitialData.correctAnswer) &&
266
- currentFormData.multipleAnswers === normalizedInitialData.multipleAnswers &&
267
- currentFormData.points === normalizedInitialData.points &&
268
- currentFormData.explanation === normalizedInitialData.explanation &&
269
- currentFormData.imageUrl === normalizedInitialData.imageUrl &&
270
- JSON.stringify(currentFormData.options) === JSON.stringify(normalizedInitialData.options);
271
- // IMPORTANT: If initialData changed and matches current form AND isCompleted is true,
272
- // this means the question was just saved. Update originalSavedDataRef to the new baseline.
273
- // The isCompleted check is crucial - it differentiates actual save from user typing echo.
274
- const wasJustSaved = initialData?.isCompleted === true;
275
- // If echo from save, just skip the reset (no need to update old refs anymore)
276
- if (isEchoFromOnChange && wasJustSaved) {
277
- return;
278
- }
279
- // Only reset if external data has different values than current form
280
- // This prevents resetting when user just edits the question text
281
- const shouldReset = !isEchoFromOnChange &&
282
- (JSON.stringify(normalizedInitialData.correctAnswer) !== JSON.stringify(currentFormData.correctAnswer) ||
283
- normalizedInitialData.multipleAnswers !== currentFormData.multipleAnswers ||
284
- normalizedInitialData.question !== currentFormData.question ||
285
- normalizedInitialData.imageUrl !== currentFormData.imageUrl);
286
- const hasInitialCorrectAnswer = Array.isArray(normalizedInitialData.correctAnswer)
287
- ? normalizedInitialData.correctAnswer.length > 0
288
- : normalizedInitialData.correctAnswer !== -1;
289
- if (shouldReset && hasInitialCorrectAnswer) {
290
- isInitializingRef.current = true;
291
- form.reset(normalizedInitialData);
292
- setTimeout(() => {
293
- isInitializingRef.current = false;
294
- }, 150);
295
- }
296
- }, [initialData, optionCount, multipleAnswers, form, watchedQuestion, watchedOptionType, watchedOptions, watchedCorrectAnswer, watchedMultipleAnswers, watchedImageUrl, watchedExplanation, watchedAskerName, watchedAnswererName, watchedIsExample, watchedPoints]);
297
- // Convert to payload format and call onChange
298
- // NOTE: We need to stringify options for proper change detection since array reference doesn't change
299
- const watchedOptionsString = JSON.stringify(watchedOptions);
300
- useEffect(() => {
301
- if (isInitializingRef.current) {
302
- const currentPayload = JSON.stringify({
303
- question: watchedQuestion,
304
- optionType: watchedOptionType,
305
- options: watchedOptions,
306
- correctAnswer: watchedCorrectAnswer,
307
- multipleAnswers: watchedMultipleAnswers,
308
- imageUrl: watchedImageUrl,
309
- explanation: watchedExplanation,
310
- askerName: watchedAskerName,
311
- answererName: watchedAnswererName,
312
- isExample: watchedIsExample,
313
- points: watchedPoints,
314
- groupTitle,
315
- groupSubtitle,
316
- groupContent,
317
- groupImageUrl,
318
- groupNumber: currentGroupNumber,
319
- ...(effectiveGroupType === 'ARTICLES' ? { articles } : {}),
320
- });
321
- previousPayloadRef.current = currentPayload;
322
- return;
323
- }
324
- const payload = {
325
- question: watchedQuestion,
326
- optionType: watchedOptionType,
327
- options: watchedOptions,
328
- correctAnswer: watchedCorrectAnswer,
329
- multipleAnswers: watchedMultipleAnswers,
330
- imageUrl: includesImageUrl ? watchedImageUrl : '',
331
- explanation: watchedExplanation,
332
- askerName: watchedAskerName,
333
- answererName: watchedAnswererName,
334
- isExample: watchedIsExample,
335
- points: watchedPoints,
336
- groupTitle,
337
- groupSubtitle,
338
- groupContent,
339
- groupImageUrl: includesGroupImageUrl ? groupImageUrl : '',
340
- groupNumber: currentGroupNumber,
341
- ...(effectiveGroupType === 'ARTICLES' ? { articles } : {}),
342
- };
343
- const payloadString = JSON.stringify(payload);
344
- if (previousPayloadRef.current !== payloadString) {
345
- previousPayloadRef.current = payloadString;
346
- debouncedOnChange(payload);
347
- }
348
- }, [
349
- watchedQuestion,
350
- watchedOptionType,
351
- watchedOptionsString, // Use stringified version for proper change detection
352
- watchedCorrectAnswer,
353
- watchedMultipleAnswers,
354
- watchedImageUrl,
355
- watchedExplanation,
356
- watchedAskerName,
357
- watchedAnswererName,
358
- watchedIsExample,
359
- watchedPoints,
360
- groupTitle,
361
- groupSubtitle,
362
- groupContent,
363
- groupImageUrl,
364
- currentGroupNumber,
365
- groupType,
366
- articles,
367
- ]);
368
- // Handle save with validation
369
- const handleSave = form.handleSubmit((data) => {
370
- if (data.multipleAnswers) {
371
- const correctAnswers = Array.isArray(data.correctAnswer)
372
- ? data.correctAnswer
373
- : data.correctAnswer === -1
374
- ? []
375
- : [data.correctAnswer];
376
- const hasInvalidAnswer = correctAnswers.some((answer) => answer < 0 || answer >= data.options.length);
377
- if (hasInvalidAnswer) {
378
- form.setError('correctAnswer', { message: 'Đáp án đúng không hợp lệ!' });
379
- return;
380
- }
381
- }
382
- else {
383
- // Validate correctAnswer is within bounds (but allow -1 = not selected)
384
- const correctAnswer = typeof data.correctAnswer === 'number' ? data.correctAnswer : -1;
385
- if (correctAnswer !== -1 && correctAnswer >= data.options.length) {
386
- form.setError('correctAnswer', { message: 'Đáp án đúng không hợp lệ!' });
387
- return;
388
- }
389
- }
390
- // NOTE: Save status is now managed by ExamCreator via localStorage
391
- // No need to update old tracking refs here
392
- // Clear cached options for the non-active mode after saving
393
- textOptionsCacheRef.current = null;
394
- imageOptionsCacheRef.current = null;
395
- onSave?.(data);
396
- // Note: Toast is shown by parent ExamCreator with question number
397
- });
398
- // Client mode preview
399
- if (isClientMode) {
400
- const questionData = {
401
- question: watchedQuestion || '',
402
- optionType: watchedOptionType,
403
- options: watchedOptions,
404
- correctAnswer: watchedCorrectAnswer,
405
- multipleAnswers: watchedMultipleAnswers,
406
- imageUrl: displayPreviewUrl || watchedImageUrl,
407
- explanation: watchedExplanation,
408
- askerName: watchedAskerName,
409
- answererName: watchedAnswererName,
410
- isExample: watchedIsExample,
411
- isGroup: isGrouped,
412
- groupTitle,
413
- groupSubtitle,
414
- groupContent,
415
- groupImageUrl,
416
- groupNumber: currentGroupNumber,
417
- ...(effectiveGroupType === 'ARTICLES' ? { articles } : {}),
418
- };
419
- return (_jsxs("div", { className: "space-y-4", children: [_jsx(Card, { children: _jsx(CardHeader, { children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx(CardTitle, { children: "Choose the correct answer (Preview)" }), _jsx("p", { className: "mt-1 text-sm text-gray-500", children: "Ch\u1EBF \u0111\u1ED9 xem tr\u01B0\u1EDBc - Hi\u1EC3n th\u1ECB \u0111\u00E1p \u00E1n \u0111\u00FAng" })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setIsClientMode(false), children: [_jsx(Pencil, { className: "mr-2 h-4 w-4" }), "Quay l\u1EA1i Edit Mode"] })] }) }) }), _jsx(ChooseTheCorrectAnswerClient, { questionData: questionData, questionConfig: questionConfig, isReviewMode: true, userAnswer: watchedMultipleAnswers
420
- ? watchedCorrectAnswer
421
- : watchedCorrectAnswer !== -1
422
- ? watchedCorrectAnswer
423
- : undefined })] }));
424
- }
425
- // Creator UI
426
- return (_jsxs("div", { className: "space-y-4", children: [isGrouped && effectiveGroupType === 'ARTICLES' && (_jsx(ArticlesGroupCard, { groupNumber: currentGroupNumber, articleCount: articleCount, articles: articles, onArticlesChange: setArticles, title: groupTitle, onTitleChange: setGroupTitle, isReadOnly: !isFirstInGroup, uploadIdPrefix: `choose-correct-answer-${partId ?? 'articles'}` })), isGrouped && effectiveGroupType === 'BASIC' && (_jsx(BasicQuestionGroupCard, { groupNumber: currentGroupNumber, title: groupTitle, subtitle: groupSubtitle, content: groupContent, imageUrl: groupImageUrl, onTitleChange: setGroupTitle, onSubtitleChange: setGroupSubtitle, onContentChange: setGroupContent, onImageChange: setGroupImageUrl, groupConfig: groupType ? groupConfig : undefined, isReadOnly: !isFirstInGroup, uploadIdPrefix: `choose-correct-answer-${partId ?? 'group'}` })), isGrouped && effectiveGroupType === 'DOCUMENT' && (_jsx(DocumentGroupCard, { groupNumber: currentGroupNumber, title: groupTitle, subtitle: groupSubtitle, content: groupContent, imageUrl: groupImageUrl, onTitleChange: setGroupTitle, onSubtitleChange: setGroupSubtitle, onContentChange: setGroupContent, onImageChange: setGroupImageUrl, groupConfig: groupType ? groupConfig : undefined, isReadOnly: !isFirstInGroup, uploadIdPrefix: `choose-correct-answer-${partId ?? 'document'}` })), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-blue-100/50", children: [_jsx(CardHeader, { className: "px-4 py-3", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-gray-100", children: _jsx(HelpCircle, { className: "h-4 w-4 text-gray-600" }) }), _jsxs("div", { children: [_jsx(CardTitle, { className: "text-base font-bold text-gray-900", children: "Ch\u1ECDn \u0111\u00E1p \u00E1n \u0111\u00FAng" }), _jsx("p", { className: "text-xs text-gray-500", children: "T\u1EA1o c\u00E2u h\u1ECFi tr\u1EAFc nghi\u1EC7m v\u1EDBi nhi\u1EC1u l\u1EF1a ch\u1ECDn" })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [headerExtra, _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setIsClientMode(true), disabled: watchedOptions.filter((o) => o.trim()).length < 2, className: "gap-2 border-indigo-200 text-indigo-600 hover:bg-indigo-50 hover:text-indigo-700", children: [_jsx(Eye, { className: "h-4 w-4" }), "Xem tr\u01B0\u1EDBc"] })] })] }) }), _jsxs(CardContent, { className: "space-y-3 px-4 pb-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-y-2", children: [_jsx(PointsInput, { ...form.register('points', { valueAsNumber: true }), error: form.hasError('points') ? form.getFieldError('points') : undefined }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { type: "button", style: { paddingBlock: 'calc(var(--spacing) * 1)' }, onClick: () => form.setValue('isExample', !watchedIsExample), className: `inline-flex items-center gap-2 rounded-md border px-3.5 text-sm font-medium transition-colors select-none ${watchedIsExample
427
- ? 'border-amber-300 bg-amber-50 text-amber-700'
428
- : 'border-gray-200 bg-white text-gray-400 hover:text-gray-600'}`, children: [_jsx(Star, { className: `h-4 w-4 ${watchedIsExample ? 'fill-amber-400 text-amber-400' : ''}` }), "Example"] }), _jsxs("button", { type: "button", style: { paddingBlock: 'calc(var(--spacing) * 1)' }, disabled: Boolean(multipleAnswers), onClick: () => {
429
- const enabled = !watchedMultipleAnswers;
430
- const currentValue = form.getValues('correctAnswer');
431
- const normalized = Array.isArray(currentValue)
432
- ? currentValue
433
- : currentValue === -1 ? [] : [currentValue];
434
- form.setValue('multipleAnswers', enabled, { shouldValidate: true });
435
- form.setValue('correctAnswer', enabled ? normalized : (normalized[0] ?? -1), { shouldValidate: true });
436
- }, className: `inline-flex items-center gap-2 rounded-md border px-3.5 text-sm font-medium transition-colors select-none ${watchedMultipleAnswers
437
- ? 'border-violet-300 bg-violet-50 text-violet-700'
438
- : 'border-gray-200 bg-white text-gray-400 hover:text-gray-600'} ${Boolean(multipleAnswers) ? 'cursor-not-allowed opacity-50' : ''}`, children: [_jsx(ListChecks, { className: "h-4 w-4" }), "Nhi\u1EC1u \u0111\u00E1p \u00E1n"] })] })] }), viewMode === 'CONVERSATION' && (_jsxs("div", { className: "space-y-3", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(Users, { className: "h-4 w-4 text-indigo-500" }), "H\u1ED9i tho\u1EA1i ", _jsx("span", { className: "text-sm font-normal text-gray-500", children: "(tu\u1EF3 ch\u1ECDn - d\u00F9ng cho c\u00E2u h\u1ECFi d\u1EA1ng h\u1ED9i tho\u1EA1i)" })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4 rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { htmlFor: "askerName", className: "flex items-center gap-1 text-sm font-medium text-gray-600", children: ["T\u00EAn ng\u01B0\u1EDDi h\u1ECFi ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { id: "askerName", ...form.register('askerName'), placeholder: "VD: John, Mary, Teacher...", className: `border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 ${form.hasError('askerName') ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` }), form.hasError('askerName') && (_jsx("p", { className: "text-sm text-red-600", children: form.getFieldError('askerName') }))] }), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { htmlFor: "answererName", className: "flex items-center gap-1 text-sm font-medium text-gray-600", children: ["T\u00EAn ng\u01B0\u1EDDi tr\u1EA3 l\u1EDDi ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { id: "answererName", ...form.register('answererName'), placeholder: "VD: Tom, Anna, Student...", className: `border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 ${form.hasError('answererName') ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` }), form.hasError('answererName') && (_jsx("p", { className: "text-sm text-red-600", children: form.getFieldError('answererName') }))] })] })] })), (!questionConfig || questionConfig.length === 0 || questionConfig.includes('question')) && (_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { htmlFor: "question", className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(MessageSquare, { className: "h-4 w-4 text-indigo-500" }), _jsx("span", { className: "flex items-center gap-1", children: "C\u00E2u h\u1ECFi" }), _jsx("span", { className: "text-sm font-normal text-gray-500", children: "(tu\u1EF3 ch\u1ECDn)" })] }), _jsx(Textarea, { id: "question", ...form.register('question'), placeholder: "Nh\u1EADp c\u00E2u h\u1ECFi...", className: `min-h-[100px] border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 ${form.hasError('question') ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}`, rows: 3 }), form.hasError('question') && (_jsx("p", { className: "text-sm text-red-600", children: form.getFieldError('question') }))] })), (!questionConfig || questionConfig.length === 0 || questionConfig.includes('imageUrl') || questionConfig.includes('imageUrl ')) && (_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(ImageIcon, { className: "h-4 w-4 text-indigo-500" }), "H\u00ECnh \u1EA3nh ", _jsx("span", { className: "text-sm font-normal text-gray-500" })] }), _jsx(FileUpload, { id: "question-image", label: "", accept: "image/*", value: watchedImageUrl || '', onChange: (url) => {
439
- form.setValue('imageUrl', url, { shouldValidate: true });
440
- }, onPresignedUrlChange: setImagePreviewUrl, maxSize: 5, placeholder: "Upload \u1EA3nh ho\u1EB7c paste URL", autoUpload: true, prefix: "questions" }), form.hasError('imageUrl') && (_jsx("p", { className: "mt-1 text-sm text-red-600", children: form.getFieldError('imageUrl') })), displayPreviewUrl && (_jsx(ImagePreview, { src: displayPreviewUrl, alt: "Preview", className: "mt-2 h-48 w-full max-w-md rounded-lg border border-gray-200" }))] })), externalErrors && externalErrors.length > 0 && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-red-200 bg-gradient-to-r from-red-50 to-rose-50 p-4", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-red-100", children: _jsx("span", { className: "text-lg", children: "\u274C" }) }), _jsxs("div", { className: "text-sm", children: [_jsx("p", { className: "font-semibold text-red-800", children: "L\u1ED7i:" }), _jsx("ul", { className: "mt-1 list-inside list-disc text-red-700", children: externalErrors.map((error, index) => (_jsx("li", { children: error }, index))) })] })] })), form.formState.errors.options?.message && (_jsx("div", { className: "rounded-xl border border-red-200 bg-red-50 p-4", children: _jsx("p", { className: "text-sm text-red-600", children: form.formState.errors.options.message }) }))] })] }), (!questionConfig || questionConfig.length === 0 || questionConfig.includes('options')) && (_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-indigo-100/50", children: [_jsx(CardHeader, { className: "px-4 py-3", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-6 w-6 items-center justify-center rounded-md bg-indigo-100", children: _jsx(Lightbulb, { className: "h-3.5 w-3.5 text-indigo-600" }) }), _jsxs(CardTitle, { className: "text-base font-semibold text-gray-800", children: ["C\u00E1c l\u1EF1a ch\u1ECDn ", _jsxs("span", { className: "text-xs font-normal text-gray-500", children: ["(", watchedOptions.length, " \u0111\u00E1p \u00E1n)"] })] })] }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-gray-200 bg-gray-50 px-3 py-1.5", children: [_jsx(Type, { className: `h-3.5 w-3.5 ${watchedOptionType === 'text' ? 'text-indigo-600' : 'text-gray-400'}` }), _jsx("span", { className: `text-xs font-medium ${watchedOptionType === 'text' ? 'text-indigo-600' : 'text-gray-400'}`, children: "Text" }), _jsx(Switch, { checked: watchedOptionType === 'image', disabled: true, className: watchedOptionType === 'image' ? '!bg-indigo-600 !opacity-100' : '!bg-indigo-600 !opacity-100', onCheckedChange: (checked) => {
441
- const newType = checked ? 'image' : 'text';
442
- const currentOptions = form.getValues('options');
443
- const currentCorrectAnswer = form.getValues('correctAnswer');
444
- // Save current mode's options to cache
445
- if (watchedOptionType === 'text') {
446
- textOptionsCacheRef.current = { options: currentOptions, correctAnswer: currentCorrectAnswer };
447
- }
448
- else {
449
- imageOptionsCacheRef.current = { options: currentOptions, correctAnswer: currentCorrectAnswer };
450
- }
451
- // Restore cached values for the target mode, or use empty defaults
452
- const targetCache = newType === 'text' ? textOptionsCacheRef.current : imageOptionsCacheRef.current;
453
- if (targetCache) {
454
- form.setValue('options', targetCache.options);
455
- form.setValue('correctAnswer', targetCache.correctAnswer);
456
- }
457
- else {
458
- const emptyOptions = Array.from({ length: currentOptions.length }, () => '');
459
- form.setValue('options', emptyOptions);
460
- form.setValue('correctAnswer', -1);
461
- }
462
- form.setValue('optionType', newType);
463
- // Clear all validation errors from previous mode
464
- form.clearErrors();
465
- setOptionPreviewUrls({});
466
- } }), _jsx(ImageIcon, { className: `h-3.5 w-3.5 ${watchedOptionType === 'image' ? 'text-indigo-600' : 'text-gray-400'}` }), _jsx("span", { className: `text-xs font-medium ${watchedOptionType === 'image' ? 'text-indigo-600' : 'text-gray-400'}`, children: "\u1EA2nh" })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => {
467
- const currentOptions = form.getValues('options');
468
- form.setValue('options', [...currentOptions, '']);
469
- }, className: "gap-2 border-green-200 text-green-600 hover:bg-green-50 hover:text-green-700", children: [_jsx(Plus, { className: "h-4 w-4" }), "Th\u00EAm \u0111\u00E1p \u00E1n"] })] })] }) }), _jsxs(CardContent, { className: "space-y-3 px-4 pb-4", children: [watchedMultipleAnswers ? (_jsx("div", { className: "space-y-3", children: watchedOptions.map((option, index) => {
470
- const optionError = form.formState.errors.options?.[index];
471
- const selectedAnswers = Array.isArray(watchedCorrectAnswer)
472
- ? watchedCorrectAnswer
473
- : watchedCorrectAnswer === -1
474
- ? []
475
- : [watchedCorrectAnswer];
476
- const isCorrect = selectedAnswers.includes(index);
477
- const optionLetter = String.fromCharCode(65 + index);
478
- return (_jsx("div", { className: `group relative rounded-xl border-2 p-4 transition-all duration-200 ${isCorrect
479
- ? 'border-green-300 bg-gradient-to-r from-green-50 to-emerald-50 shadow-md shadow-green-100'
480
- : 'border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm'}`, children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: `flex h-10 w-10 flex-shrink-0 cursor-pointer items-center justify-center rounded-xl font-bold transition-all ${isCorrect
481
- ? 'bg-gradient-to-br from-green-500 to-emerald-600 text-white shadow-md'
482
- : 'bg-gray-100 text-gray-600 hover:bg-indigo-100 hover:text-indigo-600'}`, onClick: () => {
483
- if (watchedMultipleAnswers) {
484
- const currentAnswers = Array.isArray(form.getValues('correctAnswer'))
485
- ? form.getValues('correctAnswer')
486
- : [];
487
- const nextAnswers = currentAnswers.includes(index)
488
- ? currentAnswers.filter((answer) => answer !== index)
489
- : [...currentAnswers, index].sort((a, b) => a - b);
490
- form.setValue('correctAnswer', nextAnswers, { shouldValidate: true });
491
- return;
492
- }
493
- form.setValue('correctAnswer', index, { shouldValidate: true });
494
- }, children: optionLetter }), _jsxs("div", { className: "flex-1 space-y-2", children: [watchedOptionType === 'image' ? (
495
- /* Image Upload Mode */
496
- _jsxs("div", { className: "space-y-2", children: [_jsx(FileUpload, { id: `option-image-${index}`, label: "", accept: "image/*", value: option || '', onChange: (url) => {
497
- const newOptions = [...watchedOptions];
498
- newOptions[index] = url;
499
- form.setValue('options', newOptions, { shouldValidate: true });
500
- }, onPresignedUrlChange: (presignedUrl) => {
501
- setOptionPreviewUrls((prev) => ({ ...prev, [index]: presignedUrl }));
502
- }, maxSize: 5, placeholder: `Upload ảnh đáp án ${optionLetter}...`, autoUpload: true, prefix: "questions/options" }), (optionPreviewUrls[index] || option) && (_jsx(OptionImagePreview, { src: optionPreviewUrls[index] || option, alt: `Đáp án ${optionLetter}` }))] })) : (
503
- /* Text Input Mode */
504
- _jsx(Input, { id: `option-input-${index}`, ...form.register(`options.${index}`), placeholder: `Nhập đáp án ${optionLetter}...`, className: `border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 ${optionError ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` })), optionError && (_jsx("p", { className: "text-sm text-red-600", children: optionError.message })), isCorrect && (_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-full bg-green-100 px-3 py-1 text-xs font-semibold text-green-700", children: [_jsx(CheckCircle2, { className: "h-3.5 w-3.5" }), watchedMultipleAnswers ? 'Đáp án đúng đã chọn' : 'Đáp án đúng'] }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => {
505
- if (watchedMultipleAnswers) {
506
- const currentAnswers = Array.isArray(form.getValues('correctAnswer'))
507
- ? form.getValues('correctAnswer')
508
- : [];
509
- const nextAnswers = currentAnswers.includes(index)
510
- ? currentAnswers.filter((answer) => answer !== index)
511
- : [...currentAnswers, index].sort((a, b) => a - b);
512
- form.setValue('correctAnswer', nextAnswers, { shouldValidate: true });
513
- return;
514
- }
515
- form.setValue('correctAnswer', index, { shouldValidate: true });
516
- }, className: isCorrect ? 'text-green-600 hover:text-green-700' : 'text-gray-400 hover:text-green-600', title: watchedMultipleAnswers
517
- ? (isCorrect ? 'Bỏ chọn đáp án đúng' : 'Chọn thêm đáp án đúng')
518
- : 'Chọn làm đáp án đúng', children: _jsx(CheckCircle2, { className: "h-4 w-4" }) }), watchedOptions.length > 2 && (_jsx(Button, { variant: "ghost", size: "sm", onClick: () => {
519
- const currentOptions = form.getValues('options');
520
- const newOptions = currentOptions.filter((_, i) => i !== index);
521
- form.setValue('options', newOptions);
522
- // Adjust correctAnswer if needed
523
- const currentCorrect = form.getValues('correctAnswer');
524
- if (Array.isArray(currentCorrect)) {
525
- const nextCorrect = currentCorrect
526
- .filter((answer) => answer !== index)
527
- .map((answer) => (answer > index ? answer - 1 : answer));
528
- form.setValue('correctAnswer', nextCorrect, { shouldValidate: true });
529
- }
530
- else if (currentCorrect === index) {
531
- form.setValue('correctAnswer', -1, { shouldValidate: true });
532
- }
533
- else if (typeof currentCorrect === 'number' && currentCorrect > index) {
534
- form.setValue('correctAnswer', currentCorrect - 1, { shouldValidate: true });
535
- }
536
- }, className: "text-red-500 hover:bg-red-50 hover:text-red-600", children: _jsx(Trash2, { className: "h-4 w-4" }) }))] })] }) }, index));
537
- }) })) : (_jsx(RadioGroup, { value: watchedCorrectAnswer === -1 ? '' : watchedCorrectAnswer.toString(), onValueChange: (value) => {
538
- form.setValue('correctAnswer', Number(value), { shouldValidate: true });
539
- }, children: watchedOptions.map((option, index) => {
540
- const optionError = form.formState.errors.options?.[index];
541
- const isCorrect = watchedCorrectAnswer === index;
542
- const optionLetter = String.fromCharCode(65 + index);
543
- return (_jsx("div", { className: `group relative rounded-xl border-2 p-4 transition-all duration-200 ${isCorrect
544
- ? 'border-green-300 bg-gradient-to-r from-green-50 to-emerald-50 shadow-md shadow-green-100'
545
- : 'border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm'}`, children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: `flex h-10 w-10 flex-shrink-0 cursor-pointer items-center justify-center rounded-xl font-bold transition-all ${isCorrect
546
- ? 'bg-gradient-to-br from-green-500 to-emerald-600 text-white shadow-md'
547
- : 'bg-gray-100 text-gray-600 hover:bg-indigo-100 hover:text-indigo-600'}`, onClick: () => {
548
- form.setValue('correctAnswer', index, { shouldValidate: true });
549
- }, children: optionLetter }), _jsxs("div", { className: "flex-1 space-y-2", children: [watchedOptionType === 'image' ? (
550
- /* Image Upload Mode */
551
- _jsxs("div", { className: "space-y-2", children: [_jsx(FileUpload, { id: `option-image-${index}`, label: "", accept: "image/*", value: option || '', onChange: (url) => {
552
- const newOptions = [...watchedOptions];
553
- newOptions[index] = url;
554
- form.setValue('options', newOptions, { shouldValidate: true });
555
- }, onPresignedUrlChange: (presignedUrl) => {
556
- setOptionPreviewUrls((prev) => ({ ...prev, [index]: presignedUrl }));
557
- }, maxSize: 5, placeholder: `Upload ảnh đáp án ${optionLetter}...`, autoUpload: true, prefix: "questions/options" }), (optionPreviewUrls[index] || option) && (_jsx(OptionImagePreview, { src: optionPreviewUrls[index] || option, alt: `Đáp án ${optionLetter}` }))] })) : (
558
- /* Text Input Mode */
559
- _jsx(Input, { id: `option-input-${index}`, ...form.register(`options.${index}`), placeholder: `Nhập đáp án ${optionLetter}...`, className: `border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 ${optionError ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` })), optionError && (_jsx("p", { className: "text-sm text-red-600", children: optionError.message })), isCorrect && (_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-full bg-green-100 px-3 py-1 text-xs font-semibold text-green-700", children: [_jsx(CheckCircle2, { className: "h-3.5 w-3.5" }), "\u0110\u00E1p \u00E1n \u0111\u00FAng"] }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => {
560
- form.setValue('correctAnswer', index, { shouldValidate: true });
561
- }, className: isCorrect ? 'text-green-600 hover:text-green-700' : 'text-gray-400 hover:text-green-600', title: "Ch\u1ECDn l\u00E0m \u0111\u00E1p \u00E1n \u0111\u00FAng", children: _jsx(CheckCircle2, { className: "h-4 w-4" }) }), watchedOptions.length > 2 && (_jsx(Button, { variant: "ghost", size: "sm", onClick: () => {
562
- const currentOptions = form.getValues('options');
563
- const newOptions = currentOptions.filter((_, i) => i !== index);
564
- form.setValue('options', newOptions);
565
- // Adjust correctAnswer if needed
566
- const currentCorrect = form.getValues('correctAnswer');
567
- if (typeof currentCorrect === 'number' && currentCorrect === index) {
568
- form.setValue('correctAnswer', -1, { shouldValidate: true });
569
- }
570
- else if (typeof currentCorrect === 'number' && currentCorrect > index) {
571
- form.setValue('correctAnswer', currentCorrect - 1, { shouldValidate: true });
572
- }
573
- }, className: "text-red-500 hover:bg-red-50 hover:text-red-600", children: _jsx(Trash2, { className: "h-4 w-4" }) }))] })] }) }, index));
574
- }) })), ((Array.isArray(watchedCorrectAnswer) && watchedCorrectAnswer.length === 0)
575
- || (!Array.isArray(watchedCorrectAnswer) && watchedCorrectAnswer === -1)) && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-4", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-amber-100", children: _jsx("span", { className: "text-lg", children: "\u26A0\uFE0F" }) }), _jsxs("div", { className: "text-sm text-amber-800", children: [_jsx("p", { className: "font-semibold", children: "Ch\u01B0a ch\u1ECDn \u0111\u00E1p \u00E1n \u0111\u00FAng" }), _jsx("p", { className: "mt-0.5 text-amber-700", children: watchedMultipleAnswers
576
- ? 'Click vào ô chữ cái hoặc icon ✓ để chọn một hoặc nhiều đáp án đúng'
577
- : 'Click vào ô chữ cái hoặc icon ✓ để chọn đáp án đúng' })] })] })), form.hasError('correctAnswer') && (_jsx("div", { className: "rounded-xl border border-red-200 bg-red-50 p-4", children: _jsx("p", { className: "text-sm text-red-600", children: form.getFieldError('correctAnswer') }) }))] })] })), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-amber-100/50", children: [_jsx(CardHeader, { className: "px-4 py-3", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-amber-500 to-orange-500 shadow-sm", children: _jsx(BookOpen, { className: "h-3.5 w-3.5 text-white" }) }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-base font-semibold text-gray-800", children: "Gi\u1EA3i th\u00EDch" }), _jsx("span", { className: "inline-flex items-center rounded-full border border-amber-200 bg-amber-50 px-2 py-0.5 text-xs font-medium text-amber-600", children: "Kh\u00F4ng b\u1EAFt bu\u1ED9c" })] }), _jsx("p", { className: "text-xs text-gray-500 mt-0.5", children: "Gi\u1EA3i th\u00EDch cho \u0111\u00E1p \u00E1n \u0111\u00FAng \u2014 hi\u1EC3n th\u1ECB sau khi h\u1ECDc sinh ho\u00E0n th\u00E0nh c\u00E2u h\u1ECFi" })] })] }) }), _jsx(CardContent, { className: "px-4 pb-4", children: _jsx(Textarea, { ...form.register('explanation'), placeholder: "VD: C\u00E2u tr\u1EA3 l\u1EDDi \u0111\u00FAng l\u00E0... v\u00EC...", rows: 3, className: "min-h-[80px] border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200 resize-none" }) })] })] }));
578
- }
579
- export function ChooseTheCorrectAnswerCreator(props) {
580
- return _jsx(ChooseTheCorrectAnswerCreatorContent, { ...props });
581
- }
1
+ "use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{ImagePreview as t}from"../../../../components/ui/image-preview";import{useState as n,useRef as s,useEffect as o,useMemo as a}from"react";import{Button as i}from"../../../../components/ui/button";import{Label as l}from"../../../../components/ui/label";import{Input as c}from"../../../../components/ui/input";import{Textarea as d}from"../../../../components/ui/textarea";import{PointsInput as m}from"../../../../components/ui/points-input";import{Card as g,CardContent as p,CardHeader as u,CardTitle as h}from"../../../../components/ui/card";import{RadioGroup as x}from"../../../../components/ui/radio-group";import{Switch as f}from"../../../../components/ui/switch";import{usePresignedFileUrl as b,useDebouncedCallback as w}from"../../../../shared/lib/hooks";import{useReactHookForm as N}from"../../../../shared/lib/hooks/useReactHookForm";import{Pencil as y,Eye as v,Plus as A,Trash2 as C,HelpCircle as V,CheckCircle2 as U,Lightbulb as k,MessageSquare as T,ImageIcon as S,Type as E,Users as q,BookOpen as I,Star as G,ListChecks as O}from"lucide-react";import{FileUpload as j}from"../../../../components/ui/file-upload";import{ChooseTheCorrectAnswerClient as $}from"./ChooseTheCorrectAnswerClient";import{chooseCorrectAnswerFormSchema as R}from"../../../../shared/lib/validation/choose-correct-answer.validation";import{BasicQuestionGroupCard as z}from"../../groups/BasicQuestionGroupCard";import{ArticlesGroupCard as B}from"../../groups/ArticlesGroupCard";import{DocumentGroupCard as F}from"../../groups/DocumentGroupCard";import{useBasicQuestionGroup as J}from"../../_shared/hooks/useBasicQuestionGroup";import{z as P}from"zod";function D({src:r,alt:t}){const{previewUrl:n,isLoading:s}=b(r);return e("div",s?{className:"flex h-24 w-full max-w-[200px] items-center justify-center rounded-lg border border-gray-200 bg-gray-50",children:e("div",{className:"h-5 w-5 animate-spin rounded-full border-2 border-gray-200 border-t-blue-500"})}:{className:"relative h-24 w-full max-w-[200px] overflow-hidden rounded-lg border border-gray-200 bg-gray-50",children:e("img",{src:n||r,alt:t,className:"h-full w-full object-contain",onError:e=>{const r=e.target;r.onerror=null,r.src="/images/placeholder-image.svg"}})})}function L({initialData:L,onSave:M,onCancel:H,onChange:Q,externalErrors:Z,optionCount:K=4,optionMode:X,defaultValue:_,defaultQuestion:W,viewMode:Y,onUnsavedChangesChange:ee,validationRef:re,groups:te,questionIndexInPart:ne=0,partId:se="",questionConfig:oe,groupType:ae,groupConfig:ie,articleCount:le=0,multipleAnswers:ce,headerExtra:de}){console.log("=== viewMode ===",Y);const me=L,ge=a(()=>R.superRefine((e,r)=>{"CONVERSATION"===Y&&(e.askerName?.trim()||r.addIssue({code:P.ZodIssueCode.custom,message:"Vui lòng nhập tên người hỏi!",path:["askerName"]}),e.answererName?.trim()||r.addIssue({code:P.ZodIssueCode.custom,message:"Vui lòng nhập tên người trả lời!",path:["answererName"]}))}),[Y]),pe=me?.correctAnswer,ue=Array.isArray(pe)?pe:"object"==typeof pe&&null!==pe?pe?.answer??-1:pe??-1,he=Boolean(me?.multipleAnswers??me?.content?.multipleAnswers??me?.questionGroup?.payload?.multipleAnswers??Array.isArray(ue)),xe=N({defaultValues:{question:me?.content?.question||me?.question||W||"",optionType:me?.content?.optionType||me?.optionType||"text",options:(me?.content?.options||me?.options)?.length>0?me?.content?.options||me?.options:_&&_.length>0?_:Array.from({length:K},()=>""),correctAnswer:he?Array.isArray(ue)?ue:-1===ue?[]:[ue]:Array.isArray(ue)?ue[0]??-1:ue,multipleAnswers:he||Boolean(ce),imageUrl:me?.content?.imageUrl||me?.imageUrl||"",explanation:me?.explanation||"",askerName:me?.content?.askerName||me?.askerName||"",answererName:me?.content?.answererName||me?.answererName||"",isExample:me?.isExample||!1,points:me?.points??1},zodSchema:ge,mode:"onBlur"}),[fe,be]=n(!1),[we,Ne]=n(""),[ye,ve]=n({}),{isGrouped:Ae,currentGroupNumber:Ce,isFirstInGroup:Ve,groupTitle:Ue,groupSubtitle:ke,groupContent:Te,imageUrl:Se,articles:Ee,setGroupTitle:qe,setGroupSubtitle:Ie,setGroupContent:Ge,setImageUrl:Oe,setArticles:je}=J({partId:se,groups:te,questionIndexInPart:ne,initialData:{title:L?.groupTitle||L?.questionGroup?.payload?.title||L?.title||"",subtitle:L?.groupSubtitle||L?.questionGroup?.payload?.subtitle||"",content:L?.groupContent||L?.questionGroup?.payload?.content||"",imageUrl:L?.groupImageUrl||L?.questionGroup?.payload?.imageUrl||"",articles:L?.articles||L?.questionGroup?.payload?.articles||void 0},articleCount:le}),$e=s(null),Re=s(null),ze=s(L),Be=s(!1),Fe=s(Q),Je=s("");o(()=>{Fe.current=Q},[Q]);const Pe=w(e=>{Fe.current?.(e)},300),De=xe.watch("question"),Le=xe.watch("optionType"),Me=xe.watch("options"),He=xe.watch("correctAnswer"),Qe=xe.watch("multipleAnswers"),Ze=xe.watch("imageUrl"),Ke=xe.watch("explanation"),Xe=xe.watch("askerName"),_e=xe.watch("answererName"),We=xe.watch("isExample"),Ye=xe.watch("points"),er="image"===X?.toLowerCase()?"image":"text",rr=(ae||"BASIC").toUpperCase(),tr=!oe||0===oe.length||oe.includes("imageUrl"),nr=!ie||0===ie.length||ie.includes("imageUrl");o(()=>{er&&Le!==er&&xe.setValue("optionType",er)},[er,Le,xe]);const{previewUrl:sr}=b(Ze),or=we||sr||"";o(()=>{re&&(re.current={triggerValidation:async()=>await xe.trigger(),getFormData:()=>({question:De,optionType:Le,options:Me,correctAnswer:He,multipleAnswers:Qe,imageUrl:tr?Ze:"",explanation:Ke,askerName:Xe,answererName:_e,isExample:We,points:Ye,groupTitle:Ue,groupSubtitle:ke,groupContent:Te,groupImageUrl:nr?Se:"",groupNumber:Ce,..."ARTICLES"===rr?{articles:Ee}:{}})})},[re,xe,He,Qe,De,Le,Me,Ze,Ke,Xe,_e,We,Ye,Ue,ke,Te,Se,Ce,ae,Ee]),o(()=>{const e=L,r={question:e?.content?.question||e?.question||W||"",optionType:e?.content?.optionType||e?.optionType||"text",options:(e?.content?.options||e?.options)?.length>0?e?.content?.options||e?.options:_&&_.length>0?_:Array.from({length:K},()=>""),correctAnswer:he?Array.isArray(ue)?ue:-1===ue?[]:[ue]:Array.isArray(ue)?ue[0]??-1:ue,multipleAnswers:he||Boolean(ce),imageUrl:e?.content?.imageUrl||e?.imageUrl||"",explanation:e?.explanation||"",askerName:e?.content?.askerName||e?.askerName||"",answererName:e?.content?.answererName||e?.answererName||"",isExample:e?.isExample||!1,points:e?.points??1,groupTitle:e?.groupTitle||e?.questionGroup?.payload?.title||"",groupContent:e?.groupContent||e?.questionGroup?.payload?.content||"",groupImageUrl:e?.groupImageUrl||e?.questionGroup?.payload?.imageUrl||""};if(!(JSON.stringify(ze.current)!==JSON.stringify(L)))return;ze.current=L;const t={question:De,optionType:Le,options:Me,correctAnswer:He,multipleAnswers:Qe,imageUrl:Ze,explanation:Ke,askerName:Xe,answererName:_e,isExample:We,points:Ye},n=t.question===r.question&&t.optionType===r.optionType&&JSON.stringify(t.correctAnswer)===JSON.stringify(r.correctAnswer)&&t.multipleAnswers===r.multipleAnswers&&t.points===r.points&&t.explanation===r.explanation&&t.imageUrl===r.imageUrl&&JSON.stringify(t.options)===JSON.stringify(r.options);if(n&&!0===L?.isCompleted)return;const s=!n&&(JSON.stringify(r.correctAnswer)!==JSON.stringify(t.correctAnswer)||r.multipleAnswers!==t.multipleAnswers||r.question!==t.question||r.imageUrl!==t.imageUrl),o=Array.isArray(r.correctAnswer)?r.correctAnswer.length>0:-1!==r.correctAnswer;s&&o&&(Be.current=!0,xe.reset(r),setTimeout(()=>{Be.current=!1},150))},[L,K,ce,xe,De,Le,Me,He,Qe,Ze,Ke,Xe,_e,We,Ye]);const ar=JSON.stringify(Me);o(()=>{if(Be.current){const e=JSON.stringify({question:De,optionType:Le,options:Me,correctAnswer:He,multipleAnswers:Qe,imageUrl:Ze,explanation:Ke,askerName:Xe,answererName:_e,isExample:We,points:Ye,groupTitle:Ue,groupSubtitle:ke,groupContent:Te,groupImageUrl:Se,groupNumber:Ce,..."ARTICLES"===rr?{articles:Ee}:{}});return void(Je.current=e)}const e={question:De,optionType:Le,options:Me,correctAnswer:He,multipleAnswers:Qe,imageUrl:tr?Ze:"",explanation:Ke,askerName:Xe,answererName:_e,isExample:We,points:Ye,groupTitle:Ue,groupSubtitle:ke,groupContent:Te,groupImageUrl:nr?Se:"",groupNumber:Ce,..."ARTICLES"===rr?{articles:Ee}:{}},r=JSON.stringify(e);Je.current!==r&&(Je.current=r,Pe(e))},[De,Le,ar,He,Qe,Ze,Ke,Xe,_e,We,Ye,Ue,ke,Te,Se,Ce,ae,Ee]);xe.handleSubmit(e=>{if(e.multipleAnswers){if((Array.isArray(e.correctAnswer)?e.correctAnswer:-1===e.correctAnswer?[]:[e.correctAnswer]).some(r=>r<0||r>=e.options.length))return void xe.setError("correctAnswer",{message:"Đáp án đúng không hợp lệ!"})}else{const r="number"==typeof e.correctAnswer?e.correctAnswer:-1;if(-1!==r&&r>=e.options.length)return void xe.setError("correctAnswer",{message:"Đáp án đúng không hợp lệ!"})}$e.current=null,Re.current=null,M?.(e)});if(fe){const t={question:De||"",optionType:Le,options:Me,correctAnswer:He,multipleAnswers:Qe,imageUrl:or||Ze,explanation:Ke,askerName:Xe,answererName:_e,isExample:We,isGroup:Ae,groupTitle:Ue,groupSubtitle:ke,groupContent:Te,groupImageUrl:Se,groupNumber:Ce,..."ARTICLES"===rr?{articles:Ee}:{}};return r("div",{className:"space-y-4",children:[e(g,{children:e(u,{children:r("div",{className:"flex items-center justify-between",children:[r("div",{children:[e(h,{children:"Choose the correct answer (Preview)"}),e("p",{className:"mt-1 text-sm text-gray-500",children:"Chế độ xem trước - Hiển thị đáp án đúng"})]}),r(i,{variant:"outline",size:"sm",onClick:()=>be(!1),children:[e(y,{className:"mr-2 h-4 w-4"}),"Quay lại Edit Mode"]})]})})}),e($,{questionData:t,questionConfig:oe,isReviewMode:!0,userAnswer:Qe||-1!==He?He:void 0})]})}return r("div",{className:"space-y-4",children:[Ae&&"ARTICLES"===rr&&e(B,{groupNumber:Ce,articleCount:le,articles:Ee,onArticlesChange:je,title:Ue,onTitleChange:qe,isReadOnly:!Ve,uploadIdPrefix:`choose-correct-answer-${se??"articles"}`}),Ae&&"BASIC"===rr&&e(z,{groupNumber:Ce,title:Ue,subtitle:ke,content:Te,imageUrl:Se,onTitleChange:qe,onSubtitleChange:Ie,onContentChange:Ge,onImageChange:Oe,groupConfig:ae?ie:void 0,isReadOnly:!Ve,uploadIdPrefix:`choose-correct-answer-${se??"group"}`}),Ae&&"DOCUMENT"===rr&&e(F,{groupNumber:Ce,title:Ue,subtitle:ke,content:Te,imageUrl:Se,onTitleChange:qe,onSubtitleChange:Ie,onContentChange:Ge,onImageChange:Oe,groupConfig:ae?ie:void 0,isReadOnly:!Ve,uploadIdPrefix:`choose-correct-answer-${se??"document"}`}),r(g,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-blue-100/50",children:[e(u,{className:"px-4 py-3",children:r("div",{className:"flex items-center justify-between",children:[r("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gray-100",children:e(V,{className:"h-4 w-4 text-gray-600"})}),r("div",{children:[e(h,{className:"text-base font-bold text-gray-900",children:"Chọn đáp án đúng"}),e("p",{className:"text-xs text-gray-500",children:"Tạo câu hỏi trắc nghiệm với nhiều lựa chọn"})]})]}),r("div",{className:"flex items-center gap-2",children:[de,r(i,{variant:"outline",size:"sm",onClick:()=>be(!0),disabled:Me.filter(e=>e.trim()).length<2,className:"gap-2 border-indigo-200 text-indigo-600 hover:bg-indigo-50 hover:text-indigo-700",children:[e(v,{className:"h-4 w-4"}),"Xem trước"]})]})]})}),r(p,{className:"space-y-3 px-4 pb-4",children:[r("div",{className:"flex flex-wrap items-center justify-between gap-y-2",children:[e(m,{...xe.register("points",{valueAsNumber:!0}),error:xe.hasError("points")?xe.getFieldError("points"):void 0}),r("div",{className:"flex items-center gap-2",children:[r("button",{type:"button",style:{paddingBlock:"calc(var(--spacing) * 1)"},onClick:()=>xe.setValue("isExample",!We),className:"inline-flex items-center gap-2 rounded-md border px-3.5 text-sm font-medium transition-colors select-none "+(We?"border-amber-300 bg-amber-50 text-amber-700":"border-gray-200 bg-white text-gray-400 hover:text-gray-600"),children:[e(G,{className:"h-4 w-4 "+(We?"fill-amber-400 text-amber-400":"")}),"Example"]}),r("button",{type:"button",style:{paddingBlock:"calc(var(--spacing) * 1)"},disabled:Boolean(ce),onClick:()=>{const e=!Qe,r=xe.getValues("correctAnswer"),t=Array.isArray(r)?r:-1===r?[]:[r];xe.setValue("multipleAnswers",e,{shouldValidate:!0}),xe.setValue("correctAnswer",e?t:t[0]??-1,{shouldValidate:!0})},className:`inline-flex items-center gap-2 rounded-md border px-3.5 text-sm font-medium transition-colors select-none ${Qe?"border-violet-300 bg-violet-50 text-violet-700":"border-gray-200 bg-white text-gray-400 hover:text-gray-600"} ${Boolean(ce)?"cursor-not-allowed opacity-50":""}`,children:[e(O,{className:"h-4 w-4"}),"Nhiều đáp án"]})]})]}),"CONVERSATION"===Y&&r("div",{className:"space-y-3",children:[r(l,{className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(q,{className:"h-4 w-4 text-indigo-500"}),"Hội thoại ",e("span",{className:"text-sm font-normal text-gray-500",children:"(tuỳ chọn - dùng cho câu hỏi dạng hội thoại)"})]}),r("div",{className:"grid grid-cols-2 gap-4 rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4",children:[r("div",{className:"space-y-1.5",children:[r(l,{htmlFor:"askerName",className:"flex items-center gap-1 text-sm font-medium text-gray-600",children:["Tên người hỏi ",e("span",{className:"text-red-500",children:"*"})]}),e(c,{id:"askerName",...xe.register("askerName"),placeholder:"VD: John, Mary, Teacher...",className:"border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 "+(xe.hasError("askerName")?"border-red-400 focus:border-red-500 focus:ring-red-200":"")}),xe.hasError("askerName")&&e("p",{className:"text-sm text-red-600",children:xe.getFieldError("askerName")})]}),r("div",{className:"space-y-1.5",children:[r(l,{htmlFor:"answererName",className:"flex items-center gap-1 text-sm font-medium text-gray-600",children:["Tên người trả lời ",e("span",{className:"text-red-500",children:"*"})]}),e(c,{id:"answererName",...xe.register("answererName"),placeholder:"VD: Tom, Anna, Student...",className:"border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 "+(xe.hasError("answererName")?"border-red-400 focus:border-red-500 focus:ring-red-200":"")}),xe.hasError("answererName")&&e("p",{className:"text-sm text-red-600",children:xe.getFieldError("answererName")})]})]})]}),(!oe||0===oe.length||oe.includes("question"))&&r("div",{className:"space-y-2",children:[r(l,{htmlFor:"question",className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(T,{className:"h-4 w-4 text-indigo-500"}),e("span",{className:"flex items-center gap-1",children:"Câu hỏi"}),e("span",{className:"text-sm font-normal text-gray-500",children:"(tuỳ chọn)"})]}),e(d,{id:"question",...xe.register("question"),placeholder:"Nhập câu hỏi...",className:"min-h-[100px] border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 "+(xe.hasError("question")?"border-red-400 focus:border-red-500 focus:ring-red-200":""),rows:3}),xe.hasError("question")&&e("p",{className:"text-sm text-red-600",children:xe.getFieldError("question")})]}),(!oe||0===oe.length||oe.includes("imageUrl")||oe.includes("imageUrl "))&&r("div",{className:"space-y-2",children:[r(l,{className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(S,{className:"h-4 w-4 text-indigo-500"}),"Hình ảnh ",e("span",{className:"text-sm font-normal text-gray-500"})]}),e(j,{id:"question-image",label:"",accept:"image/*",value:Ze||"",onChange:e=>{xe.setValue("imageUrl",e,{shouldValidate:!0})},onPresignedUrlChange:Ne,maxSize:5,placeholder:"Upload ảnh hoặc paste URL",autoUpload:!0,prefix:"questions"}),xe.hasError("imageUrl")&&e("p",{className:"mt-1 text-sm text-red-600",children:xe.getFieldError("imageUrl")}),or&&e(t,{src:or,alt:"Preview",className:"mt-2 h-48 w-full max-w-md rounded-lg border border-gray-200"})]}),Z&&Z.length>0&&r("div",{className:"flex items-start gap-3 rounded-xl border border-red-200 bg-gradient-to-r from-red-50 to-rose-50 p-4",children:[e("div",{className:"flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-red-100",children:e("span",{className:"text-lg",children:"❌"})}),r("div",{className:"text-sm",children:[e("p",{className:"font-semibold text-red-800",children:"Lỗi:"}),e("ul",{className:"mt-1 list-inside list-disc text-red-700",children:Z.map((r,t)=>e("li",{children:r},t))})]})]}),xe.formState.errors.options?.message&&e("div",{className:"rounded-xl border border-red-200 bg-red-50 p-4",children:e("p",{className:"text-sm text-red-600",children:xe.formState.errors.options.message})})]})]}),(!oe||0===oe.length||oe.includes("options"))&&r(g,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-indigo-100/50",children:[e(u,{className:"px-4 py-3",children:r("div",{className:"flex items-center justify-between",children:[r("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-6 w-6 items-center justify-center rounded-md bg-indigo-100",children:e(k,{className:"h-3.5 w-3.5 text-indigo-600"})}),r(h,{className:"text-base font-semibold text-gray-800",children:["Các lựa chọn ",r("span",{className:"text-xs font-normal text-gray-500",children:["(",Me.length," đáp án)"]})]})]}),r("div",{className:"flex items-center gap-3",children:[r("div",{className:"flex items-center gap-2 rounded-lg border border-gray-200 bg-gray-50 px-3 py-1.5",children:[e(E,{className:"h-3.5 w-3.5 "+("text"===Le?"text-indigo-600":"text-gray-400")}),e("span",{className:"text-xs font-medium "+("text"===Le?"text-indigo-600":"text-gray-400"),children:"Text"}),e(f,{checked:"image"===Le,disabled:!0,className:"!bg-indigo-600 !opacity-100",onCheckedChange:e=>{const r=e?"image":"text",t=xe.getValues("options"),n=xe.getValues("correctAnswer");"text"===Le?$e.current={options:t,correctAnswer:n}:Re.current={options:t,correctAnswer:n};const s="text"===r?$e.current:Re.current;if(s)xe.setValue("options",s.options),xe.setValue("correctAnswer",s.correctAnswer);else{const e=Array.from({length:t.length},()=>"");xe.setValue("options",e),xe.setValue("correctAnswer",-1)}xe.setValue("optionType",r),xe.clearErrors(),ve({})}}),e(S,{className:"h-3.5 w-3.5 "+("image"===Le?"text-indigo-600":"text-gray-400")}),e("span",{className:"text-xs font-medium "+("image"===Le?"text-indigo-600":"text-gray-400"),children:"Ảnh"})]}),r(i,{variant:"outline",size:"sm",onClick:()=>{const e=xe.getValues("options");xe.setValue("options",[...e,""])},className:"gap-2 border-green-200 text-green-600 hover:bg-green-50 hover:text-green-700",children:[e(A,{className:"h-4 w-4"}),"Thêm đáp án"]})]})]})}),r(p,{className:"space-y-3 px-4 pb-4",children:[Qe?e("div",{className:"space-y-3",children:Me.map((t,n)=>{const s=xe.formState.errors.options?.[n],o=(Array.isArray(He)?He:-1===He?[]:[He]).includes(n),a=String.fromCharCode(65+n);return e("div",{className:"group relative rounded-xl border-2 p-4 transition-all duration-200 "+(o?"border-green-300 bg-gradient-to-r from-green-50 to-emerald-50 shadow-md shadow-green-100":"border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm"),children:r("div",{className:"flex items-start gap-4",children:[e("div",{className:"flex h-10 w-10 flex-shrink-0 cursor-pointer items-center justify-center rounded-xl font-bold transition-all "+(o?"bg-gradient-to-br from-green-500 to-emerald-600 text-white shadow-md":"bg-gray-100 text-gray-600 hover:bg-indigo-100 hover:text-indigo-600"),onClick:()=>{if(Qe){const e=Array.isArray(xe.getValues("correctAnswer"))?xe.getValues("correctAnswer"):[],r=e.includes(n)?e.filter(e=>e!==n):[...e,n].sort((e,r)=>e-r);return void xe.setValue("correctAnswer",r,{shouldValidate:!0})}xe.setValue("correctAnswer",n,{shouldValidate:!0})},children:a}),r("div",{className:"flex-1 space-y-2",children:["image"===Le?r("div",{className:"space-y-2",children:[e(j,{id:`option-image-${n}`,label:"",accept:"image/*",value:t||"",onChange:e=>{const r=[...Me];r[n]=e,xe.setValue("options",r,{shouldValidate:!0})},onPresignedUrlChange:e=>{ve(r=>({...r,[n]:e}))},maxSize:5,placeholder:`Upload ảnh đáp án ${a}...`,autoUpload:!0,prefix:"questions/options"}),(ye[n]||t)&&e(D,{src:ye[n]||t,alt:`Đáp án ${a}`})]}):e(c,{id:`option-input-${n}`,...xe.register(`options.${n}`),placeholder:`Nhập đáp án ${a}...`,className:"border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 "+(s?"border-red-400 focus:border-red-500 focus:ring-red-200":"")}),s&&e("p",{className:"text-sm text-red-600",children:s.message}),o&&r("span",{className:"inline-flex items-center gap-1.5 rounded-full bg-green-100 px-3 py-1 text-xs font-semibold text-green-700",children:[e(U,{className:"h-3.5 w-3.5"}),Qe?"Đáp án đúng đã chọn":"Đáp án đúng"]})]}),r("div",{className:"flex items-center gap-2",children:[e(i,{type:"button",variant:"ghost",size:"sm",onClick:()=>{if(Qe){const e=Array.isArray(xe.getValues("correctAnswer"))?xe.getValues("correctAnswer"):[],r=e.includes(n)?e.filter(e=>e!==n):[...e,n].sort((e,r)=>e-r);return void xe.setValue("correctAnswer",r,{shouldValidate:!0})}xe.setValue("correctAnswer",n,{shouldValidate:!0})},className:o?"text-green-600 hover:text-green-700":"text-gray-400 hover:text-green-600",title:Qe?o?"Bỏ chọn đáp án đúng":"Chọn thêm đáp án đúng":"Chọn làm đáp án đúng",children:e(U,{className:"h-4 w-4"})}),Me.length>2&&e(i,{variant:"ghost",size:"sm",onClick:()=>{const e=xe.getValues("options").filter((e,r)=>r!==n);xe.setValue("options",e);const r=xe.getValues("correctAnswer");if(Array.isArray(r)){const e=r.filter(e=>e!==n).map(e=>e>n?e-1:e);xe.setValue("correctAnswer",e,{shouldValidate:!0})}else r===n?xe.setValue("correctAnswer",-1,{shouldValidate:!0}):"number"==typeof r&&r>n&&xe.setValue("correctAnswer",r-1,{shouldValidate:!0})},className:"text-red-500 hover:bg-red-50 hover:text-red-600",children:e(C,{className:"h-4 w-4"})})]})]})},n)})}):e(x,{value:-1===He?"":He.toString(),onValueChange:e=>{xe.setValue("correctAnswer",Number(e),{shouldValidate:!0})},children:Me.map((t,n)=>{const s=xe.formState.errors.options?.[n],o=He===n,a=String.fromCharCode(65+n);return e("div",{className:"group relative rounded-xl border-2 p-4 transition-all duration-200 "+(o?"border-green-300 bg-gradient-to-r from-green-50 to-emerald-50 shadow-md shadow-green-100":"border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm"),children:r("div",{className:"flex items-start gap-4",children:[e("div",{className:"flex h-10 w-10 flex-shrink-0 cursor-pointer items-center justify-center rounded-xl font-bold transition-all "+(o?"bg-gradient-to-br from-green-500 to-emerald-600 text-white shadow-md":"bg-gray-100 text-gray-600 hover:bg-indigo-100 hover:text-indigo-600"),onClick:()=>{xe.setValue("correctAnswer",n,{shouldValidate:!0})},children:a}),r("div",{className:"flex-1 space-y-2",children:["image"===Le?r("div",{className:"space-y-2",children:[e(j,{id:`option-image-${n}`,label:"",accept:"image/*",value:t||"",onChange:e=>{const r=[...Me];r[n]=e,xe.setValue("options",r,{shouldValidate:!0})},onPresignedUrlChange:e=>{ve(r=>({...r,[n]:e}))},maxSize:5,placeholder:`Upload ảnh đáp án ${a}...`,autoUpload:!0,prefix:"questions/options"}),(ye[n]||t)&&e(D,{src:ye[n]||t,alt:`Đáp án ${a}`})]}):e(c,{id:`option-input-${n}`,...xe.register(`options.${n}`),placeholder:`Nhập đáp án ${a}...`,className:"border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 "+(s?"border-red-400 focus:border-red-500 focus:ring-red-200":"")}),s&&e("p",{className:"text-sm text-red-600",children:s.message}),o&&r("span",{className:"inline-flex items-center gap-1.5 rounded-full bg-green-100 px-3 py-1 text-xs font-semibold text-green-700",children:[e(U,{className:"h-3.5 w-3.5"}),"Đáp án đúng"]})]}),r("div",{className:"flex items-center gap-2",children:[e(i,{type:"button",variant:"ghost",size:"sm",onClick:()=>{xe.setValue("correctAnswer",n,{shouldValidate:!0})},className:o?"text-green-600 hover:text-green-700":"text-gray-400 hover:text-green-600",title:"Chọn làm đáp án đúng",children:e(U,{className:"h-4 w-4"})}),Me.length>2&&e(i,{variant:"ghost",size:"sm",onClick:()=>{const e=xe.getValues("options").filter((e,r)=>r!==n);xe.setValue("options",e);const r=xe.getValues("correctAnswer");"number"==typeof r&&r===n?xe.setValue("correctAnswer",-1,{shouldValidate:!0}):"number"==typeof r&&r>n&&xe.setValue("correctAnswer",r-1,{shouldValidate:!0})},className:"text-red-500 hover:bg-red-50 hover:text-red-600",children:e(C,{className:"h-4 w-4"})})]})]})},n)})}),(Array.isArray(He)&&0===He.length||!Array.isArray(He)&&-1===He)&&r("div",{className:"flex items-start gap-3 rounded-xl border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-4",children:[e("div",{className:"flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-amber-100",children:e("span",{className:"text-lg",children:"⚠️"})}),r("div",{className:"text-sm text-amber-800",children:[e("p",{className:"font-semibold",children:"Chưa chọn đáp án đúng"}),e("p",{className:"mt-0.5 text-amber-700",children:Qe?"Click vào ô chữ cái hoặc icon ✓ để chọn một hoặc nhiều đáp án đúng":"Click vào ô chữ cái hoặc icon ✓ để chọn đáp án đúng"})]})]}),xe.hasError("correctAnswer")&&e("div",{className:"rounded-xl border border-red-200 bg-red-50 p-4",children:e("p",{className:"text-sm text-red-600",children:xe.getFieldError("correctAnswer")})})]})]}),r(g,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-amber-100/50",children:[e(u,{className:"px-4 py-3",children:r("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-amber-500 to-orange-500 shadow-sm",children:e(I,{className:"h-3.5 w-3.5 text-white"})}),r("div",{children:[r("div",{className:"flex items-center gap-2",children:[e(h,{className:"text-base font-semibold text-gray-800",children:"Giải thích"}),e("span",{className:"inline-flex items-center rounded-full border border-amber-200 bg-amber-50 px-2 py-0.5 text-xs font-medium text-amber-600",children:"Không bắt buộc"})]}),e("p",{className:"text-xs text-gray-500 mt-0.5",children:"Giải thích cho đáp án đúng — hiển thị sau khi học sinh hoàn thành câu hỏi"})]})]})}),e(p,{className:"px-4 pb-4",children:e(d,{...xe.register("explanation"),placeholder:"VD: Câu trả lời đúng là... vì...",rows:3,className:"min-h-[80px] border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200 resize-none"})})]})]})}export function ChooseTheCorrectAnswerCreator(r){return e(L,{...r})}