@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,233 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useState, useEffect, useCallback, useMemo } from 'react';
4
- import { Check, X, FileText, Star, Mail } from 'lucide-react';
5
- import { usePresignedFileUrl } from '../../../../shared/lib/hooks';
6
- import { cn } from '../../../../shared/lib/utils';
7
- function parseParagraph(paragraph) {
8
- const segments = [];
9
- const regex = /\{(\d+)\}/g;
10
- let lastIndex = 0;
11
- let match;
12
- while ((match = regex.exec(paragraph)) !== null) {
13
- if (match.index > lastIndex) {
14
- segments.push({ type: 'text', value: paragraph.slice(lastIndex, match.index) });
15
- }
16
- segments.push({ type: 'blank', index: parseInt(match[1], 10) });
17
- lastIndex = regex.lastIndex;
18
- }
19
- if (lastIndex < paragraph.length) {
20
- segments.push({ type: 'text', value: paragraph.slice(lastIndex) });
21
- }
22
- return segments;
23
- }
24
- function isWithOptionsMode(wordBank) {
25
- return wordBank.length > 0 && Array.isArray(wordBank[0]?.options);
26
- }
27
- // ---------------------------------------------------------------------------
28
- // Sub-component: presigned image for word-bank card
29
- // ---------------------------------------------------------------------------
30
- function WordBankImage({ imageUrl }) {
31
- const { previewUrl, isLoading } = usePresignedFileUrl(imageUrl);
32
- if (isLoading) {
33
- return (_jsx("div", { className: "flex h-16 w-16 items-center justify-center rounded-lg bg-gray-100", children: _jsx("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-gray-300 border-t-teal-500" }) }));
34
- }
35
- if (!previewUrl)
36
- return null;
37
- return (_jsx("img", { src: previewUrl, alt: "", className: "h-16 w-16 rounded-lg object-cover border border-gray-200" }));
38
- }
39
- // ---------------------------------------------------------------------------
40
- // Example blank badge — shown pre-filled in the paragraph
41
- // ---------------------------------------------------------------------------
42
- function ExampleBadge({ text }) {
43
- return (_jsxs("span", { className: "mx-1 inline-flex items-center gap-1 rounded-sm border border-amber-300 bg-amber-100 px-2.5 py-0.5 text-sm font-semibold text-amber-800 align-middle", children: [_jsx(Star, { className: "h-3 w-3 fill-amber-400 text-amber-400 shrink-0" }), text] }));
44
- }
45
- // ---------------------------------------------------------------------------
46
- // Unified WordFillParagraphClient
47
- // ---------------------------------------------------------------------------
48
- export function WordFillParagraphClient({ questionData, onSubmit, isReviewMode = false, userAnswer, autoFillCorrectAnswers = false, explanation, }) {
49
- const { title = '', paragraph = '', wordBank = [], answers = [], exampleAnswer = [], imageUrl, emailFrom, emailTo, } = questionData;
50
- const withOptions = isWithOptionsMode(wordBank);
51
- const isDefaultMode = !withOptions && wordBank.length === 0;
52
- // ── Example sets ──────────────────────────────────────────────────────────
53
- // WITH_WORD_BANK: example blank indices derived from wordBank[i].isExample
54
- const exampleBlankIndices = useMemo(() => {
55
- if (withOptions || isDefaultMode)
56
- return new Set();
57
- const indices = new Set();
58
- wordBank.forEach((item) => {
59
- if (item.isExample) {
60
- const answerIdx = answers.indexOf(item.word);
61
- if (answerIdx >= 0)
62
- indices.add(answerIdx);
63
- }
64
- });
65
- return indices;
66
- }, [withOptions, isDefaultMode, wordBank, answers]);
67
- // DEFAULT / EMAIL: example blank indices derived from exampleAnswer string list
68
- const defaultExampleBlankIndices = useMemo(() => {
69
- if (!isDefaultMode || !exampleAnswer?.length)
70
- return new Set();
71
- const exSet = new Set(exampleAnswer);
72
- const indices = new Set();
73
- answers.forEach((ans, idx) => {
74
- if (exSet.has(ans))
75
- indices.add(idx);
76
- });
77
- return indices;
78
- }, [isDefaultMode, exampleAnswer, answers]);
79
- // Unified helper: is a given blank index an example?
80
- const isExampleBlank = useCallback((blankIdx) => {
81
- if (withOptions)
82
- return !!(wordBank[blankIdx]?.isExample);
83
- if (isDefaultMode)
84
- return defaultExampleBlankIndices.has(blankIdx);
85
- return exampleBlankIndices.has(blankIdx);
86
- }, [withOptions, isDefaultMode, wordBank, exampleBlankIndices, defaultExampleBlankIndices]);
87
- // ── Filled answers state ──────────────────────────────────────────────────
88
- const [filledAnswers, setFilledAnswers] = useState(() => {
89
- const initial = {};
90
- if (userAnswer) {
91
- userAnswer.forEach((ans, idx) => { initial[idx] = ans; });
92
- }
93
- else if (autoFillCorrectAnswers) {
94
- answers.forEach((ans, idx) => { initial[idx] = ans; });
95
- }
96
- return initial;
97
- });
98
- useEffect(() => {
99
- if (userAnswer) {
100
- const updated = {};
101
- userAnswer.forEach((ans, idx) => { updated[idx] = ans; });
102
- setFilledAnswers(updated);
103
- }
104
- }, [userAnswer]);
105
- // ── Image ─────────────────────────────────────────────────────────────────
106
- const { previewUrl: imagePreviewUrl, isLoading: imageLoading } = usePresignedFileUrl(imageUrl || '');
107
- // ── Paragraph parsing ─────────────────────────────────────────────────────
108
- const segments = useMemo(() => parseParagraph(paragraph), [paragraph]);
109
- const allBlanks = useMemo(() => segments.filter(s => s.type === 'blank').map(s => s.index), [segments]);
110
- // ── Correctness (skip example blanks) ────────────────────────────────────
111
- const nonExampleBlanks = useMemo(() => allBlanks.filter(idx => !isExampleBlank(idx)), [allBlanks, isExampleBlank]);
112
- const allFilled = nonExampleBlanks.every(idx => filledAnswers[idx]);
113
- const isAllCorrect = isReviewMode && nonExampleBlanks.every(idx => filledAnswers[idx] === answers[idx]);
114
- const displayExplanation = explanation || questionData.explanation;
115
- // ── WITH_OPTIONS: expanded blank ──────────────────────────────────────────
116
- const [expandedBlank, setExpandedBlank] = useState(null);
117
- const handleSelectOption = useCallback((blankIndex, option) => {
118
- if (isReviewMode)
119
- return;
120
- const updated = { ...filledAnswers, [blankIndex]: option };
121
- setFilledAnswers(updated);
122
- const answerArray = allBlanks.map(idx => updated[idx] || '');
123
- onSubmit?.(answerArray);
124
- }, [isReviewMode, filledAnswers, allBlanks, onSubmit]);
125
- // ── WITH_WORD_BANK: direct input handling ─────────────────────────────────
126
- const handleInputChange = useCallback((blankIndex, value) => {
127
- if (isReviewMode)
128
- return;
129
- const updated = { ...filledAnswers, [blankIndex]: value };
130
- setFilledAnswers(updated);
131
- const answerArray = allBlanks.map(idx => updated[idx] || '');
132
- onSubmit?.(answerArray);
133
- }, [isReviewMode, filledAnswers, allBlanks, onSubmit]);
134
- const usedWords = useMemo(() => {
135
- const used = new Set();
136
- Object.values(filledAnswers).forEach(w => { if (w)
137
- used.add(w); });
138
- return used;
139
- }, [filledAnswers]);
140
- // ── Example summary (blanks pre-filled) ───────────────────────────────────
141
- const exampleEntries = useMemo(() => {
142
- return allBlanks
143
- .filter(idx => isExampleBlank(idx))
144
- .map(idx => ({ blankIdx: idx, answer: answers[idx] || '' }))
145
- .filter(e => e.answer);
146
- }, [allBlanks, isExampleBlank, answers]);
147
- // ── Render ────────────────────────────────────────────────────────────────
148
- const headerGradient = withOptions
149
- ? 'bg-gradient-to-br from-emerald-500 to-teal-600'
150
- : isDefaultMode
151
- ? 'bg-gradient-to-br from-indigo-500 to-blue-600'
152
- : 'bg-gradient-to-br from-teal-500 to-cyan-600';
153
- return (_jsx("div", { className: "space-y-4", children: _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-5 py-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: `flex h-8 w-8 items-center justify-center rounded-lg ${headerGradient} text-white shadow-sm`, children: _jsx(FileText, { className: "h-4 w-4" }) }), _jsx("span", { className: "text-sm font-medium text-gray-700", children: "\u0110i\u1EC1n t\u1EEB v\u00E0o \u0111o\u1EA1n v\u0103n" })] }), isReviewMode && allFilled && (_jsxs("div", { className: cn('flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold', isAllCorrect ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'), children: [isAllCorrect ? _jsx(Check, { className: "h-3.5 w-3.5" }) : _jsx(X, { className: "h-3.5 w-3.5" }), isAllCorrect ? 'Đúng' : 'Sai'] }))] }), _jsxs("div", { className: "space-y-5 p-5", children: [title && (_jsx("h2", { className: "text-center text-xl font-bold text-gray-900", children: title })), exampleEntries.length > 0 && (_jsxs("div", { className: "flex flex-wrap items-center gap-2 rounded-lg border border-amber-200 bg-amber-50 px-4 py-2.5", children: [_jsxs("div", { className: "flex items-center gap-1.5 text-xs font-semibold text-amber-700 shrink-0", children: [_jsx(Star, { className: "h-3.5 w-3.5 fill-amber-400 text-amber-400" }), "\u0110\u00E3 \u0111i\u1EC1n s\u1EB5n (Example):"] }), exampleEntries.map(({ blankIdx, answer }) => (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-md border border-amber-300 bg-white px-2 py-0.5 text-xs font-semibold text-amber-800", children: [_jsx("span", { className: "text-amber-500", children: '{' + blankIdx + '}' }), answer] }, blankIdx)))] })), (imagePreviewUrl || imageUrl) && (_jsx("div", { className: "flex justify-center", children: _jsx("div", { className: "overflow-hidden rounded-lg border border-gray-200 bg-gray-50", children: imageLoading ? (_jsx("div", { className: "flex h-48 w-48 items-center justify-center", children: _jsx("div", { className: "h-8 w-8 animate-spin rounded-full border-4 border-gray-200 border-t-teal-500" }) })) : (_jsx("img", { src: imagePreviewUrl || imageUrl, alt: title, className: "max-h-56 w-auto object-contain p-2" })) }) })), _jsxs("div", { className: (emailFrom || emailTo)
154
- ? 'overflow-hidden rounded-xl border border-gray-300 bg-white shadow-sm'
155
- : 'rounded-lg border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50', children: [(emailFrom || emailTo) && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-1.5 border-b border-gray-200 bg-gray-100 px-4 py-2.5", children: [_jsx("span", { className: "h-3 w-3 rounded-full bg-red-400" }), _jsx("span", { className: "h-3 w-3 rounded-full bg-yellow-400" }), _jsx("span", { className: "h-3 w-3 rounded-full bg-green-400" }), _jsxs("div", { className: "ml-3 flex items-center gap-1.5 text-xs text-gray-400", children: [_jsx(Mail, { className: "h-3.5 w-3.5" }), _jsx("span", { children: "Email" })] })] }), _jsxs("div", { className: "border-b border-gray-200 bg-gray-50 px-5 py-3 space-y-1.5 text-sm", children: [emailFrom && (_jsxs("div", { className: "flex items-baseline gap-2", children: [_jsx("span", { className: "w-10 shrink-0 text-xs font-semibold uppercase tracking-wide text-gray-400", children: "From" }), _jsx("span", { className: "font-medium text-gray-800", children: emailFrom })] })), emailTo && (_jsxs("div", { className: "flex items-baseline gap-2", children: [_jsx("span", { className: "w-10 shrink-0 text-xs font-semibold uppercase tracking-wide text-gray-400", children: "To" }), _jsx("span", { className: "font-medium text-gray-800", children: emailTo })] }))] })] })), _jsx("div", { className: `text-base leading-loose text-gray-800 whitespace-pre-wrap ${(emailFrom || emailTo) ? 'p-5 bg-white' : 'p-5 bg-gradient-to-r from-gray-50 to-slate-50'}`, children: segments.map((segment, idx) => {
156
- if (segment.type === 'text') {
157
- return _jsx("span", { children: segment.value }, idx);
158
- }
159
- const blankIdx = segment.index;
160
- const filled = filledAnswers[blankIdx];
161
- const isCorrectFill = isReviewMode && filled === answers[blankIdx];
162
- const isWrongFill = isReviewMode && !!filled && filled !== answers[blankIdx];
163
- const example = isExampleBlank(blankIdx);
164
- // ── Example blank: always shown pre-filled ──────────────────
165
- if (example) {
166
- return _jsx(ExampleBadge, { text: answers[blankIdx] || '___' }, idx);
167
- }
168
- // ── WITH_OPTIONS blank ──────────────────────────────────────
169
- if (withOptions) {
170
- const isExpanded = expandedBlank === blankIdx;
171
- const blankOptions = wordBank[blankIdx]?.options || [];
172
- return (_jsxs("span", { className: "relative mx-1 inline-flex flex-col items-center align-middle", children: [_jsxs("button", { type: "button", onClick: () => !isReviewMode && setExpandedBlank(isExpanded ? null : blankIdx), disabled: isReviewMode, className: cn('inline-flex min-w-[80px] items-center rounded border-2 border-dashed px-3 py-0.5 text-center text-sm font-semibold transition-all', isReviewMode
173
- ? isCorrectFill
174
- ? 'border-green-400 bg-green-50 text-green-800'
175
- : isWrongFill
176
- ? 'border-red-400 bg-red-50 text-red-800'
177
- : 'border-gray-300 bg-gray-50 text-gray-400'
178
- : isExpanded
179
- ? 'border-teal-500 bg-teal-50 text-teal-700 ring-2 ring-teal-200'
180
- : filled
181
- ? 'cursor-pointer border-teal-300 bg-teal-50 text-teal-700 hover:bg-teal-100'
182
- : 'cursor-pointer border-gray-300 bg-white text-gray-400 hover:border-teal-300 hover:bg-teal-50'), children: [filled || `(${blankIdx + 1})`, isReviewMode && filled && (isCorrectFill
183
- ? _jsx(Check, { className: "ml-1 h-3.5 w-3.5 text-green-600" })
184
- : _jsx(X, { className: "ml-1 h-3.5 w-3.5 text-red-600" }))] }), isExpanded && !isReviewMode && blankOptions.length > 0 && (_jsx("div", { className: "absolute left-1/2 top-full z-10 mt-1 flex -translate-x-1/2 gap-1 rounded-lg border border-teal-200 bg-white p-1.5 shadow-lg", children: blankOptions.map((opt, optIdx) => (_jsx("button", { type: "button", onClick: (e) => {
185
- e.stopPropagation();
186
- handleSelectOption(blankIdx, opt);
187
- setExpandedBlank(null);
188
- }, className: cn('whitespace-nowrap rounded-md px-2.5 py-1 text-sm font-medium transition-all', filled === opt
189
- ? 'bg-teal-500 text-white'
190
- : 'bg-gray-50 text-gray-700 hover:bg-teal-100 hover:text-teal-700'), children: opt }, optIdx))) }))] }, idx));
191
- }
192
- // ── WITH_WORD_BANK or DEFAULT blank ─────────────────────────
193
- if (isDefaultMode) {
194
- // DEFAULT: read-only inputs in review, otherwise show filled/empty state
195
- return (_jsxs("span", { className: cn('mx-1 inline-flex min-w-[80px] items-center justify-center rounded border-2 px-3 py-0.5 text-sm font-semibold align-middle', isReviewMode
196
- ? isCorrectFill
197
- ? 'border-green-400 bg-green-50 text-green-800'
198
- : isWrongFill
199
- ? 'border-red-400 bg-red-50 text-red-800'
200
- : 'border-dashed border-gray-300 bg-gray-50 text-gray-400'
201
- : filled
202
- ? 'border-indigo-300 bg-indigo-50 text-indigo-800'
203
- : 'border-dashed border-gray-300 bg-white text-gray-400'), children: [filled || `(${blankIdx + 1})`, isReviewMode && filled && (isCorrectFill
204
- ? _jsx(Check, { className: "ml-1 h-3.5 w-3.5 text-green-600" })
205
- : _jsx(X, { className: "ml-1 h-3.5 w-3.5 text-red-600" }))] }, idx));
206
- }
207
- // WITH_WORD_BANK input field
208
- return (_jsxs("span", { className: "mx-1 inline-flex items-center align-middle", children: [_jsx("input", { type: "text", value: filled || '', onChange: (e) => handleInputChange(blankIdx, e.target.value), disabled: isReviewMode, placeholder: `(${blankIdx + 1})`, className: cn('inline-flex min-w-[80px] max-w-[120px] rounded border-2 border-dashed px-3 py-0.5 text-center text-sm font-semibold transition-all outline-none', isReviewMode
209
- ? isCorrectFill
210
- ? 'border-green-400 bg-green-50 text-green-800'
211
- : isWrongFill
212
- ? 'border-red-400 bg-red-50 text-red-800'
213
- : 'border-gray-300 bg-gray-50 text-gray-400'
214
- : filled
215
- ? 'border-teal-300 bg-teal-50 text-teal-700'
216
- : 'border-gray-300 bg-white text-gray-400 placeholder:text-gray-300', 'focus:border-teal-500 focus:bg-teal-50 focus:text-teal-700 focus:ring-2 focus:ring-teal-200', isReviewMode ? 'cursor-default' : 'cursor-text') }), isReviewMode && filled && (_jsx("span", { className: "ml-1", children: isCorrectFill
217
- ? _jsx(Check, { className: "h-3.5 w-3.5 text-green-600" })
218
- : _jsx(X, { className: "h-3.5 w-3.5 text-red-600" }) }))] }, idx));
219
- }) })] }), !withOptions && !isDefaultMode && (_jsxs("div", { className: "space-y-2", children: [_jsx("span", { className: "text-xs font-medium uppercase tracking-wider text-gray-500", children: "Word Bank (Reference)" }), _jsx("div", { className: "grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4", children: wordBank.map((item, index) => {
220
- const isUsed = usedWords.has(item.word);
221
- const isExampleWord = item.isExample;
222
- const hasImage = item.imageUrl && item.imageUrl.trim() !== '';
223
- return (_jsxs("div", { className: cn('flex flex-col items-center gap-2 rounded-xl border-2 p-3', isExampleWord
224
- ? 'border-amber-300 bg-amber-50'
225
- : isUsed
226
- ? 'border-emerald-200 bg-emerald-50 opacity-60'
227
- : 'border-gray-200 bg-gray-50'), children: [hasImage && _jsx(WordBankImage, { imageUrl: item.imageUrl }), _jsxs("div", { className: "flex flex-col items-center gap-1", children: [_jsx("span", { className: cn('text-sm font-semibold', isExampleWord ? 'text-amber-700' : isUsed ? 'text-emerald-700' : 'text-gray-700'), children: item.word }), isExampleWord && (_jsxs("span", { className: "flex items-center gap-0.5 rounded-full bg-amber-100 px-1.5 py-0.5 text-[10px] font-semibold text-amber-600", children: [_jsx(Star, { className: "h-2.5 w-2.5 fill-amber-400 text-amber-400" }), "example"] })), isUsed && !isExampleWord && (_jsx("span", { className: "flex items-center gap-0.5 rounded-full bg-emerald-100 px-1.5 py-0.5 text-[10px] font-semibold text-emerald-600", children: "used" }))] })] }, index));
228
- }) })] })), isReviewMode && !isAllCorrect && (_jsxs("div", { className: "rounded-lg border border-green-200 bg-green-50 p-3", children: [_jsx("span", { className: "text-xs font-medium uppercase tracking-wider text-green-600", children: "\u0110\u00E1p \u00E1n \u0111\u00FAng" }), _jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: answers.map((answer, index) => {
229
- if (isExampleBlank(index))
230
- return null;
231
- return (_jsxs("span", { className: "rounded-lg border border-green-300 bg-green-100 px-3 py-1.5 text-sm font-semibold text-green-800", children: ['{' + index + '}', ": ", answer] }, index));
232
- }) })] })), isReviewMode && displayExplanation && (_jsxs("div", { className: "rounded-lg border border-blue-200 bg-gradient-to-r from-blue-50 to-indigo-50 p-3", children: [_jsx("span", { className: "text-xs font-medium uppercase tracking-wider text-blue-600", children: "Gi\u1EA3i th\u00EDch" }), _jsx("p", { className: "mt-1 text-sm text-blue-800", children: displayExplanation })] }))] })] }) }));
233
- }
1
+ "use client";import{jsx as e,jsxs as r,Fragment as t}from"react/jsx-runtime";import{useState as a,useEffect as l,useCallback as n,useMemo as s}from"react";import{Check as d,X as i,FileText as o,Star as m,Mail as c}from"lucide-react";import{usePresignedFileUrl as g}from"../../../../shared/lib/hooks";import{cn as b}from"../../../../shared/lib/utils";function x({imageUrl:r}){const{previewUrl:t,isLoading:a}=g(r);return a?e("div",{className:"flex h-16 w-16 items-center justify-center rounded-lg bg-gray-100",children:e("div",{className:"h-4 w-4 animate-spin rounded-full border-2 border-gray-300 border-t-teal-500"})}):t?e("img",{src:t,alt:"",className:"h-16 w-16 rounded-lg object-cover border border-gray-200"}):null}function p({text:t}){return r("span",{className:"mx-1 inline-flex items-center gap-1 rounded-sm border border-amber-300 bg-amber-100 px-2.5 py-0.5 text-sm font-semibold text-amber-800 align-middle",children:[e(m,{className:"h-3 w-3 fill-amber-400 text-amber-400 shrink-0"}),t]})}export function WordFillParagraphClient({questionData:h,onSubmit:u,isReviewMode:f=!1,userAnswer:y,autoFillCorrectAnswers:w=!1,explanation:N}){const{title:v="",paragraph:k="",wordBank:j=[],answers:E=[],exampleAnswer:S=[],imageUrl:U,emailFrom:A,emailTo:C}=h,F=function(e){return e.length>0&&Array.isArray(e[0]?.options)}(j),I=!F&&0===j.length,$=s(()=>{if(F||I)return new Set;const e=new Set;return j.forEach(r=>{if(r.isExample){const t=E.indexOf(r.word);t>=0&&e.add(t)}}),e},[F,I,j,E]),_=s(()=>{if(!I||!S?.length)return new Set;const e=new Set(S),r=new Set;return E.forEach((t,a)=>{e.has(t)&&r.add(a)}),r},[I,S,E]),B=n(e=>F?!!j[e]?.isExample:I?_.has(e):$.has(e),[F,I,j,$,_]),[L,O]=a(()=>{const e={};return y?y.forEach((r,t)=>{e[t]=r}):w&&E.forEach((r,t)=>{e[t]=r}),e});l(()=>{if(y){const e={};y.forEach((r,t)=>{e[t]=r}),O(e)}},[y]);const{previewUrl:P,isLoading:R}=g(U||""),T=s(()=>function(e){const r=[],t=/\{(\d+)\}/g;let a,l=0;for(;null!==(a=t.exec(e));)a.index>l&&r.push({type:"text",value:e.slice(l,a.index)}),r.push({type:"blank",index:parseInt(a[1],10)}),l=t.lastIndex;return l<e.length&&r.push({type:"text",value:e.slice(l)}),r}(k),[k]),W=s(()=>T.filter(e=>"blank"===e.type).map(e=>e.index),[T]),q=s(()=>W.filter(e=>!B(e)),[W,B]),z=q.every(e=>L[e]),D=f&&q.every(e=>L[e]===E[e]),G=N||h.explanation,[M,H]=a(null),J=n((e,r)=>{if(f)return;const t={...L,[e]:r};O(t);const a=W.map(e=>t[e]||"");u?.(a)},[f,L,W,u]),K=n((e,r)=>{if(f)return;const t={...L,[e]:r};O(t);const a=W.map(e=>t[e]||"");u?.(a)},[f,L,W,u]),Q=s(()=>{const e=new Set;return Object.values(L).forEach(r=>{r&&e.add(r)}),e},[L]),V=s(()=>W.filter(e=>B(e)).map(e=>({blankIdx:e,answer:E[e]||""})).filter(e=>e.answer),[W,B,E]);return e("div",{className:"space-y-4",children:r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center justify-between border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-5 py-3",children:[r("div",{className:"flex items-center gap-3",children:[e("div",{className:`flex h-8 w-8 items-center justify-center rounded-lg ${F?"bg-gradient-to-br from-emerald-500 to-teal-600":I?"bg-gradient-to-br from-indigo-500 to-blue-600":"bg-gradient-to-br from-teal-500 to-cyan-600"} text-white shadow-sm`,children:e(o,{className:"h-4 w-4"})}),e("span",{className:"text-sm font-medium text-gray-700",children:"Điền từ vào đoạn văn"})]}),f&&z&&r("div",{className:b("flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold",D?"bg-green-100 text-green-700":"bg-red-100 text-red-700"),children:[e(D?d:i,{className:"h-3.5 w-3.5"}),D?"Đúng":"Sai"]})]}),r("div",{className:"space-y-5 p-5",children:[v&&e("h2",{className:"text-center text-xl font-bold text-gray-900",children:v}),V.length>0&&r("div",{className:"flex flex-wrap items-center gap-2 rounded-lg border border-amber-200 bg-amber-50 px-4 py-2.5",children:[r("div",{className:"flex items-center gap-1.5 text-xs font-semibold text-amber-700 shrink-0",children:[e(m,{className:"h-3.5 w-3.5 fill-amber-400 text-amber-400"}),"Đã điền sẵn (Example):"]}),V.map(({blankIdx:t,answer:a})=>r("span",{className:"inline-flex items-center gap-1 rounded-md border border-amber-300 bg-white px-2 py-0.5 text-xs font-semibold text-amber-800",children:[e("span",{className:"text-amber-500",children:"{"+t+"}"}),a]},t))]}),(P||U)&&e("div",{className:"flex justify-center",children:e("div",{className:"overflow-hidden rounded-lg border border-gray-200 bg-gray-50",children:R?e("div",{className:"flex h-48 w-48 items-center justify-center",children:e("div",{className:"h-8 w-8 animate-spin rounded-full border-4 border-gray-200 border-t-teal-500"})}):e("img",{src:P||U,alt:v,className:"max-h-56 w-auto object-contain p-2"})})}),r("div",{className:A||C?"overflow-hidden rounded-xl border border-gray-300 bg-white shadow-sm":"rounded-lg border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50",children:[(A||C)&&r(t,{children:[r("div",{className:"flex items-center gap-1.5 border-b border-gray-200 bg-gray-100 px-4 py-2.5",children:[e("span",{className:"h-3 w-3 rounded-full bg-red-400"}),e("span",{className:"h-3 w-3 rounded-full bg-yellow-400"}),e("span",{className:"h-3 w-3 rounded-full bg-green-400"}),r("div",{className:"ml-3 flex items-center gap-1.5 text-xs text-gray-400",children:[e(c,{className:"h-3.5 w-3.5"}),e("span",{children:"Email"})]})]}),r("div",{className:"border-b border-gray-200 bg-gray-50 px-5 py-3 space-y-1.5 text-sm",children:[A&&r("div",{className:"flex items-baseline gap-2",children:[e("span",{className:"w-10 shrink-0 text-xs font-semibold uppercase tracking-wide text-gray-400",children:"From"}),e("span",{className:"font-medium text-gray-800",children:A})]}),C&&r("div",{className:"flex items-baseline gap-2",children:[e("span",{className:"w-10 shrink-0 text-xs font-semibold uppercase tracking-wide text-gray-400",children:"To"}),e("span",{className:"font-medium text-gray-800",children:C})]})]})]}),e("div",{className:"text-base leading-loose text-gray-800 whitespace-pre-wrap "+(A||C?"p-5 bg-white":"p-5 bg-gradient-to-r from-gray-50 to-slate-50"),children:T.map((t,a)=>{if("text"===t.type)return e("span",{children:t.value},a);const l=t.index,n=L[l],s=f&&n===E[l],o=f&&!!n&&n!==E[l];if(B(l))return e(p,{text:E[l]||"___"},a);if(F){const t=M===l,m=j[l]?.options||[];return r("span",{className:"relative mx-1 inline-flex flex-col items-center align-middle",children:[r("button",{type:"button",onClick:()=>!f&&H(t?null:l),disabled:f,className:b("inline-flex min-w-[80px] items-center rounded border-2 border-dashed px-3 py-0.5 text-center text-sm font-semibold transition-all",f?s?"border-green-400 bg-green-50 text-green-800":o?"border-red-400 bg-red-50 text-red-800":"border-gray-300 bg-gray-50 text-gray-400":t?"border-teal-500 bg-teal-50 text-teal-700 ring-2 ring-teal-200":n?"cursor-pointer border-teal-300 bg-teal-50 text-teal-700 hover:bg-teal-100":"cursor-pointer border-gray-300 bg-white text-gray-400 hover:border-teal-300 hover:bg-teal-50"),children:[n||`(${l+1})`,f&&n&&(s?e(d,{className:"ml-1 h-3.5 w-3.5 text-green-600"}):e(i,{className:"ml-1 h-3.5 w-3.5 text-red-600"}))]}),t&&!f&&m.length>0&&e("div",{className:"absolute left-1/2 top-full z-10 mt-1 flex -translate-x-1/2 gap-1 rounded-lg border border-teal-200 bg-white p-1.5 shadow-lg",children:m.map((r,t)=>e("button",{type:"button",onClick:e=>{e.stopPropagation(),J(l,r),H(null)},className:b("whitespace-nowrap rounded-md px-2.5 py-1 text-sm font-medium transition-all",n===r?"bg-teal-500 text-white":"bg-gray-50 text-gray-700 hover:bg-teal-100 hover:text-teal-700"),children:r},t))})]},a)}return r("span",I?{className:b("mx-1 inline-flex min-w-[80px] items-center justify-center rounded border-2 px-3 py-0.5 text-sm font-semibold align-middle",f?s?"border-green-400 bg-green-50 text-green-800":o?"border-red-400 bg-red-50 text-red-800":"border-dashed border-gray-300 bg-gray-50 text-gray-400":n?"border-indigo-300 bg-indigo-50 text-indigo-800":"border-dashed border-gray-300 bg-white text-gray-400"),children:[n||`(${l+1})`,f&&n&&(s?e(d,{className:"ml-1 h-3.5 w-3.5 text-green-600"}):e(i,{className:"ml-1 h-3.5 w-3.5 text-red-600"}))]}:{className:"mx-1 inline-flex items-center align-middle",children:[e("input",{type:"text",value:n||"",onChange:e=>K(l,e.target.value),disabled:f,placeholder:`(${l+1})`,className:b("inline-flex min-w-[80px] max-w-[120px] rounded border-2 border-dashed px-3 py-0.5 text-center text-sm font-semibold transition-all outline-none",f?s?"border-green-400 bg-green-50 text-green-800":o?"border-red-400 bg-red-50 text-red-800":"border-gray-300 bg-gray-50 text-gray-400":n?"border-teal-300 bg-teal-50 text-teal-700":"border-gray-300 bg-white text-gray-400 placeholder:text-gray-300","focus:border-teal-500 focus:bg-teal-50 focus:text-teal-700 focus:ring-2 focus:ring-teal-200",f?"cursor-default":"cursor-text")}),f&&n&&e("span",{className:"ml-1",children:s?e(d,{className:"h-3.5 w-3.5 text-green-600"}):e(i,{className:"h-3.5 w-3.5 text-red-600"})})]},a)})})]}),!F&&!I&&r("div",{className:"space-y-2",children:[e("span",{className:"text-xs font-medium uppercase tracking-wider text-gray-500",children:"Word Bank (Reference)"}),e("div",{className:"grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4",children:j.map((t,a)=>{const l=Q.has(t.word),n=t.isExample,s=t.imageUrl&&""!==t.imageUrl.trim();return r("div",{className:b("flex flex-col items-center gap-2 rounded-xl border-2 p-3",n?"border-amber-300 bg-amber-50":l?"border-emerald-200 bg-emerald-50 opacity-60":"border-gray-200 bg-gray-50"),children:[s&&e(x,{imageUrl:t.imageUrl}),r("div",{className:"flex flex-col items-center gap-1",children:[e("span",{className:b("text-sm font-semibold",n?"text-amber-700":l?"text-emerald-700":"text-gray-700"),children:t.word}),n&&r("span",{className:"flex items-center gap-0.5 rounded-full bg-amber-100 px-1.5 py-0.5 text-[10px] font-semibold text-amber-600",children:[e(m,{className:"h-2.5 w-2.5 fill-amber-400 text-amber-400"}),"example"]}),l&&!n&&e("span",{className:"flex items-center gap-0.5 rounded-full bg-emerald-100 px-1.5 py-0.5 text-[10px] font-semibold text-emerald-600",children:"used"})]})]},a)})})]}),f&&!D&&r("div",{className:"rounded-lg border border-green-200 bg-green-50 p-3",children:[e("span",{className:"text-xs font-medium uppercase tracking-wider text-green-600",children:"Đáp án đúng"}),e("div",{className:"mt-2 flex flex-wrap gap-2",children:E.map((e,t)=>B(t)?null:r("span",{className:"rounded-lg border border-green-300 bg-green-100 px-3 py-1.5 text-sm font-semibold text-green-800",children:["{"+t+"}",": ",e]},t))})]}),f&&G&&r("div",{className:"rounded-lg border border-blue-200 bg-gradient-to-r from-blue-50 to-indigo-50 p-3",children:[e("span",{className:"text-xs font-medium uppercase tracking-wider text-blue-600",children:"Giải thích"}),e("p",{className:"mt-1 text-sm text-blue-800",children:G})]})]})]})})}