@tinyweb_dev/oe-exam-sdk 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (514) hide show
  1. package/dist/api/exam-create.js +1 -179
  2. package/dist/api/exam-create.types.js +1 -1
  3. package/dist/api/exam-questions.d.ts +1 -1
  4. package/dist/api/exam-questions.js +1 -98
  5. package/dist/api/exam-questions.types.d.ts +45 -1
  6. package/dist/api/exam-questions.types.js +1 -1
  7. package/dist/api/exam-taking.js +1 -73
  8. package/dist/api/exam-taking.types.js +1 -1
  9. package/dist/api/index.js +1 -6
  10. package/dist/api/result-review.js +1 -50
  11. package/dist/api/result-review.types.js +1 -1
  12. package/dist/components/CueCardEditor.js +1 -58
  13. package/dist/components/common/ResolvedImage.js +1 -15
  14. package/dist/components/exams/CompletionDialog.d.ts +8 -0
  15. package/dist/components/exams/CompletionDialog.js +1 -0
  16. package/dist/components/exams/CreateExamInfoForm.d.ts +4 -1
  17. package/dist/components/exams/CreateExamInfoForm.js +1 -35
  18. package/dist/components/exams/CreateExamPageContainer.d.ts +3 -0
  19. package/dist/components/exams/CreateExamPageContainer.js +1 -103
  20. package/dist/components/exams/ExamCreator.d.ts +9 -3
  21. package/dist/components/exams/ExamCreator.js +1 -89
  22. package/dist/components/exams/ExamPartTabs.d.ts +1 -1
  23. package/dist/components/exams/ExamPartTabs.js +1 -40
  24. package/dist/components/exams/ExamPreviewDialog.d.ts +20 -0
  25. package/dist/components/exams/ExamPreviewDialog.js +1 -0
  26. package/dist/components/exams/ExamQuestionGrid.d.ts +1 -1
  27. package/dist/components/exams/ExamQuestionGrid.js +1 -18
  28. package/dist/components/exams/ExamQuestionsPageContainer.d.ts +3 -0
  29. package/dist/components/exams/ExamQuestionsPageContainer.js +1 -90
  30. package/dist/components/exams/ExamViewDialog.d.ts +24 -0
  31. package/dist/components/exams/ExamViewDialog.js +1 -0
  32. package/dist/components/exams/PartAudioUploader.js +1 -9
  33. package/dist/components/exams/TemplateSelector.js +1 -66
  34. package/dist/components/exams/UnsavedChangesDialog.d.ts +8 -0
  35. package/dist/components/exams/UnsavedChangesDialog.js +1 -0
  36. package/dist/components/exams/api.d.ts +1 -1
  37. package/dist/components/exams/api.js +1 -3
  38. package/dist/components/exams/create-exam.texts.d.ts +58 -0
  39. package/dist/components/exams/create-exam.texts.js +1 -0
  40. package/dist/components/exams/create-exam.validation.js +1 -18
  41. package/dist/components/exams/exam-question-status.d.ts +9 -0
  42. package/dist/components/exams/exam-question-status.js +1 -0
  43. package/dist/components/exams/exam-template.utils.js +1 -18
  44. package/dist/components/exams/index.d.ts +11 -1
  45. package/dist/components/exams/index.js +1 -10
  46. package/dist/components/exams/take/ExamTakingPageContainer.js +1 -153
  47. package/dist/components/exams/take/GenericQuestionRenderer.js +1 -14
  48. package/dist/components/exams/take/exam-taking.utils.js +1 -88
  49. package/dist/components/exams/take/hooks/useSpeakingRecorder.js +1 -24
  50. package/dist/components/exams/take/index.js +1 -2
  51. package/dist/components/exams/take/types.js +1 -1
  52. package/dist/components/index.js +1 -42
  53. package/dist/components/questions/_shared/config/question-types.config.js +1 -333
  54. package/dist/components/questions/_shared/constants/color-palette.js +1 -21
  55. package/dist/components/questions/_shared/hooks/useAnswerGroupQuestionGroup.js +1 -105
  56. package/dist/components/questions/_shared/hooks/useBasicQuestionGroup.js +1 -222
  57. package/dist/components/questions/_shared/hooks/useCompareImagesGroup.js +1 -140
  58. package/dist/components/questions/_shared/hooks/useImageQuestionGroup.js +1 -123
  59. package/dist/components/questions/_shared/hooks/useInfoExchangeGroup.js +1 -50
  60. package/dist/components/questions/_shared/hooks/useQuestionFormState.js +1 -54
  61. package/dist/components/questions/_shared/hooks/useQuestionInitialization.js +1 -123
  62. package/dist/components/questions/_shared/hooks/useQuestionListGroup.js +1 -121
  63. package/dist/components/questions/_shared/hooks/useQuestionOnChange.js +1 -70
  64. package/dist/components/questions/_shared/hooks/useSceneQuestionGroup.js +1 -194
  65. package/dist/components/questions/_shared/index.js +1 -7
  66. package/dist/components/questions/_shared/types/answer-the-question.type.js +1 -1
  67. package/dist/components/questions/_shared/types/arrange-letters-into-words.type.js +1 -1
  68. package/dist/components/questions/_shared/types/choose-correct-adjective.type.js +1 -3
  69. package/dist/components/questions/_shared/types/color-region.config.js +1 -1
  70. package/dist/components/questions/_shared/types/fill-in-blank.type.js +1 -1
  71. package/dist/components/questions/_shared/types/fill-missing-words-in-grid.type.js +1 -1
  72. package/dist/components/questions/_shared/types/gn-speaking-interview.type.js +1 -1
  73. package/dist/components/questions/_shared/types/index.js +1 -12
  74. package/dist/components/questions/_shared/types/label-the-picture.type.js +1 -1
  75. package/dist/components/questions/_shared/types/listen-and-choose-from-answer-group.type.js +1 -1
  76. package/dist/components/questions/_shared/types/listen-and-choose-objects-in-scene.type.js +1 -1
  77. package/dist/components/questions/_shared/types/listen-and-drag-objects-into-scene.type.js +1 -1
  78. package/dist/components/questions/_shared/types/listen-and-speak-answer.type.js +1 -1
  79. package/dist/components/questions/_shared/types/listen-and-speak-compare-images.type.js +1 -1
  80. package/dist/components/questions/_shared/types/listen-and-speak-image-group.type.js +1 -1
  81. package/dist/components/questions/_shared/types/listen-and-speak-info-exchange.type.js +1 -1
  82. package/dist/components/questions/_shared/types/listen-and-speak-odd-one-out.type.js +1 -3
  83. package/dist/components/questions/_shared/types/listen-and-speak-question-list.type.js +1 -1
  84. package/dist/components/questions/_shared/types/listen-and-speak-with-story-images.type.js +1 -3
  85. package/dist/components/questions/_shared/types/listen-and-tick-answer.type.js +1 -1
  86. package/dist/components/questions/_shared/types/listening-drawline.type.js +1 -1
  87. package/dist/components/questions/_shared/types/look-and-choose-answer.type.js +1 -1
  88. package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.js +1 -1
  89. package/dist/components/questions/_shared/types/match-by-writing-answer.type.js +1 -1
  90. package/dist/components/questions/_shared/types/multiple-choice.type.js +1 -1
  91. package/dist/components/questions/_shared/types/question-group.type.js +1 -11
  92. package/dist/components/questions/_shared/types/read-and-color-objects.type.js +1 -1
  93. package/dist/components/questions/_shared/types/read-displayed-content.type.js +1 -1
  94. package/dist/components/questions/_shared/types/read-passage-and-answer-questions.type.js +1 -1
  95. package/dist/components/questions/_shared/types/speaking-describe-image.type.js +1 -1
  96. package/dist/components/questions/_shared/types/spontaneous-qa.type.js +1 -1
  97. package/dist/components/questions/_shared/types/word-fill-paragraph-with-options.type.js +1 -1
  98. package/dist/components/questions/_shared/types/word-fill-paragraph.type.js +1 -1
  99. package/dist/components/questions/_shared/types/word-fill-structured-form.type.js +1 -1
  100. package/dist/components/questions/_shared/types/word-ordering.type.js +1 -1
  101. package/dist/components/questions/_shared/types/write-a-short-letter.type.js +1 -1
  102. package/dist/components/questions/_shared/types/write-correct-verb-form.type.js +1 -3
  103. package/dist/components/questions/_shared/types/write-sentences.type.js +1 -1
  104. package/dist/components/questions/_shared/types/write-short-paragraph.type.js +1 -1
  105. package/dist/components/questions/_shared/utils/answer-builder.js +1 -79
  106. package/dist/components/questions/_shared/utils/createColorRegionRegistration.js +1 -39
  107. package/dist/components/questions/_shared/utils/id-generator.js +1 -3
  108. package/dist/components/questions/_shared/utils/question-validation.js +1 -21
  109. package/dist/components/questions/components/ColorNode.js +1 -85
  110. package/dist/components/questions/components/ColorRegionClient.js +1 -545
  111. package/dist/components/questions/components/ColorRegionCreator.js +1 -420
  112. package/dist/components/questions/components/ColorRegionNode.js +1 -59
  113. package/dist/components/questions/components/CreatorGuide.js +1 -103
  114. package/dist/components/questions/components/NameNode.js +1 -26
  115. package/dist/components/questions/components/QuestionBankOption.js +1 -46
  116. package/dist/components/questions/components/QuestionBasicInfoForm.js +1 -9
  117. package/dist/components/questions/components/QuestionCommonFields.js +1 -33
  118. package/dist/components/questions/components/QuestionSearchDropdown.js +1 -258
  119. package/dist/components/questions/components/QuestionTypeSelector.js +1 -32
  120. package/dist/components/questions/components/QuestionTypeSpecificForms.js +1 -6
  121. package/dist/components/questions/components/RegionNode.js +1 -94
  122. package/dist/components/questions/components/index.js +1 -14
  123. package/dist/components/questions/creator/QuestionCreator.js +1 -90
  124. package/dist/components/questions/creator/QuestionGroupCreator.js +1 -119
  125. package/dist/components/questions/creator/dedicated-component-router.js +1 -79
  126. package/dist/components/questions/creator/index.js +1 -3
  127. package/dist/components/questions/creator/question-type-registry.js +1 -80
  128. package/dist/components/questions/groups/ArticlesGroupCard.js +1 -121
  129. package/dist/components/questions/groups/BasicQuestionGroupCard.js +1 -50
  130. package/dist/components/questions/groups/DocumentGroupCard.js +1 -114
  131. package/dist/components/questions/groups/MatchAnswerGroupCard.js +1 -25
  132. package/dist/components/questions/index.js +1 -10
  133. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +1 -37
  134. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionCreator.js +1 -351
  135. package/dist/components/questions/types/answer-the-question/register.js +1 -67
  136. package/dist/components/questions/types/answer-the-question/transform.js +1 -36
  137. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +1 -141
  138. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsCreator.js +1 -118
  139. package/dist/components/questions/types/arrange-letters-into-words/index.js +1 -2
  140. package/dist/components/questions/types/arrange-letters-into-words/register.js +1 -4
  141. package/dist/components/questions/types/arrange-letters-into-words/transform.js +1 -24
  142. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +1 -64
  143. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js +1 -169
  144. package/dist/components/questions/types/choose-correct-adjective/index.js +1 -2
  145. package/dist/components/questions/types/choose-correct-adjective/register.js +1 -55
  146. package/dist/components/questions/types/choose-correct-adjective/transform.js +1 -16
  147. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +1 -131
  148. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +1 -581
  149. package/dist/components/questions/types/choose-the-correct-answer/index.js +1 -2
  150. package/dist/components/questions/types/choose-the-correct-answer/register.js +1 -101
  151. package/dist/components/questions/types/choose-the-correct-answer/transform.js +1 -43
  152. package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +1 -275
  153. package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +1 -448
  154. package/dist/components/questions/types/fill-in-blank/index.js +1 -2
  155. package/dist/components/questions/types/fill-in-blank/register.js +1 -138
  156. package/dist/components/questions/types/fill-in-blank/transform.js +1 -59
  157. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +1 -117
  158. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridCreator.js +1 -671
  159. package/dist/components/questions/types/fill-missing-words-in-grid/index.js +1 -2
  160. package/dist/components/questions/types/fill-missing-words-in-grid/register.js +1 -37
  161. package/dist/components/questions/types/fill-missing-words-in-grid/transform.js +1 -15
  162. package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.js +1 -262
  163. package/dist/components/questions/types/gn-speaking-interview/register.js +1 -121
  164. package/dist/components/questions/types/gn-speaking-interview/transform.js +1 -48
  165. package/dist/components/questions/types/image-object-matching/ImageObjectMatchingClient.js +1 -16
  166. package/dist/components/questions/types/image-object-matching/ImageObjectMatchingCreator.js +1 -27
  167. package/dist/components/questions/types/image-object-matching/index.js +1 -2
  168. package/dist/components/questions/types/image-object-matching/register.js +1 -3
  169. package/dist/components/questions/types/image-object-matching/transform.js +1 -2
  170. package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +1 -102
  171. package/dist/components/questions/types/label-the-picture/LabelThePictureCreator.js +1 -344
  172. package/dist/components/questions/types/label-the-picture/index.js +1 -2
  173. package/dist/components/questions/types/label-the-picture/register.js +1 -54
  174. package/dist/components/questions/types/label-the-picture/transform.js +1 -28
  175. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +1 -78
  176. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupCreator.js +1 -232
  177. package/dist/components/questions/types/listen-and-choose-from-answer-group/index.js +1 -2
  178. package/dist/components/questions/types/listen-and-choose-from-answer-group/register.js +1 -82
  179. package/dist/components/questions/types/listen-and-choose-from-answer-group/transform.js +1 -27
  180. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneClient.js +1 -70
  181. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneCreator.js +1 -386
  182. package/dist/components/questions/types/listen-and-choose-objects-in-scene/index.js +1 -2
  183. package/dist/components/questions/types/listen-and-choose-objects-in-scene/register.js +1 -100
  184. package/dist/components/questions/types/listen-and-choose-objects-in-scene/transform.js +1 -33
  185. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneClient.js +1 -106
  186. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneCreator.js +1 -457
  187. package/dist/components/questions/types/listen-and-drag-objects-into-scene/index.js +1 -2
  188. package/dist/components/questions/types/listen-and-drag-objects-into-scene/register.js +1 -110
  189. package/dist/components/questions/types/listen-and-drag-objects-into-scene/transform.js +1 -35
  190. package/dist/components/questions/types/listen-and-speak-answer/ArrowIndicator.js +1 -8
  191. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +1 -22
  192. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerCreator.js +1 -291
  193. package/dist/components/questions/types/listen-and-speak-answer/index.js +1 -2
  194. package/dist/components/questions/types/listen-and-speak-answer/register.js +1 -84
  195. package/dist/components/questions/types/listen-and-speak-answer/transform.js +1 -27
  196. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +1 -32
  197. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesCreator.js +1 -295
  198. package/dist/components/questions/types/listen-and-speak-compare-images/register.js +1 -79
  199. package/dist/components/questions/types/listen-and-speak-compare-images/transform.js +1 -27
  200. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +1 -34
  201. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupCreator.js +1 -285
  202. package/dist/components/questions/types/listen-and-speak-image-group/register.js +1 -81
  203. package/dist/components/questions/types/listen-and-speak-image-group/transform.js +1 -26
  204. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +1 -38
  205. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeCreator.js +1 -385
  206. package/dist/components/questions/types/listen-and-speak-info-exchange/register.js +1 -87
  207. package/dist/components/questions/types/listen-and-speak-info-exchange/transform.js +1 -32
  208. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +1 -26
  209. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutCreator.js +1 -247
  210. package/dist/components/questions/types/listen-and-speak-odd-one-out/register.js +1 -59
  211. package/dist/components/questions/types/listen-and-speak-odd-one-out/transform.js +1 -18
  212. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +1 -26
  213. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListCreator.js +1 -256
  214. package/dist/components/questions/types/listen-and-speak-question-list/register.js +1 -81
  215. package/dist/components/questions/types/listen-and-speak-question-list/transform.js +1 -26
  216. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +1 -26
  217. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesCreator.js +1 -230
  218. package/dist/components/questions/types/listen-and-speak-with-story-images/register.js +1 -56
  219. package/dist/components/questions/types/listen-and-speak-with-story-images/transform.js +1 -16
  220. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.js +1 -72
  221. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.js +1 -230
  222. package/dist/components/questions/types/look-picture-choose-correct-answer/index.js +1 -1
  223. package/dist/components/questions/types/look-picture-choose-correct-answer/register.js +1 -66
  224. package/dist/components/questions/types/look-picture-choose-correct-answer/transform.js +1 -42
  225. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.js +1 -96
  226. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.js +1 -238
  227. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.js +1 -2
  228. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.js +1 -76
  229. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.js +1 -19
  230. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.js +1 -134
  231. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.js +1 -617
  232. package/dist/components/questions/types/look-picture-fill-word-hint/index.js +1 -2
  233. package/dist/components/questions/types/look-picture-fill-word-hint/register.js +1 -82
  234. package/dist/components/questions/types/look-picture-fill-word-hint/transform.js +1 -29
  235. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +1 -38
  236. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerCreator.js +1 -359
  237. package/dist/components/questions/types/match-by-writing-answer/index.js +1 -3
  238. package/dist/components/questions/types/match-by-writing-answer/register.js +1 -58
  239. package/dist/components/questions/types/match-by-writing-answer/transform.js +1 -61
  240. package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsClient.js +1 -16
  241. package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsCreator.js +1 -23
  242. package/dist/components/questions/types/read-and-color-objects/index.js +1 -2
  243. package/dist/components/questions/types/read-and-color-objects/register.js +1 -3
  244. package/dist/components/questions/types/read-and-color-objects/transform.js +1 -36
  245. package/dist/components/questions/types/read-displayed-content/ReadDisplayedContentCreator.js +1 -125
  246. package/dist/components/questions/types/read-displayed-content/register.js +1 -64
  247. package/dist/components/questions/types/read-displayed-content/transform.js +1 -12
  248. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +1 -64
  249. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsCreator.js +1 -511
  250. package/dist/components/questions/types/read-passage-and-answer-questions/index.js +1 -2
  251. package/dist/components/questions/types/read-passage-and-answer-questions/register.js +1 -58
  252. package/dist/components/questions/types/read-passage-and-answer-questions/transform.js +1 -28
  253. package/dist/components/questions/types/speaking-conversation/SpeakingConversationCreator.js +1 -373
  254. package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +1 -41
  255. package/dist/components/questions/types/speaking-conversation/register.js +1 -110
  256. package/dist/components/questions/types/speaking-conversation/transform.js +1 -34
  257. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +1 -74
  258. package/dist/components/questions/types/speaking-cue-card/register.js +1 -52
  259. package/dist/components/questions/types/speaking-cue-card/transform.js +1 -12
  260. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +1 -10
  261. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageCreator.js +1 -161
  262. package/dist/components/questions/types/speaking-describe-image/index.js +1 -2
  263. package/dist/components/questions/types/speaking-describe-image/register.js +1 -69
  264. package/dist/components/questions/types/speaking-describe-image/transform.js +1 -16
  265. package/dist/components/questions/types/spontaneous-qa/SpontaneousQACreator.js +1 -234
  266. package/dist/components/questions/types/spontaneous-qa/register.js +1 -93
  267. package/dist/components/questions/types/spontaneous-qa/transform.js +1 -34
  268. package/dist/components/questions/types/true-false/TrueFalseClient.js +1 -75
  269. package/dist/components/questions/types/true-false/TrueFalseCreator.js +1 -244
  270. package/dist/components/questions/types/true-false/index.js +1 -2
  271. package/dist/components/questions/types/true-false/register.js +1 -77
  272. package/dist/components/questions/types/true-false/transform.js +1 -32
  273. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +1 -233
  274. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphCreator.js +1 -631
  275. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphWrapper.js +1 -28
  276. package/dist/components/questions/types/word-fill-paragraph/index.js +1 -2
  277. package/dist/components/questions/types/word-fill-paragraph/register.js +1 -136
  278. package/dist/components/questions/types/word-fill-paragraph/transform.js +1 -56
  279. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -138
  280. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +1 -261
  281. package/dist/components/questions/types/word-fill-structured-form/index.js +1 -2
  282. package/dist/components/questions/types/word-fill-structured-form/register.js +1 -67
  283. package/dist/components/questions/types/word-fill-structured-form/transform.js +1 -40
  284. package/dist/components/questions/types/word-ordering/WordOrderingClient.js +1 -84
  285. package/dist/components/questions/types/word-ordering/WordOrderingCreator.js +1 -192
  286. package/dist/components/questions/types/word-ordering/index.js +1 -2
  287. package/dist/components/questions/types/word-ordering/register.js +1 -46
  288. package/dist/components/questions/types/word-ordering/transform.js +1 -24
  289. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +1 -98
  290. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +1 -320
  291. package/dist/components/questions/types/write-a-short-letter/index.js +1 -2
  292. package/dist/components/questions/types/write-a-short-letter/register.js +1 -68
  293. package/dist/components/questions/types/write-a-short-letter/transform.js +1 -25
  294. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +1 -61
  295. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js +1 -196
  296. package/dist/components/questions/types/write-correct-verb-form/index.js +1 -2
  297. package/dist/components/questions/types/write-correct-verb-form/register.js +1 -62
  298. package/dist/components/questions/types/write-correct-verb-form/transform.js +1 -17
  299. package/dist/components/questions/types/write-sentences/WriteSentencesClient.js +1 -22
  300. package/dist/components/questions/types/write-sentences/WriteSentencesCreator.js +1 -174
  301. package/dist/components/questions/types/write-sentences/index.js +1 -2
  302. package/dist/components/questions/types/write-sentences/register.js +1 -58
  303. package/dist/components/questions/types/write-sentences/transform.js +1 -28
  304. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphClient.js +1 -96
  305. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphCreator.js +1 -161
  306. package/dist/components/questions/types/write-short-paragraph/index.js +1 -2
  307. package/dist/components/questions/types/write-short-paragraph/register.js +1 -4
  308. package/dist/components/questions/types/write-short-paragraph/transform.js +1 -21
  309. package/dist/components/questions/viewer/QuestionGroupViewer.js +1 -36
  310. package/dist/components/questions/viewer/QuestionViewer.js +1 -446
  311. package/dist/components/questions/viewer/index.js +1 -2
  312. package/dist/components/results/ResultReviewPageContainer.js +1 -98
  313. package/dist/components/results/ReviewQuestionRenderer.js +1 -72
  314. package/dist/components/results/index.js +1 -2
  315. package/dist/components/results/result-review.utils.js +1 -6
  316. package/dist/components/results/review-data.js +1 -150
  317. package/dist/components/results/review-renderer.utils.js +1 -97
  318. package/dist/components/results/review-types.js +1 -1
  319. package/dist/components/themes/cambridge-yle/CambridgeYleAudioPlayer.js +1 -138
  320. package/dist/components/themes/cambridge-yle/CambridgeYleBottomNav.js +1 -12
  321. package/dist/components/themes/cambridge-yle/CambridgeYleExamLayout.js +1 -18
  322. package/dist/components/themes/cambridge-yle/CambridgeYleExampleText.js +1 -11
  323. package/dist/components/themes/cambridge-yle/CambridgeYleHeader.js +1 -11
  324. package/dist/components/themes/cambridge-yle/CambridgeYleInstructionBanner.js +1 -9
  325. package/dist/components/themes/cambridge-yle/CambridgeYleNavButton.js +1 -13
  326. package/dist/components/themes/cambridge-yle/CambridgeYlePartBanner.js +1 -8
  327. package/dist/components/themes/cambridge-yle/CambridgeYleProgressBar.js +1 -6
  328. package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCard.js +1 -5
  329. package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCardFullWidth.js +1 -9
  330. package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.js +1 -41
  331. package/dist/components/themes/cambridge-yle/CambridgeYleTimer.js +1 -25
  332. package/dist/components/themes/cambridge-yle/index.js +1 -13
  333. package/dist/components/themes/english-certification/EcAnswerTheQuestion.js +1 -24
  334. package/dist/components/themes/english-certification/EcMatchByWritingAnswer.js +1 -88
  335. package/dist/components/themes/english-certification/EcWordFillParagraph.js +1 -55
  336. package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -156
  337. package/dist/components/themes/english-certification/EcWritingTask.js +1 -34
  338. package/dist/components/themes/english-certification/EnglishCertificationAudioPlayer.js +1 -114
  339. package/dist/components/themes/english-certification/EnglishCertificationBrand.js +1 -11
  340. package/dist/components/themes/english-certification/EnglishCertificationExamLayout.js +1 -21
  341. package/dist/components/themes/english-certification/EnglishCertificationFlagButton.js +1 -15
  342. package/dist/components/themes/english-certification/EnglishCertificationFooterBar.js +1 -19
  343. package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.js +1 -148
  344. package/dist/components/themes/english-certification/EnglishCertificationHeader.js +1 -31
  345. package/dist/components/themes/english-certification/EnglishCertificationNavigationPanel.js +1 -71
  346. package/dist/components/themes/english-certification/EnglishCertificationOptionSelector.js +1 -33
  347. package/dist/components/themes/english-certification/EnglishCertificationPassagePanel.js +1 -16
  348. package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.js +1 -22
  349. package/dist/components/themes/english-certification/EnglishCertificationQuestionItem.js +1 -37
  350. package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -72
  351. package/dist/components/themes/english-certification/EnglishCertificationReadingSection.js +1 -90
  352. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestion.js +1 -18
  353. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js +1 -29
  354. package/dist/components/themes/english-certification/english-certification-theme.js +1 -58
  355. package/dist/components/themes/english-certification/grouped-question-utils.js +1 -218
  356. package/dist/components/themes/english-certification/index.js +1 -21
  357. package/dist/components/themes/index.js +1 -6
  358. package/dist/components/themes/summer-sky/SummerSkyAudioPlayer.js +1 -170
  359. package/dist/components/themes/summer-sky/SummerSkyLayout.js +1 -221
  360. package/dist/components/themes/summer-sky/SummerSkySubmitModal.js +1 -18
  361. package/dist/components/themes/summer-sky/SummerSkyWaitingRoom.js +1 -194
  362. package/dist/components/themes/types.js +1 -1
  363. package/dist/components/ui/alert-dialog.js +1 -26
  364. package/dist/components/ui/alert.js +1 -22
  365. package/dist/components/ui/avatar.js +1 -12
  366. package/dist/components/ui/badge.js +1 -38
  367. package/dist/components/ui/button.js +1 -35
  368. package/dist/components/ui/calendar.js +1 -76
  369. package/dist/components/ui/card.js +1 -16
  370. package/dist/components/ui/carousel.js +1 -91
  371. package/dist/components/ui/checkbox.js +1 -9
  372. package/dist/components/ui/collapsible.js +1 -13
  373. package/dist/components/ui/command.js +1 -34
  374. package/dist/components/ui/confirm-dialog.js +1 -49
  375. package/dist/components/ui/dialog.js +1 -23
  376. package/dist/components/ui/drawer.js +1 -35
  377. package/dist/components/ui/dropdown-menu.js +1 -33
  378. package/dist/components/ui/file-upload.js +1 -155
  379. package/dist/components/ui/form.js +1 -62
  380. package/dist/components/ui/hover-card.js +1 -10
  381. package/dist/components/ui/image-preview.js +1 -29
  382. package/dist/components/ui/input.js +1 -8
  383. package/dist/components/ui/label.js +1 -9
  384. package/dist/components/ui/language-switcher.js +1 -15
  385. package/dist/components/ui/multi-select.js +1 -90
  386. package/dist/components/ui/points-input.js +1 -33
  387. package/dist/components/ui/popover.js +1 -26
  388. package/dist/components/ui/progress.js +1 -16
  389. package/dist/components/ui/radio-group.js +1 -12
  390. package/dist/components/ui/scroll-area.js +1 -11
  391. package/dist/components/ui/select.js +1 -38
  392. package/dist/components/ui/separator.js +1 -8
  393. package/dist/components/ui/sheet.js +1 -40
  394. package/dist/components/ui/single-select.js +1 -76
  395. package/dist/components/ui/skeleton.js +1 -6
  396. package/dist/components/ui/switch.js +1 -8
  397. package/dist/components/ui/table.js +1 -20
  398. package/dist/components/ui/tabs.js +1 -17
  399. package/dist/components/ui/textarea.js +1 -8
  400. package/dist/components/ui/tooltip.js +1 -11
  401. package/dist/index.d.ts +3 -3
  402. package/dist/index.js +1 -19
  403. package/dist/mcp/config.js +1 -32
  404. package/dist/mcp/http-client.js +1 -48
  405. package/dist/mcp/index.js +1 -29
  406. package/dist/mcp/tools/_helpers.js +1 -25
  407. package/dist/mcp/tools/exams.js +1 -439
  408. package/dist/mcp/tools/index.js +1 -6
  409. package/dist/mcp/tools/results.js +1 -19
  410. package/dist/shared/constants/ApiConstant.js +1 -276
  411. package/dist/shared/constants/QueryKeyConstant.js +1 -112
  412. package/dist/shared/constants/exam-level.enum.js +1 -41
  413. package/dist/shared/constants/landings/placement-test.constants.js +1 -431
  414. package/dist/shared/constants/question-skills.js +1 -267
  415. package/dist/shared/constants/routes.js +1 -81
  416. package/dist/shared/index.d.ts +3 -0
  417. package/dist/shared/index.js +1 -7
  418. package/dist/shared/lib/hooks/index.js +1 -10
  419. package/dist/shared/lib/hooks/useAlertDialog.js +1 -57
  420. package/dist/shared/lib/hooks/useAudioPlayCounter.js +1 -30
  421. package/dist/shared/lib/hooks/useAudioPreview.js +1 -81
  422. package/dist/shared/lib/hooks/useAudioUpload.js +1 -24
  423. package/dist/shared/lib/hooks/useConfirmDialog.js +1 -89
  424. package/dist/shared/lib/hooks/useDebouncedCallback.js +1 -32
  425. package/dist/shared/lib/hooks/useDelayedAutoPlay.js +1 -12
  426. package/dist/shared/lib/hooks/useFileUpload.js +1 -24
  427. package/dist/shared/lib/hooks/useImageUrl.js +1 -5
  428. package/dist/shared/lib/hooks/usePresignedFileUrl.js +1 -10
  429. package/dist/shared/lib/hooks/useReactHookForm.js +1 -31
  430. package/dist/shared/lib/hooks/useToast.js +1 -62
  431. package/dist/shared/lib/i18n/index.js +1 -54
  432. package/dist/shared/lib/i18n/messages/en/admin.js +1 -2104
  433. package/dist/shared/lib/i18n/messages/en/auth.js +1 -86
  434. package/dist/shared/lib/i18n/messages/en/common.js +1 -140
  435. package/dist/shared/lib/i18n/messages/en/file-upload.js +1 -18
  436. package/dist/shared/lib/i18n/messages/en/student.js +1 -133
  437. package/dist/shared/lib/i18n/messages/en/terms.js +1 -37
  438. package/dist/shared/lib/i18n/messages/en.js +1 -15
  439. package/dist/shared/lib/i18n/messages/vi/admin.js +1 -2104
  440. package/dist/shared/lib/i18n/messages/vi/auth.js +1 -86
  441. package/dist/shared/lib/i18n/messages/vi/common.js +1 -140
  442. package/dist/shared/lib/i18n/messages/vi/file-upload.js +1 -18
  443. package/dist/shared/lib/i18n/messages/vi/student.js +1 -133
  444. package/dist/shared/lib/i18n/messages/vi/terms.js +1 -37
  445. package/dist/shared/lib/i18n/messages/vi.js +1 -15
  446. package/dist/shared/lib/i18n/types.js +1 -1
  447. package/dist/shared/lib/stores/examQuestionStore.js +1 -212
  448. package/dist/shared/lib/stores/localeStore.js +1 -10
  449. package/dist/shared/lib/utils/public-page.js +1 -44
  450. package/dist/shared/lib/utils/question-reverse-transform.d.ts +6 -0
  451. package/dist/shared/lib/utils/question-reverse-transform.js +1 -0
  452. package/dist/shared/lib/utils/question-transform-types.js +1 -1
  453. package/dist/shared/lib/utils/question-transform-validation.d.ts +6 -0
  454. package/dist/shared/lib/utils/question-transform-validation.js +1 -0
  455. package/dist/shared/lib/utils/question-transform.d.ts +6 -2
  456. package/dist/shared/lib/utils/question-transform.js +1 -174
  457. package/dist/shared/lib/utils.js +1 -168
  458. package/dist/shared/lib/validation/choose-correct-answer.validation.js +1 -111
  459. package/dist/shared/lib/validation/label-the-picture.validation.js +1 -19
  460. package/dist/shared/lib/validation/listen-and-choose-from-answer-group.validation.js +1 -46
  461. package/dist/shared/lib/validation/listen-and-choose-objects-in-scene.validation.js +1 -21
  462. package/dist/shared/lib/validation/listen-and-drag-objects-into-scene.validation.js +1 -34
  463. package/dist/shared/lib/validation/listen-and-speak-answer.validation.js +1 -40
  464. package/dist/shared/lib/validation/listen-and-speak-compare-images.validation.js +1 -45
  465. package/dist/shared/lib/validation/listen-and-speak-image-group.validation.js +1 -19
  466. package/dist/shared/lib/validation/listen-and-speak-info-exchange.validation.js +1 -39
  467. package/dist/shared/lib/validation/listen-and-speak-odd-one-out.validation.js +1 -32
  468. package/dist/shared/lib/validation/listen-and-speak-question-list.validation.js +1 -19
  469. package/dist/shared/lib/validation/listen-and-speak-with-story-images.validation.js +1 -28
  470. package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.js +1 -12
  471. package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.js +1 -47
  472. package/dist/shared/lib/validation/read-and-color-objects.validation.js +1 -29
  473. package/dist/shared/lib/validation/read-displayed-content.validation.js +1 -28
  474. package/dist/shared/lib/validation/speaking-conversation.validation.js +1 -75
  475. package/dist/shared/lib/validation/speaking-describe-image.validation.js +1 -31
  476. package/dist/shared/lib/validation/spontaneous-qa.validation.js +1 -48
  477. package/dist/shared/lib/validation/word-fill-paragraph-default.validation.js +1 -38
  478. package/dist/shared/lib/validation/word-fill-paragraph-with-options.validation.js +1 -39
  479. package/dist/shared/lib/validation/word-fill-paragraph.validation.js +1 -43
  480. package/dist/shared/lib/validation/word-ordering.validation.js +1 -33
  481. package/dist/shared/types/branch.types.js +1 -6
  482. package/dist/shared/types/common.types.js +1 -50
  483. package/dist/shared/types/entities/exam-schedule.types.js +1 -5
  484. package/dist/shared/types/entities/exam.types.js +1 -1
  485. package/dist/shared/types/entities/question.types.js +1 -4
  486. package/dist/shared/types/entities/result.types.js +1 -4
  487. package/dist/shared/types/entities/user.types.js +1 -4
  488. package/dist/shared/types/exam-taking.types.js +1 -2
  489. package/dist/shared/types/history.types.js +1 -34
  490. package/dist/shared/types/index.js +1 -1
  491. package/dist/shared/types/questions/choose-correct-adjective.js +1 -4
  492. package/dist/shared/types/questions/choose-the-correct-answer.js +1 -9
  493. package/dist/shared/types/questions/fill-missing-words-in-grid.js +1 -11
  494. package/dist/shared/types/questions/index.js +1 -40
  495. package/dist/shared/types/questions/listen-and-speak-answer.js +1 -1
  496. package/dist/shared/types/questions/listen-and-speak-compare-images.js +1 -1
  497. package/dist/shared/types/questions/listen-and-speak-image-group.js +1 -1
  498. package/dist/shared/types/questions/listen-and-speak-info-exchange.js +1 -3
  499. package/dist/shared/types/questions/listen-and-speak-odd-one-out.js +1 -3
  500. package/dist/shared/types/questions/listen-and-speak-question-list.js +1 -1
  501. package/dist/shared/types/questions/listen-and-speak-with-story-images.js +1 -3
  502. package/dist/shared/types/questions/look-picture-choose-correct-answer.js +1 -5
  503. package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.js +1 -9
  504. package/dist/shared/types/questions/look-picture-fill-word-hint.js +1 -7
  505. package/dist/shared/types/questions/read-displayed-content.js +1 -1
  506. package/dist/shared/types/questions/speaking-conversation.js +1 -7
  507. package/dist/shared/types/questions/speaking-describe-image.js +1 -1
  508. package/dist/shared/types/questions/spontaneous-qa.js +1 -1
  509. package/dist/shared/types/questions/write-correct-verb-form.js +1 -12
  510. package/dist/shared/types/role.types.js +1 -1
  511. package/dist/shared/types/structure-management.js +1 -28
  512. package/dist/shared/types/student.types.js +1 -54
  513. package/dist/shared/types/teacher-dashboard-rooms.js +1 -2
  514. package/package.json +12 -3
@@ -1,2 +1 @@
1
- export * from './LookPictureFillWordHintCreator';
2
- export * from './LookPictureFillWordHintClient';
1
+ export*from"./LookPictureFillWordHintCreator";export*from"./LookPictureFillWordHintClient";
@@ -1,82 +1 @@
1
- import { LookPictureFillWordHint } from './LookPictureFillWordHintCreator';
2
- export const lookPictureFillWordHintRegistration = {
3
- component: LookPictureFillWordHint,
4
- transformInitialData: (initialData) => {
5
- const content = initialData?.content;
6
- const answer = initialData?.answer;
7
- // Get hintLetters from various sources
8
- const hintLettersFromGroup = initialData?.questionGroup?.payload?.hintLetters;
9
- const hintLettersFromAnswer = answer?.hintLetters;
10
- const hintLettersFallback = content?.hintLetters;
11
- const hintLetters = hintLettersFromGroup || hintLettersFromAnswer || hintLettersFallback || [];
12
- const apiPoints = initialData?.total_points
13
- ? parseFloat(initialData.total_points)
14
- : (initialData?.points || 1);
15
- // PRIORITY 1: Store format - answer has subQuestions
16
- if (answer?.subQuestions && answer.subQuestions.length > 0) {
17
- return {
18
- subQuestions: answer.subQuestions,
19
- hintLetters: hintLetters.length > 0 ? hintLetters : answer.hintLetters || [],
20
- caseSensitive: answer?.caseSensitive ?? false,
21
- points: apiPoints,
22
- explanation: answer?.explanation || initialData?.explanation || '',
23
- };
24
- }
25
- // PRIORITY 2: API format - content has imageUrl/word
26
- else if (content && (content.imageUrl !== undefined || content.word !== undefined)) {
27
- return {
28
- content: {
29
- imageUrl: content.imageUrl || '',
30
- word: content.word || '',
31
- },
32
- answer: {
33
- correctAnswer: answer?.correctAnswer || '',
34
- caseSensitive: answer?.caseSensitive ?? false,
35
- hintLetters,
36
- explanation: answer?.explanation || initialData?.explanation || '',
37
- },
38
- hintLetters,
39
- caseSensitive: answer?.caseSensitive ?? false,
40
- points: apiPoints,
41
- explanation: answer?.explanation || initialData?.explanation || '',
42
- };
43
- }
44
- // PRIORITY 3: Fallback
45
- else {
46
- return {
47
- ...answer,
48
- hintLetters,
49
- caseSensitive: answer?.caseSensitive ?? false,
50
- points: apiPoints,
51
- explanation: answer?.explanation || initialData?.explanation || '',
52
- };
53
- }
54
- },
55
- getExtraProps: (ctx) => ({
56
- groups: ctx.groups,
57
- questionIndexInPart: ctx.questionIndexInPart,
58
- partId: ctx.partId,
59
- onUnsavedChangesChange: ctx.onUnsavedChangesChange,
60
- validationRef: ctx.validationRef,
61
- }),
62
- wrapOnSave: (data, ctx) => ({
63
- type: ctx.questionType,
64
- content: ctx.state.content,
65
- points: data?.points ?? ctx.state.points ?? 1,
66
- level: ctx.state.level,
67
- difficulty: ctx.state.difficulty,
68
- skill: ctx.state.skill,
69
- answer: data,
70
- explanation: data?.explanation || '',
71
- }),
72
- wrapOnChange: (data, ctx) => ({
73
- type: ctx.questionType,
74
- content: ctx.state.content,
75
- points: data?.points ?? ctx.state.points ?? 1,
76
- level: ctx.state.level,
77
- difficulty: ctx.state.difficulty,
78
- skill: ctx.state.skill,
79
- answer: data,
80
- explanation: data?.explanation || '',
81
- }),
82
- };
1
+ import{LookPictureFillWordHint as t}from"./LookPictureFillWordHintCreator";export const lookPictureFillWordHintRegistration={component:t,transformInitialData:t=>{const e=t?.content,n=t?.answer,i=t?.questionGroup?.payload?.hintLetters,a=n?.hintLetters,s=e?.hintLetters,o=i||a||s||[],l=t?.total_points?parseFloat(t.total_points):t?.points||1;return n?.subQuestions&&n.subQuestions.length>0?{subQuestions:n.subQuestions,hintLetters:o.length>0?o:n.hintLetters||[],caseSensitive:n?.caseSensitive??!1,points:l,explanation:n?.explanation||t?.explanation||""}:!e||void 0===e.imageUrl&&void 0===e.word?{...n,hintLetters:o,caseSensitive:n?.caseSensitive??!1,points:l,explanation:n?.explanation||t?.explanation||""}:{content:{imageUrl:e.imageUrl||"",word:e.word||""},answer:{correctAnswer:n?.correctAnswer||"",caseSensitive:n?.caseSensitive??!1,hintLetters:o,explanation:n?.explanation||t?.explanation||""},hintLetters:o,caseSensitive:n?.caseSensitive??!1,points:l,explanation:n?.explanation||t?.explanation||""}},getExtraProps:t=>({groups:t.groups,questionIndexInPart:t.questionIndexInPart,partId:t.partId,onUnsavedChangesChange:t.onUnsavedChangesChange,validationRef:t.validationRef}),wrapOnSave:(t,e)=>({type:e.questionType,content:e.state.content,points:t?.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:t,explanation:t?.explanation||""}),wrapOnChange:(t,e)=>({type:e.questionType,content:e.state.content,points:t?.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:t,explanation:t?.explanation||""})};
@@ -1,29 +1 @@
1
- export const transformLookPictureFillWordHint = (question) => {
2
- const answerData = question.answer;
3
- if (!answerData?.subQuestions || answerData.subQuestions.length === 0) {
4
- return { apiContent: {}, apiCorrectAnswer: {} };
5
- }
6
- const sq = answerData.subQuestions[0];
7
- const apiContent = {
8
- imageUrl: sq.imageUrl,
9
- word: sq.word,
10
- };
11
- const groupNumber = sq.groupNumber || 1;
12
- const hintLettersByGroup = answerData.hintLettersByGroup;
13
- let hintLetters = [];
14
- if (hintLettersByGroup && hintLettersByGroup[groupNumber]) {
15
- hintLetters = hintLettersByGroup[groupNumber];
16
- }
17
- else if (answerData.hintLetters) {
18
- hintLetters = answerData.hintLetters;
19
- }
20
- return {
21
- apiContent,
22
- apiCorrectAnswer: {
23
- correctAnswer: sq.correctAnswer || '',
24
- caseSensitive: answerData.caseSensitive || false,
25
- },
26
- hintLetters,
27
- groupNumber,
28
- };
29
- };
1
+ export const transformLookPictureFillWordHint=e=>{const t=e.answer;if(!t?.subQuestions||0===t.subQuestions.length)return{apiContent:{},apiCorrectAnswer:{}};const r=t.subQuestions[0],n={imageUrl:r.imageUrl,word:r.word},s=r.groupNumber||1,o=t.hintLettersByGroup;let i=[];return o&&o[s]?i=o[s]:t.hintLetters&&(i=t.hintLetters),{apiContent:n,apiCorrectAnswer:{correctAnswer:r.correctAnswer||"",caseSensitive:t.caseSensitive||!1},hintLetters:i,groupNumber:s}};
@@ -1,38 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Card, CardContent } from '../../../../components/ui/card';
4
- import { Input } from '../../../../components/ui/input';
5
- import { Label } from '../../../../components/ui/label';
6
- import { CheckCircle2, XCircle, BookOpen } from 'lucide-react';
7
- import { usePresignedFileUrl } from '../../../../shared/lib/hooks';
8
- import { useState } from 'react';
9
- function OptionCard({ option }) {
10
- const { previewUrl } = usePresignedFileUrl(option.imageUrl || '');
11
- const displayUrl = previewUrl || option.imageUrl;
12
- if (displayUrl) {
13
- return (_jsxs("div", { className: "flex flex-col items-center gap-2 rounded-xl border border-gray-200 bg-white p-3 shadow-sm", children: [_jsx("div", { className: "relative h-24 w-24 overflow-hidden rounded-lg bg-gray-50", children: _jsx("img", { src: displayUrl, alt: option.answer, className: "h-full w-full object-contain" }) }), _jsx("span", { className: "text-sm font-semibold text-gray-700", children: option.answer }), option.content && (_jsx("span", { className: "text-xs text-gray-500 text-center line-clamp-2", children: option.content }))] }));
14
- }
15
- return (_jsxs("div", { className: "flex items-center gap-2.5 rounded-xl border border-gray-200 bg-white px-4 py-3 shadow-sm", children: [_jsx("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-teal-500 to-cyan-600 text-sm font-bold text-white shadow-sm", children: option.answer?.[0] ?? '?' }), _jsxs("div", { className: "min-w-0", children: [_jsx("span", { className: "block text-sm font-semibold text-gray-800", children: option.answer }), option.content && (_jsx("span", { className: "block truncate text-xs text-gray-500", children: option.content }))] })] }));
16
- }
17
- export function MatchByWritingAnswerClient({ questionData, onSubmit, isReviewMode = false, userAnswer, autoFillCorrectAnswers = false, explanation, }) {
18
- const [answer, setAnswer] = useState(userAnswer || '');
19
- const { previewUrl: questionImageUrl } = usePresignedFileUrl(questionData.imageUrl || '');
20
- if (!questionData.question) {
21
- return (_jsx(Card, { children: _jsx(CardContent, { className: "p-6", children: _jsx("p", { className: "text-gray-500", children: "Kh\u00F4ng c\u00F3 d\u1EEF li\u1EC7u c\u00E2u h\u1ECFi" }) }) }));
22
- }
23
- const isExample = questionData.isExample || false;
24
- const displayedAnswer = autoFillCorrectAnswers || isExample
25
- ? questionData.correctAnswer
26
- : answer;
27
- const isCorrect = isReviewMode && userAnswer !== undefined
28
- ? userAnswer.trim().toLowerCase() === questionData.correctAnswer.trim().toLowerCase()
29
- : undefined;
30
- return (_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg", children: [_jsx("div", { className: "h-1 bg-gradient-to-r from-teal-400 to-cyan-500" }), _jsxs(CardContent, { className: "p-6 space-y-6", children: [questionData.options && questionData.options.length > 0 && (_jsxs("div", { className: "rounded-xl border border-purple-200 bg-gradient-to-r from-purple-50 to-violet-50 p-4", children: [_jsx("p", { className: "mb-3 text-sm font-semibold text-purple-700", children: "C\u00E1c l\u1EF1a ch\u1ECDn:" }), _jsx("div", { className: `grid gap-3 ${questionData.options.some((o) => o.imageUrl) ? 'grid-cols-2 sm:grid-cols-3 md:grid-cols-4' : 'grid-cols-1 sm:grid-cols-2'}`, children: questionData.options.map((option, index) => (_jsx(OptionCard, { option: option }, index))) })] })), _jsxs("div", { className: "rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-5", children: [isExample && (_jsxs("div", { className: "mb-2 inline-flex items-center gap-1.5 rounded-full bg-amber-100 border border-amber-300 px-3 py-1", children: [_jsx(BookOpen, { className: "h-3.5 w-3.5 text-amber-600" }), _jsx("span", { className: "text-xs font-semibold text-amber-700 uppercase tracking-wide", children: "Example" })] })), _jsxs("div", { className: "flex items-center gap-4", children: [(questionImageUrl || questionData.imageUrl) ? (_jsx("div", { className: "relative h-20 w-20 flex-shrink-0 overflow-hidden rounded-lg border border-gray-200 bg-gray-50 shadow-sm", children: _jsx("img", { src: questionImageUrl || questionData.imageUrl, alt: questionData.question, className: "h-full w-full object-contain" }) })) : null, _jsxs("div", { className: "flex-1 space-y-2", children: [_jsx(Label, { className: "text-base font-semibold text-gray-800", children: questionData.question }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Input, { value: displayedAnswer, onChange: (e) => {
31
- setAnswer(e.target.value);
32
- onSubmit?.(e.target.value);
33
- }, placeholder: "Vi\u1EBFt \u0111\u00E1p \u00E1n...", disabled: isReviewMode || isExample, className: `max-w-xs border-2 text-lg font-medium ${isReviewMode
34
- ? isCorrect
35
- ? 'border-green-400 bg-green-50 text-green-700'
36
- : 'border-red-400 bg-red-50 text-red-700'
37
- : 'border-teal-300 focus:border-teal-500 focus:ring-teal-200'}` }), isReviewMode && isCorrect !== undefined && (_jsx("span", { className: "flex items-center gap-1", children: isCorrect ? (_jsx(CheckCircle2, { className: "h-5 w-5 text-green-500" })) : (_jsx(XCircle, { className: "h-5 w-5 text-red-500" })) }))] })] })] }), isReviewMode && isCorrect === false && (_jsxs("div", { className: "mt-3 flex items-center gap-2 rounded-lg bg-green-50 border border-green-200 px-4 py-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-green-600" }), _jsxs("span", { className: "text-sm text-green-700", children: ["\u0110\u00E1p \u00E1n \u0111\u00FAng: ", _jsx("strong", { children: questionData.correctAnswer })] })] })), autoFillCorrectAnswers && (_jsxs("div", { className: "mt-3 flex items-center gap-2 rounded-lg bg-teal-50 border border-teal-200 px-4 py-2", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-teal-600" }), _jsxs("span", { className: "text-sm text-teal-700", children: ["\u0110\u00E1p \u00E1n: ", _jsx("strong", { children: questionData.correctAnswer })] })] }))] }), explanation && isReviewMode && (_jsxs("div", { className: "rounded-xl border border-blue-200 bg-blue-50 p-4", children: [_jsx("p", { className: "text-sm font-semibold text-blue-800 mb-1", children: "Gi\u1EA3i th\u00EDch:" }), _jsx("p", { className: "text-sm text-blue-700", children: explanation })] }))] })] }));
38
- }
1
+ "use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{Card as t,CardContent as a}from"../../../../components/ui/card";import{Input as s}from"../../../../components/ui/input";import{Label as l}from"../../../../components/ui/label";import{CheckCircle2 as n,XCircle as i,BookOpen as o}from"lucide-react";import{usePresignedFileUrl as c}from"../../../../shared/lib/hooks";import{useState as d}from"react";function m({option:t}){const{previewUrl:a}=c(t.imageUrl||""),s=a||t.imageUrl;return r("div",s?{className:"flex flex-col items-center gap-2 rounded-xl border border-gray-200 bg-white p-3 shadow-sm",children:[e("div",{className:"relative h-24 w-24 overflow-hidden rounded-lg bg-gray-50",children:e("img",{src:s,alt:t.answer,className:"h-full w-full object-contain"})}),e("span",{className:"text-sm font-semibold text-gray-700",children:t.answer}),t.content&&e("span",{className:"text-xs text-gray-500 text-center line-clamp-2",children:t.content})]}:{className:"flex items-center gap-2.5 rounded-xl border border-gray-200 bg-white px-4 py-3 shadow-sm",children:[e("div",{className:"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-teal-500 to-cyan-600 text-sm font-bold text-white shadow-sm",children:t.answer?.[0]??"?"}),r("div",{className:"min-w-0",children:[e("span",{className:"block text-sm font-semibold text-gray-800",children:t.answer}),t.content&&e("span",{className:"block truncate text-xs text-gray-500",children:t.content})]})]})}export function MatchByWritingAnswerClient({questionData:g,onSubmit:p,isReviewMode:h=!1,userAnswer:b,autoFillCorrectAnswers:x=!1,explanation:u}){const[f,w]=d(b||""),{previewUrl:N}=c(g.imageUrl||"");if(!g.question)return e(t,{children:e(a,{className:"p-6",children:e("p",{className:"text-gray-500",children:"Không có dữ liệu câu hỏi"})})});const v=g.isExample||!1,y=x||v?g.correctAnswer:f,U=h&&void 0!==b?b.trim().toLowerCase()===g.correctAnswer.trim().toLowerCase():void 0;return r(t,{className:"overflow-hidden border-0 bg-white shadow-lg",children:[e("div",{className:"h-1 bg-gradient-to-r from-teal-400 to-cyan-500"}),r(a,{className:"p-6 space-y-6",children:[g.options&&g.options.length>0&&r("div",{className:"rounded-xl border border-purple-200 bg-gradient-to-r from-purple-50 to-violet-50 p-4",children:[e("p",{className:"mb-3 text-sm font-semibold text-purple-700",children:"Các lựa chọn:"}),e("div",{className:"grid gap-3 "+(g.options.some(e=>e.imageUrl)?"grid-cols-2 sm:grid-cols-3 md:grid-cols-4":"grid-cols-1 sm:grid-cols-2"),children:g.options.map((r,t)=>e(m,{option:r},t))})]}),r("div",{className:"rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-5",children:[v&&r("div",{className:"mb-2 inline-flex items-center gap-1.5 rounded-full bg-amber-100 border border-amber-300 px-3 py-1",children:[e(o,{className:"h-3.5 w-3.5 text-amber-600"}),e("span",{className:"text-xs font-semibold text-amber-700 uppercase tracking-wide",children:"Example"})]}),r("div",{className:"flex items-center gap-4",children:[N||g.imageUrl?e("div",{className:"relative h-20 w-20 flex-shrink-0 overflow-hidden rounded-lg border border-gray-200 bg-gray-50 shadow-sm",children:e("img",{src:N||g.imageUrl,alt:g.question,className:"h-full w-full object-contain"})}):null,r("div",{className:"flex-1 space-y-2",children:[e(l,{className:"text-base font-semibold text-gray-800",children:g.question}),r("div",{className:"flex items-center gap-3",children:[e(s,{value:y,onChange:e=>{w(e.target.value),p?.(e.target.value)},placeholder:"Viết đáp án...",disabled:h||v,className:"max-w-xs border-2 text-lg font-medium "+(h?U?"border-green-400 bg-green-50 text-green-700":"border-red-400 bg-red-50 text-red-700":"border-teal-300 focus:border-teal-500 focus:ring-teal-200")}),h&&void 0!==U&&e("span",{className:"flex items-center gap-1",children:U?e(n,{className:"h-5 w-5 text-green-500"}):e(i,{className:"h-5 w-5 text-red-500"})})]})]})]}),h&&!1===U&&r("div",{className:"mt-3 flex items-center gap-2 rounded-lg bg-green-50 border border-green-200 px-4 py-2",children:[e(n,{className:"h-4 w-4 text-green-600"}),r("span",{className:"text-sm text-green-700",children:["Đáp án đúng: ",e("strong",{children:g.correctAnswer})]})]}),x&&r("div",{className:"mt-3 flex items-center gap-2 rounded-lg bg-teal-50 border border-teal-200 px-4 py-2",children:[e(n,{className:"h-4 w-4 text-teal-600"}),r("span",{className:"text-sm text-teal-700",children:["Đáp án: ",e("strong",{children:g.correctAnswer})]})]})]}),u&&h&&r("div",{className:"rounded-xl border border-blue-200 bg-blue-50 p-4",children:[e("p",{className:"text-sm font-semibold text-blue-800 mb-1",children:"Giải thích:"}),e("p",{className:"text-sm text-blue-700",children:u})]})]})]})}
@@ -1,359 +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 } 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 { Pencil, Eye, ImageIcon, MessageSquare, HelpCircle, BookOpen, Grid3X3, Users } from 'lucide-react';
12
- import { FileUpload } from '../../../../components/ui/file-upload';
13
- import { Checkbox } from '../../../../components/ui/checkbox';
14
- import { MatchByWritingAnswerClient } from './MatchByWritingAnswerClient';
15
- import { MatchAnswerGroupCard } from '../../groups/MatchAnswerGroupCard';
16
- import { useDebouncedCallback, usePresignedFileUrl } from '../../../../shared/lib/hooks';
17
- import { useExamQuestionStore } from '../../../../shared/lib/stores/examQuestionStore';
18
- // Helper: Calculate group number for a question index based on groups config
19
- function getGroupNumberForIndex(questionIndex, groups) {
20
- if (!groups || groups.length === 0) {
21
- return 1;
22
- }
23
- let currentIndex = 0;
24
- for (const group of groups) {
25
- if (questionIndex < currentIndex + group.questionCount) {
26
- return group.number;
27
- }
28
- currentIndex += group.questionCount;
29
- }
30
- return groups[groups.length - 1]?.number || 1;
31
- }
32
- function MatchByWritingAnswerContent({ initialData, onSave, onSaveToQuestionBank, onCancel, onChange, onUnsavedChangesChange, externalErrors, groups, groupConfig, questionConfig, viewMode, questionIndexInPart = 0, partId = '', validationRef, headerExtra, }) {
33
- // Access exam question store for shared data
34
- const setSharedPassageData = useExamQuestionStore((state) => state.setSharedPassageData);
35
- const getSharedPassageData = useExamQuestionStore((state) => state.getSharedPassageData);
36
- // Get current group number
37
- const initialGroupNum = getGroupNumberForIndex(questionIndexInPart, groups);
38
- // Per-question state
39
- const [question, setQuestion] = useState(initialData?.question || '');
40
- const [imageUrl, setImageUrl] = useState(initialData?.imageUrl || '');
41
- const [correctAnswer, setCorrectAnswer] = useState(initialData?.correctAnswer || '');
42
- const [points, setPoints] = useState(initialData?.points || 1);
43
- const [isExample, setIsExample] = useState(initialData?.isExample || false);
44
- const [groupNumber, setGroupNumber] = useState(initialData?.groupNumber || initialGroupNum);
45
- const [explanation, setExplanation] = useState(initialData?.explanation || '');
46
- const [askerName, setAskerName] = useState(initialData?.askerName || '');
47
- const [answererName, setAnswererName] = useState(initialData?.answererName || '');
48
- // Shared options state (stored via exam question store)
49
- const [options, setOptions] = useState(() => {
50
- // Priority 1: Check shared data from store
51
- if (partId) {
52
- const storedData = getSharedPassageData(partId, initialGroupNum);
53
- if (storedData?.options && Array.isArray(storedData.options)) {
54
- return storedData.options;
55
- }
56
- }
57
- // Priority 2: From initialData
58
- return initialData?.options || [];
59
- });
60
- // Group image URL state (shared across all questions in the group)
61
- const [groupImageUrl, setGroupImageUrl] = useState(() => {
62
- if (partId) {
63
- const storedData = getSharedPassageData(partId, initialGroupNum);
64
- if (storedData?.groupImageUrl) {
65
- return storedData.groupImageUrl;
66
- }
67
- }
68
- return initialData?.groupImageUrl || '';
69
- });
70
- const [groupImagePreviewUrl, setGroupImagePreviewUrl] = useState('');
71
- // Group title state (shared across all questions in the group)
72
- const [groupTitle, setGroupTitle] = useState(() => {
73
- if (partId) {
74
- const storedData = getSharedPassageData(partId, initialGroupNum);
75
- if (storedData?.groupTitle) {
76
- return storedData.groupTitle;
77
- }
78
- }
79
- return initialData?.groupTitle || '';
80
- });
81
- // Whether to show shared group fields
82
- const showGroupImageUrl = groupConfig?.includes('groupImageUrl') ?? false;
83
- const showGroupTitle = groupConfig?.includes('groupTitle') ?? false;
84
- // UI State
85
- const [isClientMode, setIsClientMode] = useState(false);
86
- const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
87
- const [imagePreviewUrl, setImagePreviewUrl] = useState('');
88
- // Inline validation errors
89
- const [validationErrors, setValidationErrors] = useState({});
90
- // Refs
91
- const savedStateRef = useRef('');
92
- const previousInitialDataRef = useRef(initialData);
93
- const previousQuestionIndexRef = useRef(questionIndexInPart);
94
- const isInitializingRef = useRef(false);
95
- const hasInitializedRef = useRef(false);
96
- const onChangeRef = useRef(onChange);
97
- const previousPayloadRef = useRef('');
98
- const onUnsavedChangesChangeRef = useRef(onUnsavedChangesChange);
99
- const currentGroupNumber = groupNumber || 1;
100
- // Determine which per-question fields to show based on questionConfig
101
- // Default: show all fields if questionConfig is not provided
102
- const showQuestionField = !questionConfig || questionConfig.includes('question');
103
- const showImageUrlField = !questionConfig || questionConfig.includes('imageUrl');
104
- const showAnswerField = !questionConfig || questionConfig.includes('answer');
105
- // Presigned URL for per-question image preview
106
- const { previewUrl: generatedPreviewUrl } = usePresignedFileUrl(imageUrl);
107
- const displayPreviewUrl = imagePreviewUrl || generatedPreviewUrl || '';
108
- useEffect(() => { onUnsavedChangesChangeRef.current = onUnsavedChangesChange; }, [onUnsavedChangesChange]);
109
- useEffect(() => { onChangeRef.current = onChange; }, [onChange]);
110
- const debouncedOnChange = useDebouncedCallback((data) => {
111
- onChangeRef.current?.(data);
112
- }, 300);
113
- // Helper to get current state string
114
- const getCurrentStateString = () => {
115
- return JSON.stringify({
116
- question,
117
- imageUrl,
118
- correctAnswer,
119
- points,
120
- isExample,
121
- askerName,
122
- answererName,
123
- options,
124
- groupImageUrl,
125
- groupTitle,
126
- });
127
- };
128
- // Initialize saved state when questionIndexInPart changes
129
- useEffect(() => {
130
- if (isInitializingRef.current)
131
- return;
132
- const timer = setTimeout(() => {
133
- savedStateRef.current = getCurrentStateString();
134
- setHasUnsavedChanges(false);
135
- }, 150);
136
- return () => clearTimeout(timer);
137
- }, [questionIndexInPart]);
138
- // Detect unsaved changes
139
- useEffect(() => {
140
- if (isInitializingRef.current)
141
- return;
142
- if (!savedStateRef.current)
143
- return;
144
- const currentState = getCurrentStateString();
145
- const hasChanges = currentState !== savedStateRef.current;
146
- if (hasChanges !== hasUnsavedChanges) {
147
- setHasUnsavedChanges(hasChanges);
148
- onUnsavedChangesChangeRef.current?.(hasChanges);
149
- }
150
- }, [question, imageUrl, correctAnswer, points, isExample, askerName, answererName, options, groupImageUrl, groupTitle, hasUnsavedChanges]);
151
- // Expose validation function via ref
152
- useEffect(() => {
153
- if (validationRef) {
154
- validationRef.current = {
155
- triggerValidation: async () => {
156
- const errors = {};
157
- let isValid = true;
158
- if (showQuestionField && (!question || question.trim() === '')) {
159
- errors.question = 'Vui lòng nhập tên/câu hỏi';
160
- isValid = false;
161
- }
162
- if (showAnswerField && (!correctAnswer || correctAnswer.trim() === '')) {
163
- errors.correctAnswer = 'Vui lòng nhập đáp án';
164
- isValid = false;
165
- }
166
- setValidationErrors(errors);
167
- return isValid;
168
- },
169
- getFormData: () => ({
170
- question,
171
- imageUrl,
172
- correctAnswer,
173
- points,
174
- groupNumber: currentGroupNumber,
175
- isExample,
176
- askerName,
177
- answererName,
178
- options,
179
- groupImageUrl,
180
- groupTitle,
181
- explanation,
182
- groups,
183
- }),
184
- };
185
- }
186
- }, [validationRef, question, imageUrl, correctAnswer, points, currentGroupNumber, isExample, askerName, answererName, options, groupImageUrl, groupTitle, explanation, groups]);
187
- // Sync from initialData when navigation or first init
188
- useEffect(() => {
189
- const questionIndexChanged = questionIndexInPart !== previousQuestionIndexRef.current;
190
- const hasValidInitialData = !!initialData?.question;
191
- const shouldSyncForFirstInit = !hasInitializedRef.current && hasValidInitialData;
192
- const shouldSyncForNavigation = questionIndexChanged;
193
- if (!shouldSyncForFirstInit && !shouldSyncForNavigation)
194
- return;
195
- isInitializingRef.current = true;
196
- previousInitialDataRef.current = initialData;
197
- previousQuestionIndexRef.current = questionIndexInPart;
198
- hasInitializedRef.current = true;
199
- const groupNum = getGroupNumberForIndex(questionIndexInPart, groups);
200
- // Set per-question state
201
- setQuestion(initialData?.question || '');
202
- setImageUrl(initialData?.imageUrl || '');
203
- setCorrectAnswer(initialData?.correctAnswer || '');
204
- setPoints(initialData?.points || 1);
205
- setIsExample(initialData?.isExample || false);
206
- setGroupNumber(groupNum);
207
- setExplanation(initialData?.explanation || '');
208
- setAskerName(initialData?.askerName || '');
209
- setAnswererName(initialData?.answererName || '');
210
- // Handle shared options, groupImageUrl & groupTitle
211
- let sharedOptions = [];
212
- let sharedGroupImageUrl = '';
213
- let sharedGroupTitle = '';
214
- if (partId) {
215
- const storedData = getSharedPassageData(partId, groupNum);
216
- if (storedData?.options && Array.isArray(storedData.options)) {
217
- sharedOptions = storedData.options;
218
- sharedGroupImageUrl = storedData?.groupImageUrl || '';
219
- sharedGroupTitle = storedData?.groupTitle || '';
220
- }
221
- else {
222
- sharedOptions = initialData?.options || [];
223
- sharedGroupImageUrl = initialData?.groupImageUrl || '';
224
- sharedGroupTitle = initialData?.groupTitle || '';
225
- if (sharedOptions.length > 0 || sharedGroupImageUrl || sharedGroupTitle) {
226
- setSharedPassageData(partId, groupNum, { options: sharedOptions, groupImageUrl: sharedGroupImageUrl, groupTitle: sharedGroupTitle });
227
- }
228
- }
229
- }
230
- else {
231
- sharedOptions = initialData?.options || [];
232
- sharedGroupImageUrl = initialData?.groupImageUrl || '';
233
- sharedGroupTitle = initialData?.groupTitle || '';
234
- }
235
- setOptions(sharedOptions);
236
- setGroupImageUrl(sharedGroupImageUrl);
237
- setGroupTitle(sharedGroupTitle);
238
- setTimeout(() => { isInitializingRef.current = false; }, 100);
239
- }, [initialData, groups, questionIndexInPart, partId, getSharedPassageData, setSharedPassageData]);
240
- // Call onChange when data changes
241
- useEffect(() => {
242
- if (isInitializingRef.current)
243
- return;
244
- const payload = {
245
- question,
246
- imageUrl,
247
- correctAnswer,
248
- points: points || 1,
249
- groupNumber: currentGroupNumber,
250
- isExample,
251
- askerName,
252
- answererName,
253
- options,
254
- groupImageUrl,
255
- groupTitle,
256
- explanation,
257
- groups,
258
- };
259
- const payloadString = JSON.stringify(payload);
260
- if (previousPayloadRef.current !== payloadString) {
261
- previousPayloadRef.current = payloadString;
262
- // Save shared data to store
263
- if (partId) {
264
- setSharedPassageData(partId, currentGroupNumber, { options, groupImageUrl, groupTitle });
265
- }
266
- debouncedOnChange(payload);
267
- }
268
- }, [question, imageUrl, correctAnswer, points, currentGroupNumber, isExample, askerName, answererName, options, groupImageUrl, groupTitle, explanation, groups, partId, setSharedPassageData, debouncedOnChange]);
269
- // Update option
270
- const updateOption = (index, field, value) => {
271
- setOptions((prev) => {
272
- const updated = [...prev];
273
- updated[index] = { ...updated[index], [field]: value };
274
- return updated;
275
- });
276
- };
277
- // Add option
278
- const addOption = () => {
279
- const nextNumber = String(options.length + 1); // 1, 2, 3...
280
- setOptions((prev) => [...prev, { answer: '', content: '', imageUrl: '' }]);
281
- };
282
- // Remove option
283
- const removeOption = (index) => {
284
- setOptions((prev) => prev.filter((_, i) => i !== index));
285
- };
286
- // Validate all fields
287
- const validate = () => {
288
- const errors = {};
289
- let isValid = true;
290
- if (showQuestionField && (!question || question.trim() === '')) {
291
- errors.question = 'Vui lòng nhập tên/câu hỏi';
292
- isValid = false;
293
- }
294
- if (showAnswerField && (!correctAnswer || correctAnswer.trim() === '')) {
295
- errors.correctAnswer = 'Vui lòng nhập đáp án';
296
- isValid = false;
297
- }
298
- setValidationErrors(errors);
299
- return isValid;
300
- };
301
- // Handle save
302
- const handleSave = () => {
303
- if (!validate())
304
- return;
305
- const payload = {
306
- question,
307
- imageUrl,
308
- correctAnswer,
309
- points: points || 1,
310
- groupNumber: currentGroupNumber,
311
- isExample,
312
- askerName,
313
- answererName,
314
- options,
315
- groupImageUrl,
316
- groupTitle,
317
- explanation,
318
- groups,
319
- };
320
- savedStateRef.current = getCurrentStateString();
321
- setHasUnsavedChanges(false);
322
- onSave?.(payload);
323
- };
324
- // Client mode preview
325
- if (isClientMode) {
326
- const questionData = {
327
- question,
328
- imageUrl: displayPreviewUrl || imageUrl,
329
- correctAnswer,
330
- points,
331
- groupNumber: currentGroupNumber,
332
- isExample,
333
- options,
334
- };
335
- 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: "Match by Writing 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(MatchByWritingAnswerClient, { questionData: questionData, isReviewMode: true, autoFillCorrectAnswers: true, explanation: explanation })] }));
336
- }
337
- // Creator UI
338
- return (_jsxs("div", { className: "space-y-4", children: [groups && groups.length > 0 && (_jsx(MatchAnswerGroupCard, { currentGroupNumber: currentGroupNumber, groupTitle: groupTitle, groupImageUrl: groupImageUrl, groupImagePreviewUrl: groupImagePreviewUrl, options: options, groupConfig: groupConfig, showGroupTitle: showGroupTitle, showGroupImageUrl: showGroupImageUrl, onGroupTitleChange: setGroupTitle, onGroupImageChange: setGroupImageUrl, onGroupImagePreviewUrlChange: setGroupImagePreviewUrl, onUpdateOption: updateOption, onRemoveOption: removeOption, onAddOption: addOption })), _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-blue-600 shadow-sm", children: _jsx(Grid3X3, { className: "h-4 w-4 text-white" }) }), _jsxs("div", { children: [_jsx(CardTitle, { className: "text-base font-bold text-gray-900", children: "Gh\u00E9p \u0111\u00E1p \u00E1n b\u1EB1ng c\u00E1ch vi\u1EBFt" }), _jsx("p", { className: "text-xs text-gray-500", children: "Nh\u00ECn h\u00ECnh v\u00E0 vi\u1EBFt \u0111\u00E1p \u00E1n t\u01B0\u01A1ng \u1EE9ng" })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [headerExtra, _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setIsClientMode(true), disabled: !question, className: "gap-2 border-teal-200 text-teal-600 hover:bg-teal-50 hover:text-teal-700", children: [_jsx(Eye, { className: "h-4 w-4" }), "Xem tr\u01B0\u1EDBc"] })] })] }) }), _jsxs(CardContent, { className: "space-y-4 px-4 pb-4", children: [_jsxs("div", { className: "flex items-center gap-6", children: [_jsx(PointsInput, { value: points || 1, onChange: (e) => setPoints(parseFloat(e.target.value) || 1) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Checkbox, { id: "isExample", checked: isExample || false, onCheckedChange: (checked) => setIsExample(!!checked) }), _jsx(Label, { htmlFor: "isExample", className: "flex items-center gap-1.5 cursor-pointer text-sm font-medium text-gray-700", children: "\u0110\u00E1nh d\u1EA5u l\u00E0 c\u00E2u h\u1ECFi Example" })] })] }), 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: [_jsx(Label, { htmlFor: "askerName", className: "text-sm font-medium text-gray-600", children: "T\u00EAn ng\u01B0\u1EDDi h\u1ECFi" }), _jsx(Input, { id: "askerName", value: askerName, onChange: (e) => setAskerName(e.target.value), placeholder: "VD: John, Mary, Teacher...", className: "border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200" })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "answererName", className: "text-sm font-medium text-gray-600", children: "T\u00EAn ng\u01B0\u1EDDi tr\u1EA3 l\u1EDDi" }), _jsx(Input, { id: "answererName", value: answererName, onChange: (e) => setAnswererName(e.target.value), placeholder: "VD: Tom, Anna, Student...", className: "border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200" })] })] })] })), showQuestionField && (_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-teal-500" }), "T\u00EAn / C\u00E2u h\u1ECFi ", _jsx("span", { className: "text-xs font-normal text-gray-500", children: "(t\u00F9y ch\u1ECDn)" })] }), _jsx(Input, { id: "question", value: question, onChange: (e) => {
339
- setQuestion(e.target.value);
340
- if (validationErrors.question) {
341
- setValidationErrors((prev) => ({ ...prev, question: undefined }));
342
- }
343
- }, placeholder: "Nh\u1EADp t\u00EAn ho\u1EB7c c\u00E2u h\u1ECFi... (vd: Mum, Dad, Julia)", className: `border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-200 ${validationErrors.question ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` }), validationErrors.question && (_jsx("p", { className: "text-sm text-red-600", children: validationErrors.question }))] })), showImageUrlField && (_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-teal-500" }), "H\u00ECnh \u1EA3nh c\u00E2u h\u1ECFi ", _jsx("span", { className: "text-xs font-normal text-gray-500", children: "(t\u00F9y ch\u1ECDn)" })] }), _jsx(FileUpload, { id: "question-image", label: "", accept: "image/*", value: imageUrl || '', onChange: (url) => {
344
- setImageUrl(url);
345
- if (validationErrors.imageUrl) {
346
- setValidationErrors((prev) => ({ ...prev, imageUrl: undefined }));
347
- }
348
- }, onPresignedUrlChange: setImagePreviewUrl, maxSize: 5, placeholder: "Upload \u1EA3nh ho\u1EB7c paste URL", autoUpload: true, prefix: "questions" }), displayPreviewUrl && (_jsx(ImagePreview, { src: displayPreviewUrl, alt: "Preview", className: "mt-2 h-48 w-full max-w-md rounded-lg border border-gray-200" }))] })), showAnswerField && (_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { htmlFor: "correctAnswer", className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(HelpCircle, { className: "h-4 w-4 text-green-500" }), "\u0110\u00E1p \u00E1n \u0111\u00FAng ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsxs("select", { id: "correctAnswer", value: correctAnswer, onChange: (e) => {
349
- setCorrectAnswer(e.target.value);
350
- if (validationErrors.correctAnswer) {
351
- setValidationErrors((prev) => ({ ...prev, correctAnswer: undefined }));
352
- }
353
- }, className: `flex h-10 w-full rounded-md border px-3 py-2 text-sm bg-white transition-all focus:outline-none focus:ring-2 focus:ring-offset-0 ${validationErrors.correctAnswer ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : 'border-gray-200 focus:border-green-300 focus:ring-green-200'}`, children: [_jsx("option", { value: "", children: "-- Ch\u1ECDn \u0111\u00E1p \u00E1n \u0111\u00FAng --" }), options
354
- .filter((opt) => opt.answer && opt.answer.trim() !== '')
355
- .map((opt, idx) => (_jsx("option", { value: opt.answer, children: opt.answer }, idx)))] }), validationErrors.correctAnswer && (_jsx("p", { className: "text-sm text-red-600", children: validationErrors.correctAnswer }))] })), 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))) })] })] }))] })] }), _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.5 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, { id: "explanation", value: explanation, onChange: (e) => setExplanation(e.target.value), 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" }) })] })] }));
356
- }
357
- export function MatchByWritingAnswerCreator(props) {
358
- return _jsx(MatchByWritingAnswerContent, { ...props });
359
- }
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 a,useEffect as i}from"react";import{Button as s}from"../../../../components/ui/button";import{Label as o}from"../../../../components/ui/label";import{Input as l}from"../../../../components/ui/input";import{Textarea as c}from"../../../../components/ui/textarea";import{PointsInput as m}from"../../../../components/ui/points-input";import{Card as d,CardContent as u,CardHeader as g,CardTitle as p}from"../../../../components/ui/card";import{Pencil as h,Eye as x,ImageIcon as f,MessageSquare as N,HelpCircle as b,BookOpen as w,Grid3X3 as v,Users as y}from"lucide-react";import{FileUpload as C}from"../../../../components/ui/file-upload";import{Checkbox as U}from"../../../../components/ui/checkbox";import{MatchByWritingAnswerClient as A}from"./MatchByWritingAnswerClient";import{MatchAnswerGroupCard as T}from"../../groups/MatchAnswerGroupCard";import{useDebouncedCallback as q,usePresignedFileUrl as I}from"../../../../shared/lib/hooks";import{useExamQuestionStore as k}from"../../../../shared/lib/stores/examQuestionStore";function E(e,r){if(!r||0===r.length)return 1;let t=0;for(const n of r){if(e<t+n.questionCount)return n.number;t+=n.questionCount}return r[r.length-1]?.number||1}function S({initialData:S,onSave:G,onSaveToQuestionBank:D,onCancel:M,onChange:j,onUnsavedChangesChange:F,externalErrors:P,groups:O,groupConfig:V,questionConfig:R,viewMode:z,questionIndexInPart:J=0,partId:B="",validationRef:H,headerExtra:Q}){const W=k(e=>e.setSharedPassageData),L=k(e=>e.getSharedPassageData),K=E(J,O),[X,Y]=n(S?.question||""),[Z,$]=n(S?.imageUrl||""),[_,ee]=n(S?.correctAnswer||""),[re,te]=n(S?.points||1),[ne,ae]=n(S?.isExample||!1),[ie,se]=n(S?.groupNumber||K),[oe,le]=n(S?.explanation||""),[ce,me]=n(S?.askerName||""),[de,ue]=n(S?.answererName||""),[ge,pe]=n(()=>{if(B){const e=L(B,K);if(e?.options&&Array.isArray(e.options))return e.options}return S?.options||[]}),[he,xe]=n(()=>{if(B){const e=L(B,K);if(e?.groupImageUrl)return e.groupImageUrl}return S?.groupImageUrl||""}),[fe,Ne]=n(""),[be,we]=n(()=>{if(B){const e=L(B,K);if(e?.groupTitle)return e.groupTitle}return S?.groupTitle||""}),ve=V?.includes("groupImageUrl")??!1,ye=V?.includes("groupTitle")??!1,[Ce,Ue]=n(!1),[Ae,Te]=n(!1),[qe,Ie]=n(""),[ke,Ee]=n({}),Se=a(""),Ge=a(S),De=a(J),Me=a(!1),je=a(!1),Fe=a(j),Pe=a(""),Oe=a(F),Ve=ie||1,Re=!R||R.includes("question"),ze=!R||R.includes("imageUrl"),Je=!R||R.includes("answer"),{previewUrl:Be}=I(Z),He=qe||Be||"";i(()=>{Oe.current=F},[F]),i(()=>{Fe.current=j},[j]);const Qe=q(e=>{Fe.current?.(e)},300),We=()=>JSON.stringify({question:X,imageUrl:Z,correctAnswer:_,points:re,isExample:ne,askerName:ce,answererName:de,options:ge,groupImageUrl:he,groupTitle:be});i(()=>{if(Me.current)return;const e=setTimeout(()=>{Se.current=We(),Te(!1)},150);return()=>clearTimeout(e)},[J]),i(()=>{if(Me.current)return;if(!Se.current)return;const e=We()!==Se.current;e!==Ae&&(Te(e),Oe.current?.(e))},[X,Z,_,re,ne,ce,de,ge,he,be,Ae]),i(()=>{H&&(H.current={triggerValidation:async()=>{const e={};let r=!0;return!Re||X&&""!==X.trim()||(e.question="Vui lòng nhập tên/câu hỏi",r=!1),!Je||_&&""!==_.trim()||(e.correctAnswer="Vui lòng nhập đáp án",r=!1),Ee(e),r},getFormData:()=>({question:X,imageUrl:Z,correctAnswer:_,points:re,groupNumber:Ve,isExample:ne,askerName:ce,answererName:de,options:ge,groupImageUrl:he,groupTitle:be,explanation:oe,groups:O})})},[H,X,Z,_,re,Ve,ne,ce,de,ge,he,be,oe,O]),i(()=>{const e=J!==De.current,r=!!S?.question;if(!(!je.current&&r)&&!e)return;Me.current=!0,Ge.current=S,De.current=J,je.current=!0;const t=E(J,O);Y(S?.question||""),$(S?.imageUrl||""),ee(S?.correctAnswer||""),te(S?.points||1),ae(S?.isExample||!1),se(t),le(S?.explanation||""),me(S?.askerName||""),ue(S?.answererName||"");let n=[],a="",i="";if(B){const e=L(B,t);e?.options&&Array.isArray(e.options)?(n=e.options,a=e?.groupImageUrl||"",i=e?.groupTitle||""):(n=S?.options||[],a=S?.groupImageUrl||"",i=S?.groupTitle||"",(n.length>0||a||i)&&W(B,t,{options:n,groupImageUrl:a,groupTitle:i}))}else n=S?.options||[],a=S?.groupImageUrl||"",i=S?.groupTitle||"";pe(n),xe(a),we(i),setTimeout(()=>{Me.current=!1},100)},[S,O,J,B,L,W]),i(()=>{if(Me.current)return;const e={question:X,imageUrl:Z,correctAnswer:_,points:re||1,groupNumber:Ve,isExample:ne,askerName:ce,answererName:de,options:ge,groupImageUrl:he,groupTitle:be,explanation:oe,groups:O},r=JSON.stringify(e);Pe.current!==r&&(Pe.current=r,B&&W(B,Ve,{options:ge,groupImageUrl:he,groupTitle:be}),Qe(e))},[X,Z,_,re,Ve,ne,ce,de,ge,he,be,oe,O,B,W,Qe]);if(Ce){const t={question:X,imageUrl:He||Z,correctAnswer:_,points:re,groupNumber:Ve,isExample:ne,options:ge};return r("div",{className:"space-y-4",children:[e(d,{children:e(g,{children:r("div",{className:"flex items-center justify-between",children:[r("div",{children:[e(p,{children:"Match by Writing Answer (Preview)"}),e("p",{className:"mt-1 text-sm text-gray-500",children:"Chế độ xem trước - Hiển thị đáp án đúng"})]}),r(s,{variant:"outline",size:"sm",onClick:()=>Ue(!1),children:[e(h,{className:"mr-2 h-4 w-4"}),"Quay lại Edit Mode"]})]})})}),e(A,{questionData:t,isReviewMode:!0,autoFillCorrectAnswers:!0,explanation:oe})]})}return r("div",{className:"space-y-4",children:[O&&O.length>0&&e(T,{currentGroupNumber:Ve,groupTitle:be,groupImageUrl:he,groupImagePreviewUrl:fe,options:ge,groupConfig:V,showGroupTitle:ye,showGroupImageUrl:ve,onGroupTitleChange:we,onGroupImageChange:xe,onGroupImagePreviewUrlChange:Ne,onUpdateOption:(e,r,t)=>{pe(n=>{const a=[...n];return a[e]={...a[e],[r]:t},a})},onRemoveOption:e=>{pe(r=>r.filter((r,t)=>t!==e))},onAddOption:()=>{String(ge.length+1);pe(e=>[...e,{answer:"",content:"",imageUrl:""}])}}),r(d,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-blue-100/50",children:[e(g,{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-blue-600 shadow-sm",children:e(v,{className:"h-4 w-4 text-white"})}),r("div",{children:[e(p,{className:"text-base font-bold text-gray-900",children:"Ghép đáp án bằng cách viết"}),e("p",{className:"text-xs text-gray-500",children:"Nhìn hình và viết đáp án tương ứng"})]})]}),r("div",{className:"flex items-center gap-2",children:[Q,r(s,{variant:"outline",size:"sm",onClick:()=>Ue(!0),disabled:!X,className:"gap-2 border-teal-200 text-teal-600 hover:bg-teal-50 hover:text-teal-700",children:[e(x,{className:"h-4 w-4"}),"Xem trước"]})]})]})}),r(u,{className:"space-y-4 px-4 pb-4",children:[r("div",{className:"flex items-center gap-6",children:[e(m,{value:re||1,onChange:e=>te(parseFloat(e.target.value)||1)}),r("div",{className:"flex items-center gap-2",children:[e(U,{id:"isExample",checked:ne||!1,onCheckedChange:e=>ae(!!e)}),e(o,{htmlFor:"isExample",className:"flex items-center gap-1.5 cursor-pointer text-sm font-medium text-gray-700",children:"Đánh dấu là câu hỏi Example"})]})]}),"CONVERSATION"===z&&r("div",{className:"space-y-3",children:[r(o,{className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(y,{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:[e(o,{htmlFor:"askerName",className:"text-sm font-medium text-gray-600",children:"Tên người hỏi"}),e(l,{id:"askerName",value:ce,onChange:e=>me(e.target.value),placeholder:"VD: John, Mary, Teacher...",className:"border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200"})]}),r("div",{className:"space-y-1.5",children:[e(o,{htmlFor:"answererName",className:"text-sm font-medium text-gray-600",children:"Tên người trả lời"}),e(l,{id:"answererName",value:de,onChange:e=>ue(e.target.value),placeholder:"VD: Tom, Anna, Student...",className:"border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200"})]})]})]}),Re&&r("div",{className:"space-y-2",children:[r(o,{htmlFor:"question",className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(N,{className:"h-4 w-4 text-teal-500"}),"Tên / Câu hỏi ",e("span",{className:"text-xs font-normal text-gray-500",children:"(tùy chọn)"})]}),e(l,{id:"question",value:X,onChange:e=>{Y(e.target.value),ke.question&&Ee(e=>({...e,question:void 0}))},placeholder:"Nhập tên hoặc câu hỏi... (vd: Mum, Dad, Julia)",className:"border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-200 "+(ke.question?"border-red-400 focus:border-red-500 focus:ring-red-200":"")}),ke.question&&e("p",{className:"text-sm text-red-600",children:ke.question})]}),ze&&r("div",{className:"space-y-2",children:[r(o,{className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(f,{className:"h-4 w-4 text-teal-500"}),"Hình ảnh câu hỏi ",e("span",{className:"text-xs font-normal text-gray-500",children:"(tùy chọn)"})]}),e(C,{id:"question-image",label:"",accept:"image/*",value:Z||"",onChange:e=>{$(e),ke.imageUrl&&Ee(e=>({...e,imageUrl:void 0}))},onPresignedUrlChange:Ie,maxSize:5,placeholder:"Upload ảnh hoặc paste URL",autoUpload:!0,prefix:"questions"}),He&&e(t,{src:He,alt:"Preview",className:"mt-2 h-48 w-full max-w-md rounded-lg border border-gray-200"})]}),Je&&r("div",{className:"space-y-2",children:[r(o,{htmlFor:"correctAnswer",className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(b,{className:"h-4 w-4 text-green-500"}),"Đáp án đúng ",e("span",{className:"text-red-500",children:"*"})]}),r("select",{id:"correctAnswer",value:_,onChange:e=>{ee(e.target.value),ke.correctAnswer&&Ee(e=>({...e,correctAnswer:void 0}))},className:"flex h-10 w-full rounded-md border px-3 py-2 text-sm bg-white transition-all focus:outline-none focus:ring-2 focus:ring-offset-0 "+(ke.correctAnswer?"border-red-400 focus:border-red-500 focus:ring-red-200":"border-gray-200 focus:border-green-300 focus:ring-green-200"),children:[e("option",{value:"",children:"-- Chọn đáp án đúng --"}),ge.filter(e=>e.answer&&""!==e.answer.trim()).map((r,t)=>e("option",{value:r.answer,children:r.answer},t))]}),ke.correctAnswer&&e("p",{className:"text-sm text-red-600",children:ke.correctAnswer})]}),P&&P.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:P.map((r,t)=>e("li",{children:r},t))})]})]})]})]}),r(d,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-amber-100/50",children:[e(g,{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(w,{className:"h-3.5 w-3.5 text-white"})}),r("div",{children:[r("div",{className:"flex items-center gap-2",children:[e(p,{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.5 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(u,{className:"px-4 pb-4",children:e(c,{id:"explanation",value:oe,onChange:e=>le(e.target.value),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 MatchByWritingAnswerCreator(r){return e(S,{...r})}
@@ -1,3 +1 @@
1
- export { MatchByWritingAnswerCreator } from './MatchByWritingAnswerCreator';
2
- export { MatchByWritingAnswerClient } from './MatchByWritingAnswerClient';
3
- export { matchByWritingAnswerRegistration } from './register';
1
+ export{MatchByWritingAnswerCreator}from"./MatchByWritingAnswerCreator";export{MatchByWritingAnswerClient}from"./MatchByWritingAnswerClient";export{matchByWritingAnswerRegistration}from"./register";