@tinyweb_dev/oe-exam-sdk 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (485) hide show
  1. package/dist/api/exam-create.js +1 -179
  2. package/dist/api/exam-create.types.js +1 -1
  3. package/dist/api/exam-questions.js +1 -98
  4. package/dist/api/exam-questions.types.js +1 -1
  5. package/dist/api/exam-taking.js +1 -73
  6. package/dist/api/exam-taking.types.js +1 -1
  7. package/dist/api/index.js +1 -6
  8. package/dist/api/result-review.js +1 -50
  9. package/dist/api/result-review.types.js +1 -1
  10. package/dist/components/CueCardEditor.js +1 -58
  11. package/dist/components/common/ResolvedImage.js +1 -15
  12. package/dist/components/exams/CreateExamInfoForm.js +1 -35
  13. package/dist/components/exams/CreateExamPageContainer.js +1 -103
  14. package/dist/components/exams/ExamCreator.js +1 -89
  15. package/dist/components/exams/ExamPartTabs.js +1 -40
  16. package/dist/components/exams/ExamQuestionGrid.js +1 -18
  17. package/dist/components/exams/ExamQuestionsPageContainer.js +1 -90
  18. package/dist/components/exams/PartAudioUploader.js +1 -9
  19. package/dist/components/exams/TemplateSelector.js +1 -66
  20. package/dist/components/exams/api.js +1 -3
  21. package/dist/components/exams/create-exam.validation.js +1 -18
  22. package/dist/components/exams/exam-template.utils.js +1 -18
  23. package/dist/components/exams/index.js +1 -10
  24. package/dist/components/exams/take/ExamTakingPageContainer.js +1 -153
  25. package/dist/components/exams/take/GenericQuestionRenderer.js +1 -14
  26. package/dist/components/exams/take/exam-taking.utils.js +1 -88
  27. package/dist/components/exams/take/hooks/useSpeakingRecorder.js +1 -24
  28. package/dist/components/exams/take/index.js +1 -2
  29. package/dist/components/exams/take/types.js +1 -1
  30. package/dist/components/index.js +1 -42
  31. package/dist/components/questions/_shared/config/question-types.config.js +1 -333
  32. package/dist/components/questions/_shared/constants/color-palette.js +1 -21
  33. package/dist/components/questions/_shared/hooks/useAnswerGroupQuestionGroup.js +1 -105
  34. package/dist/components/questions/_shared/hooks/useBasicQuestionGroup.js +1 -222
  35. package/dist/components/questions/_shared/hooks/useCompareImagesGroup.js +1 -140
  36. package/dist/components/questions/_shared/hooks/useImageQuestionGroup.js +1 -123
  37. package/dist/components/questions/_shared/hooks/useInfoExchangeGroup.js +1 -50
  38. package/dist/components/questions/_shared/hooks/useQuestionFormState.js +1 -54
  39. package/dist/components/questions/_shared/hooks/useQuestionInitialization.js +1 -123
  40. package/dist/components/questions/_shared/hooks/useQuestionListGroup.js +1 -121
  41. package/dist/components/questions/_shared/hooks/useQuestionOnChange.js +1 -70
  42. package/dist/components/questions/_shared/hooks/useSceneQuestionGroup.js +1 -194
  43. package/dist/components/questions/_shared/index.js +1 -7
  44. package/dist/components/questions/_shared/types/answer-the-question.type.js +1 -1
  45. package/dist/components/questions/_shared/types/arrange-letters-into-words.type.js +1 -1
  46. package/dist/components/questions/_shared/types/choose-correct-adjective.type.js +1 -3
  47. package/dist/components/questions/_shared/types/color-region.config.js +1 -1
  48. package/dist/components/questions/_shared/types/fill-in-blank.type.js +1 -1
  49. package/dist/components/questions/_shared/types/fill-missing-words-in-grid.type.js +1 -1
  50. package/dist/components/questions/_shared/types/gn-speaking-interview.type.js +1 -1
  51. package/dist/components/questions/_shared/types/index.js +1 -12
  52. package/dist/components/questions/_shared/types/label-the-picture.type.js +1 -1
  53. package/dist/components/questions/_shared/types/listen-and-choose-from-answer-group.type.js +1 -1
  54. package/dist/components/questions/_shared/types/listen-and-choose-objects-in-scene.type.js +1 -1
  55. package/dist/components/questions/_shared/types/listen-and-drag-objects-into-scene.type.js +1 -1
  56. package/dist/components/questions/_shared/types/listen-and-speak-answer.type.js +1 -1
  57. package/dist/components/questions/_shared/types/listen-and-speak-compare-images.type.js +1 -1
  58. package/dist/components/questions/_shared/types/listen-and-speak-image-group.type.js +1 -1
  59. package/dist/components/questions/_shared/types/listen-and-speak-info-exchange.type.js +1 -1
  60. package/dist/components/questions/_shared/types/listen-and-speak-odd-one-out.type.js +1 -3
  61. package/dist/components/questions/_shared/types/listen-and-speak-question-list.type.js +1 -1
  62. package/dist/components/questions/_shared/types/listen-and-speak-with-story-images.type.js +1 -3
  63. package/dist/components/questions/_shared/types/listen-and-tick-answer.type.js +1 -1
  64. package/dist/components/questions/_shared/types/listening-drawline.type.js +1 -1
  65. package/dist/components/questions/_shared/types/look-and-choose-answer.type.js +1 -1
  66. package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.js +1 -1
  67. package/dist/components/questions/_shared/types/match-by-writing-answer.type.js +1 -1
  68. package/dist/components/questions/_shared/types/multiple-choice.type.js +1 -1
  69. package/dist/components/questions/_shared/types/question-group.type.js +1 -11
  70. package/dist/components/questions/_shared/types/read-and-color-objects.type.js +1 -1
  71. package/dist/components/questions/_shared/types/read-displayed-content.type.js +1 -1
  72. package/dist/components/questions/_shared/types/read-passage-and-answer-questions.type.js +1 -1
  73. package/dist/components/questions/_shared/types/speaking-describe-image.type.js +1 -1
  74. package/dist/components/questions/_shared/types/spontaneous-qa.type.js +1 -1
  75. package/dist/components/questions/_shared/types/word-fill-paragraph-with-options.type.js +1 -1
  76. package/dist/components/questions/_shared/types/word-fill-paragraph.type.js +1 -1
  77. package/dist/components/questions/_shared/types/word-fill-structured-form.type.js +1 -1
  78. package/dist/components/questions/_shared/types/word-ordering.type.js +1 -1
  79. package/dist/components/questions/_shared/types/write-a-short-letter.type.js +1 -1
  80. package/dist/components/questions/_shared/types/write-correct-verb-form.type.js +1 -3
  81. package/dist/components/questions/_shared/types/write-sentences.type.js +1 -1
  82. package/dist/components/questions/_shared/types/write-short-paragraph.type.js +1 -1
  83. package/dist/components/questions/_shared/utils/answer-builder.js +1 -79
  84. package/dist/components/questions/_shared/utils/createColorRegionRegistration.js +1 -39
  85. package/dist/components/questions/_shared/utils/id-generator.js +1 -3
  86. package/dist/components/questions/_shared/utils/question-validation.js +1 -21
  87. package/dist/components/questions/components/ColorNode.js +1 -85
  88. package/dist/components/questions/components/ColorRegionClient.js +1 -545
  89. package/dist/components/questions/components/ColorRegionCreator.js +1 -420
  90. package/dist/components/questions/components/ColorRegionNode.js +1 -59
  91. package/dist/components/questions/components/CreatorGuide.js +1 -103
  92. package/dist/components/questions/components/NameNode.js +1 -26
  93. package/dist/components/questions/components/QuestionBankOption.js +1 -46
  94. package/dist/components/questions/components/QuestionBasicInfoForm.js +1 -9
  95. package/dist/components/questions/components/QuestionCommonFields.js +1 -33
  96. package/dist/components/questions/components/QuestionSearchDropdown.js +1 -258
  97. package/dist/components/questions/components/QuestionTypeSelector.js +1 -32
  98. package/dist/components/questions/components/QuestionTypeSpecificForms.js +1 -6
  99. package/dist/components/questions/components/RegionNode.js +1 -94
  100. package/dist/components/questions/components/index.js +1 -14
  101. package/dist/components/questions/creator/QuestionCreator.js +1 -90
  102. package/dist/components/questions/creator/QuestionGroupCreator.js +1 -119
  103. package/dist/components/questions/creator/dedicated-component-router.js +1 -79
  104. package/dist/components/questions/creator/index.js +1 -3
  105. package/dist/components/questions/creator/question-type-registry.js +1 -80
  106. package/dist/components/questions/groups/ArticlesGroupCard.js +1 -121
  107. package/dist/components/questions/groups/BasicQuestionGroupCard.js +1 -50
  108. package/dist/components/questions/groups/DocumentGroupCard.js +1 -114
  109. package/dist/components/questions/groups/MatchAnswerGroupCard.js +1 -25
  110. package/dist/components/questions/index.js +1 -10
  111. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +1 -37
  112. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionCreator.js +1 -351
  113. package/dist/components/questions/types/answer-the-question/register.js +1 -67
  114. package/dist/components/questions/types/answer-the-question/transform.js +1 -36
  115. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +1 -141
  116. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsCreator.js +1 -118
  117. package/dist/components/questions/types/arrange-letters-into-words/index.js +1 -2
  118. package/dist/components/questions/types/arrange-letters-into-words/register.js +1 -4
  119. package/dist/components/questions/types/arrange-letters-into-words/transform.js +1 -24
  120. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +1 -64
  121. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js +1 -169
  122. package/dist/components/questions/types/choose-correct-adjective/index.js +1 -2
  123. package/dist/components/questions/types/choose-correct-adjective/register.js +1 -55
  124. package/dist/components/questions/types/choose-correct-adjective/transform.js +1 -16
  125. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +1 -131
  126. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +1 -581
  127. package/dist/components/questions/types/choose-the-correct-answer/index.js +1 -2
  128. package/dist/components/questions/types/choose-the-correct-answer/register.js +1 -101
  129. package/dist/components/questions/types/choose-the-correct-answer/transform.js +1 -43
  130. package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +1 -275
  131. package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +1 -448
  132. package/dist/components/questions/types/fill-in-blank/index.js +1 -2
  133. package/dist/components/questions/types/fill-in-blank/register.js +1 -138
  134. package/dist/components/questions/types/fill-in-blank/transform.js +1 -59
  135. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +1 -117
  136. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridCreator.js +1 -671
  137. package/dist/components/questions/types/fill-missing-words-in-grid/index.js +1 -2
  138. package/dist/components/questions/types/fill-missing-words-in-grid/register.js +1 -37
  139. package/dist/components/questions/types/fill-missing-words-in-grid/transform.js +1 -15
  140. package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.js +1 -262
  141. package/dist/components/questions/types/gn-speaking-interview/register.js +1 -121
  142. package/dist/components/questions/types/gn-speaking-interview/transform.js +1 -48
  143. package/dist/components/questions/types/image-object-matching/ImageObjectMatchingClient.js +1 -16
  144. package/dist/components/questions/types/image-object-matching/ImageObjectMatchingCreator.js +1 -27
  145. package/dist/components/questions/types/image-object-matching/index.js +1 -2
  146. package/dist/components/questions/types/image-object-matching/register.js +1 -3
  147. package/dist/components/questions/types/image-object-matching/transform.js +1 -2
  148. package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +1 -102
  149. package/dist/components/questions/types/label-the-picture/LabelThePictureCreator.js +1 -344
  150. package/dist/components/questions/types/label-the-picture/index.js +1 -2
  151. package/dist/components/questions/types/label-the-picture/register.js +1 -54
  152. package/dist/components/questions/types/label-the-picture/transform.js +1 -28
  153. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +1 -78
  154. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupCreator.js +1 -232
  155. package/dist/components/questions/types/listen-and-choose-from-answer-group/index.js +1 -2
  156. package/dist/components/questions/types/listen-and-choose-from-answer-group/register.js +1 -82
  157. package/dist/components/questions/types/listen-and-choose-from-answer-group/transform.js +1 -27
  158. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneClient.js +1 -70
  159. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneCreator.js +1 -386
  160. package/dist/components/questions/types/listen-and-choose-objects-in-scene/index.js +1 -2
  161. package/dist/components/questions/types/listen-and-choose-objects-in-scene/register.js +1 -100
  162. package/dist/components/questions/types/listen-and-choose-objects-in-scene/transform.js +1 -33
  163. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneClient.js +1 -106
  164. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneCreator.js +1 -457
  165. package/dist/components/questions/types/listen-and-drag-objects-into-scene/index.js +1 -2
  166. package/dist/components/questions/types/listen-and-drag-objects-into-scene/register.js +1 -110
  167. package/dist/components/questions/types/listen-and-drag-objects-into-scene/transform.js +1 -35
  168. package/dist/components/questions/types/listen-and-speak-answer/ArrowIndicator.js +1 -8
  169. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +1 -22
  170. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerCreator.js +1 -291
  171. package/dist/components/questions/types/listen-and-speak-answer/index.js +1 -2
  172. package/dist/components/questions/types/listen-and-speak-answer/register.js +1 -84
  173. package/dist/components/questions/types/listen-and-speak-answer/transform.js +1 -27
  174. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +1 -32
  175. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesCreator.js +1 -295
  176. package/dist/components/questions/types/listen-and-speak-compare-images/register.js +1 -79
  177. package/dist/components/questions/types/listen-and-speak-compare-images/transform.js +1 -27
  178. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +1 -34
  179. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupCreator.js +1 -285
  180. package/dist/components/questions/types/listen-and-speak-image-group/register.js +1 -81
  181. package/dist/components/questions/types/listen-and-speak-image-group/transform.js +1 -26
  182. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +1 -38
  183. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeCreator.js +1 -385
  184. package/dist/components/questions/types/listen-and-speak-info-exchange/register.js +1 -87
  185. package/dist/components/questions/types/listen-and-speak-info-exchange/transform.js +1 -32
  186. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +1 -26
  187. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutCreator.js +1 -247
  188. package/dist/components/questions/types/listen-and-speak-odd-one-out/register.js +1 -59
  189. package/dist/components/questions/types/listen-and-speak-odd-one-out/transform.js +1 -18
  190. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +1 -26
  191. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListCreator.js +1 -256
  192. package/dist/components/questions/types/listen-and-speak-question-list/register.js +1 -81
  193. package/dist/components/questions/types/listen-and-speak-question-list/transform.js +1 -26
  194. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +1 -26
  195. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesCreator.js +1 -230
  196. package/dist/components/questions/types/listen-and-speak-with-story-images/register.js +1 -56
  197. package/dist/components/questions/types/listen-and-speak-with-story-images/transform.js +1 -16
  198. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.js +1 -72
  199. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.js +1 -230
  200. package/dist/components/questions/types/look-picture-choose-correct-answer/index.js +1 -1
  201. package/dist/components/questions/types/look-picture-choose-correct-answer/register.js +1 -66
  202. package/dist/components/questions/types/look-picture-choose-correct-answer/transform.js +1 -42
  203. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.js +1 -96
  204. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.js +1 -238
  205. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.js +1 -2
  206. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.js +1 -76
  207. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.js +1 -19
  208. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.js +1 -134
  209. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.js +1 -617
  210. package/dist/components/questions/types/look-picture-fill-word-hint/index.js +1 -2
  211. package/dist/components/questions/types/look-picture-fill-word-hint/register.js +1 -82
  212. package/dist/components/questions/types/look-picture-fill-word-hint/transform.js +1 -29
  213. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +1 -38
  214. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerCreator.js +1 -359
  215. package/dist/components/questions/types/match-by-writing-answer/index.js +1 -3
  216. package/dist/components/questions/types/match-by-writing-answer/register.js +1 -58
  217. package/dist/components/questions/types/match-by-writing-answer/transform.js +1 -61
  218. package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsClient.js +1 -16
  219. package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsCreator.js +1 -23
  220. package/dist/components/questions/types/read-and-color-objects/index.js +1 -2
  221. package/dist/components/questions/types/read-and-color-objects/register.js +1 -3
  222. package/dist/components/questions/types/read-and-color-objects/transform.js +1 -36
  223. package/dist/components/questions/types/read-displayed-content/ReadDisplayedContentCreator.js +1 -125
  224. package/dist/components/questions/types/read-displayed-content/register.js +1 -64
  225. package/dist/components/questions/types/read-displayed-content/transform.js +1 -12
  226. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +1 -64
  227. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsCreator.js +1 -511
  228. package/dist/components/questions/types/read-passage-and-answer-questions/index.js +1 -2
  229. package/dist/components/questions/types/read-passage-and-answer-questions/register.js +1 -58
  230. package/dist/components/questions/types/read-passage-and-answer-questions/transform.js +1 -28
  231. package/dist/components/questions/types/speaking-conversation/SpeakingConversationCreator.js +1 -373
  232. package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +1 -41
  233. package/dist/components/questions/types/speaking-conversation/register.js +1 -110
  234. package/dist/components/questions/types/speaking-conversation/transform.js +1 -34
  235. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +1 -74
  236. package/dist/components/questions/types/speaking-cue-card/register.js +1 -52
  237. package/dist/components/questions/types/speaking-cue-card/transform.js +1 -12
  238. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +1 -10
  239. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageCreator.js +1 -161
  240. package/dist/components/questions/types/speaking-describe-image/index.js +1 -2
  241. package/dist/components/questions/types/speaking-describe-image/register.js +1 -69
  242. package/dist/components/questions/types/speaking-describe-image/transform.js +1 -16
  243. package/dist/components/questions/types/spontaneous-qa/SpontaneousQACreator.js +1 -234
  244. package/dist/components/questions/types/spontaneous-qa/register.js +1 -93
  245. package/dist/components/questions/types/spontaneous-qa/transform.js +1 -34
  246. package/dist/components/questions/types/true-false/TrueFalseClient.js +1 -75
  247. package/dist/components/questions/types/true-false/TrueFalseCreator.js +1 -244
  248. package/dist/components/questions/types/true-false/index.js +1 -2
  249. package/dist/components/questions/types/true-false/register.js +1 -77
  250. package/dist/components/questions/types/true-false/transform.js +1 -32
  251. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +1 -233
  252. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphCreator.js +1 -631
  253. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphWrapper.js +1 -28
  254. package/dist/components/questions/types/word-fill-paragraph/index.js +1 -2
  255. package/dist/components/questions/types/word-fill-paragraph/register.js +1 -136
  256. package/dist/components/questions/types/word-fill-paragraph/transform.js +1 -56
  257. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -138
  258. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +1 -261
  259. package/dist/components/questions/types/word-fill-structured-form/index.js +1 -2
  260. package/dist/components/questions/types/word-fill-structured-form/register.js +1 -67
  261. package/dist/components/questions/types/word-fill-structured-form/transform.js +1 -40
  262. package/dist/components/questions/types/word-ordering/WordOrderingClient.js +1 -84
  263. package/dist/components/questions/types/word-ordering/WordOrderingCreator.js +1 -192
  264. package/dist/components/questions/types/word-ordering/index.js +1 -2
  265. package/dist/components/questions/types/word-ordering/register.js +1 -46
  266. package/dist/components/questions/types/word-ordering/transform.js +1 -24
  267. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +1 -98
  268. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +1 -320
  269. package/dist/components/questions/types/write-a-short-letter/index.js +1 -2
  270. package/dist/components/questions/types/write-a-short-letter/register.js +1 -68
  271. package/dist/components/questions/types/write-a-short-letter/transform.js +1 -25
  272. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +1 -61
  273. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js +1 -196
  274. package/dist/components/questions/types/write-correct-verb-form/index.js +1 -2
  275. package/dist/components/questions/types/write-correct-verb-form/register.js +1 -62
  276. package/dist/components/questions/types/write-correct-verb-form/transform.js +1 -17
  277. package/dist/components/questions/types/write-sentences/WriteSentencesClient.js +1 -22
  278. package/dist/components/questions/types/write-sentences/WriteSentencesCreator.js +1 -174
  279. package/dist/components/questions/types/write-sentences/index.js +1 -2
  280. package/dist/components/questions/types/write-sentences/register.js +1 -58
  281. package/dist/components/questions/types/write-sentences/transform.js +1 -28
  282. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphClient.js +1 -96
  283. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphCreator.js +1 -161
  284. package/dist/components/questions/types/write-short-paragraph/index.js +1 -2
  285. package/dist/components/questions/types/write-short-paragraph/register.js +1 -4
  286. package/dist/components/questions/types/write-short-paragraph/transform.js +1 -21
  287. package/dist/components/questions/viewer/QuestionGroupViewer.js +1 -36
  288. package/dist/components/questions/viewer/QuestionViewer.js +1 -446
  289. package/dist/components/questions/viewer/index.js +1 -2
  290. package/dist/components/results/ResultReviewPageContainer.js +1 -98
  291. package/dist/components/results/ReviewQuestionRenderer.js +1 -72
  292. package/dist/components/results/index.js +1 -2
  293. package/dist/components/results/result-review.utils.js +1 -6
  294. package/dist/components/results/review-data.js +1 -150
  295. package/dist/components/results/review-renderer.utils.js +1 -97
  296. package/dist/components/results/review-types.js +1 -1
  297. package/dist/components/themes/cambridge-yle/CambridgeYleAudioPlayer.js +1 -138
  298. package/dist/components/themes/cambridge-yle/CambridgeYleBottomNav.js +1 -12
  299. package/dist/components/themes/cambridge-yle/CambridgeYleExamLayout.js +1 -18
  300. package/dist/components/themes/cambridge-yle/CambridgeYleExampleText.js +1 -11
  301. package/dist/components/themes/cambridge-yle/CambridgeYleHeader.js +1 -11
  302. package/dist/components/themes/cambridge-yle/CambridgeYleInstructionBanner.js +1 -9
  303. package/dist/components/themes/cambridge-yle/CambridgeYleNavButton.js +1 -13
  304. package/dist/components/themes/cambridge-yle/CambridgeYlePartBanner.js +1 -8
  305. package/dist/components/themes/cambridge-yle/CambridgeYleProgressBar.js +1 -6
  306. package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCard.js +1 -5
  307. package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCardFullWidth.js +1 -9
  308. package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.js +1 -41
  309. package/dist/components/themes/cambridge-yle/CambridgeYleTimer.js +1 -25
  310. package/dist/components/themes/cambridge-yle/index.js +1 -13
  311. package/dist/components/themes/english-certification/EcAnswerTheQuestion.js +1 -24
  312. package/dist/components/themes/english-certification/EcMatchByWritingAnswer.js +1 -88
  313. package/dist/components/themes/english-certification/EcWordFillParagraph.js +1 -55
  314. package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -156
  315. package/dist/components/themes/english-certification/EcWritingTask.js +1 -34
  316. package/dist/components/themes/english-certification/EnglishCertificationAudioPlayer.js +1 -114
  317. package/dist/components/themes/english-certification/EnglishCertificationBrand.js +1 -11
  318. package/dist/components/themes/english-certification/EnglishCertificationExamLayout.js +1 -21
  319. package/dist/components/themes/english-certification/EnglishCertificationFlagButton.js +1 -15
  320. package/dist/components/themes/english-certification/EnglishCertificationFooterBar.js +1 -19
  321. package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.js +1 -148
  322. package/dist/components/themes/english-certification/EnglishCertificationHeader.js +1 -31
  323. package/dist/components/themes/english-certification/EnglishCertificationNavigationPanel.js +1 -71
  324. package/dist/components/themes/english-certification/EnglishCertificationOptionSelector.js +1 -33
  325. package/dist/components/themes/english-certification/EnglishCertificationPassagePanel.js +1 -16
  326. package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.js +1 -22
  327. package/dist/components/themes/english-certification/EnglishCertificationQuestionItem.js +1 -37
  328. package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -72
  329. package/dist/components/themes/english-certification/EnglishCertificationReadingSection.js +1 -90
  330. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestion.js +1 -18
  331. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js +1 -29
  332. package/dist/components/themes/english-certification/english-certification-theme.js +1 -58
  333. package/dist/components/themes/english-certification/grouped-question-utils.js +1 -218
  334. package/dist/components/themes/english-certification/index.js +1 -21
  335. package/dist/components/themes/index.js +1 -6
  336. package/dist/components/themes/summer-sky/SummerSkyAudioPlayer.js +1 -170
  337. package/dist/components/themes/summer-sky/SummerSkyLayout.js +1 -221
  338. package/dist/components/themes/summer-sky/SummerSkySubmitModal.js +1 -18
  339. package/dist/components/themes/summer-sky/SummerSkyWaitingRoom.js +1 -194
  340. package/dist/components/themes/types.js +1 -1
  341. package/dist/components/ui/alert-dialog.js +1 -26
  342. package/dist/components/ui/alert.js +1 -22
  343. package/dist/components/ui/avatar.js +1 -12
  344. package/dist/components/ui/badge.js +1 -38
  345. package/dist/components/ui/button.js +1 -35
  346. package/dist/components/ui/calendar.js +1 -76
  347. package/dist/components/ui/card.js +1 -16
  348. package/dist/components/ui/carousel.js +1 -91
  349. package/dist/components/ui/checkbox.js +1 -9
  350. package/dist/components/ui/collapsible.js +1 -13
  351. package/dist/components/ui/command.js +1 -34
  352. package/dist/components/ui/confirm-dialog.js +1 -49
  353. package/dist/components/ui/dialog.js +1 -23
  354. package/dist/components/ui/drawer.js +1 -35
  355. package/dist/components/ui/dropdown-menu.js +1 -33
  356. package/dist/components/ui/file-upload.js +1 -155
  357. package/dist/components/ui/form.js +1 -62
  358. package/dist/components/ui/hover-card.js +1 -10
  359. package/dist/components/ui/image-preview.js +1 -29
  360. package/dist/components/ui/input.js +1 -8
  361. package/dist/components/ui/label.js +1 -9
  362. package/dist/components/ui/language-switcher.js +1 -15
  363. package/dist/components/ui/multi-select.js +1 -90
  364. package/dist/components/ui/points-input.js +1 -33
  365. package/dist/components/ui/popover.js +1 -26
  366. package/dist/components/ui/progress.js +1 -16
  367. package/dist/components/ui/radio-group.js +1 -12
  368. package/dist/components/ui/scroll-area.js +1 -11
  369. package/dist/components/ui/select.js +1 -38
  370. package/dist/components/ui/separator.js +1 -8
  371. package/dist/components/ui/sheet.js +1 -40
  372. package/dist/components/ui/single-select.js +1 -76
  373. package/dist/components/ui/skeleton.js +1 -6
  374. package/dist/components/ui/switch.js +1 -8
  375. package/dist/components/ui/table.js +1 -20
  376. package/dist/components/ui/tabs.js +1 -17
  377. package/dist/components/ui/textarea.js +1 -8
  378. package/dist/components/ui/tooltip.js +1 -11
  379. package/dist/index.js +1 -19
  380. package/dist/mcp/config.js +1 -32
  381. package/dist/mcp/http-client.js +1 -48
  382. package/dist/mcp/index.js +1 -29
  383. package/dist/mcp/tools/_helpers.js +1 -25
  384. package/dist/mcp/tools/exams.js +1 -439
  385. package/dist/mcp/tools/index.js +1 -6
  386. package/dist/mcp/tools/results.js +1 -19
  387. package/dist/shared/constants/ApiConstant.js +1 -276
  388. package/dist/shared/constants/QueryKeyConstant.js +1 -112
  389. package/dist/shared/constants/exam-level.enum.js +1 -41
  390. package/dist/shared/constants/landings/placement-test.constants.js +1 -431
  391. package/dist/shared/constants/question-skills.js +1 -267
  392. package/dist/shared/constants/routes.js +1 -81
  393. package/dist/shared/index.js +1 -7
  394. package/dist/shared/lib/hooks/index.js +1 -10
  395. package/dist/shared/lib/hooks/useAlertDialog.js +1 -57
  396. package/dist/shared/lib/hooks/useAudioPlayCounter.js +1 -30
  397. package/dist/shared/lib/hooks/useAudioPreview.js +1 -81
  398. package/dist/shared/lib/hooks/useAudioUpload.js +1 -24
  399. package/dist/shared/lib/hooks/useConfirmDialog.js +1 -89
  400. package/dist/shared/lib/hooks/useDebouncedCallback.js +1 -32
  401. package/dist/shared/lib/hooks/useDelayedAutoPlay.js +1 -12
  402. package/dist/shared/lib/hooks/useFileUpload.js +1 -24
  403. package/dist/shared/lib/hooks/useImageUrl.js +1 -5
  404. package/dist/shared/lib/hooks/usePresignedFileUrl.js +1 -10
  405. package/dist/shared/lib/hooks/useReactHookForm.js +1 -31
  406. package/dist/shared/lib/hooks/useToast.js +1 -62
  407. package/dist/shared/lib/i18n/index.js +1 -54
  408. package/dist/shared/lib/i18n/messages/en/admin.js +1 -2104
  409. package/dist/shared/lib/i18n/messages/en/auth.js +1 -86
  410. package/dist/shared/lib/i18n/messages/en/common.js +1 -140
  411. package/dist/shared/lib/i18n/messages/en/file-upload.js +1 -18
  412. package/dist/shared/lib/i18n/messages/en/student.js +1 -133
  413. package/dist/shared/lib/i18n/messages/en/terms.js +1 -37
  414. package/dist/shared/lib/i18n/messages/en.js +1 -15
  415. package/dist/shared/lib/i18n/messages/vi/admin.js +1 -2104
  416. package/dist/shared/lib/i18n/messages/vi/auth.js +1 -86
  417. package/dist/shared/lib/i18n/messages/vi/common.js +1 -140
  418. package/dist/shared/lib/i18n/messages/vi/file-upload.js +1 -18
  419. package/dist/shared/lib/i18n/messages/vi/student.js +1 -133
  420. package/dist/shared/lib/i18n/messages/vi/terms.js +1 -37
  421. package/dist/shared/lib/i18n/messages/vi.js +1 -15
  422. package/dist/shared/lib/i18n/types.js +1 -1
  423. package/dist/shared/lib/stores/examQuestionStore.js +1 -212
  424. package/dist/shared/lib/stores/localeStore.js +1 -10
  425. package/dist/shared/lib/utils/public-page.js +1 -44
  426. package/dist/shared/lib/utils/question-transform-types.js +1 -1
  427. package/dist/shared/lib/utils/question-transform.js +1 -174
  428. package/dist/shared/lib/utils.js +1 -168
  429. package/dist/shared/lib/validation/choose-correct-answer.validation.js +1 -111
  430. package/dist/shared/lib/validation/label-the-picture.validation.js +1 -19
  431. package/dist/shared/lib/validation/listen-and-choose-from-answer-group.validation.js +1 -46
  432. package/dist/shared/lib/validation/listen-and-choose-objects-in-scene.validation.js +1 -21
  433. package/dist/shared/lib/validation/listen-and-drag-objects-into-scene.validation.js +1 -34
  434. package/dist/shared/lib/validation/listen-and-speak-answer.validation.js +1 -40
  435. package/dist/shared/lib/validation/listen-and-speak-compare-images.validation.js +1 -45
  436. package/dist/shared/lib/validation/listen-and-speak-image-group.validation.js +1 -19
  437. package/dist/shared/lib/validation/listen-and-speak-info-exchange.validation.js +1 -39
  438. package/dist/shared/lib/validation/listen-and-speak-odd-one-out.validation.js +1 -32
  439. package/dist/shared/lib/validation/listen-and-speak-question-list.validation.js +1 -19
  440. package/dist/shared/lib/validation/listen-and-speak-with-story-images.validation.js +1 -28
  441. package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.js +1 -12
  442. package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.js +1 -47
  443. package/dist/shared/lib/validation/read-and-color-objects.validation.js +1 -29
  444. package/dist/shared/lib/validation/read-displayed-content.validation.js +1 -28
  445. package/dist/shared/lib/validation/speaking-conversation.validation.js +1 -75
  446. package/dist/shared/lib/validation/speaking-describe-image.validation.js +1 -31
  447. package/dist/shared/lib/validation/spontaneous-qa.validation.js +1 -48
  448. package/dist/shared/lib/validation/word-fill-paragraph-default.validation.js +1 -38
  449. package/dist/shared/lib/validation/word-fill-paragraph-with-options.validation.js +1 -39
  450. package/dist/shared/lib/validation/word-fill-paragraph.validation.js +1 -43
  451. package/dist/shared/lib/validation/word-ordering.validation.js +1 -33
  452. package/dist/shared/types/branch.types.js +1 -6
  453. package/dist/shared/types/common.types.js +1 -50
  454. package/dist/shared/types/entities/exam-schedule.types.js +1 -5
  455. package/dist/shared/types/entities/exam.types.js +1 -1
  456. package/dist/shared/types/entities/question.types.js +1 -4
  457. package/dist/shared/types/entities/result.types.js +1 -4
  458. package/dist/shared/types/entities/user.types.js +1 -4
  459. package/dist/shared/types/exam-taking.types.js +1 -2
  460. package/dist/shared/types/history.types.js +1 -34
  461. package/dist/shared/types/index.js +1 -1
  462. package/dist/shared/types/questions/choose-correct-adjective.js +1 -4
  463. package/dist/shared/types/questions/choose-the-correct-answer.js +1 -9
  464. package/dist/shared/types/questions/fill-missing-words-in-grid.js +1 -11
  465. package/dist/shared/types/questions/index.js +1 -40
  466. package/dist/shared/types/questions/listen-and-speak-answer.js +1 -1
  467. package/dist/shared/types/questions/listen-and-speak-compare-images.js +1 -1
  468. package/dist/shared/types/questions/listen-and-speak-image-group.js +1 -1
  469. package/dist/shared/types/questions/listen-and-speak-info-exchange.js +1 -3
  470. package/dist/shared/types/questions/listen-and-speak-odd-one-out.js +1 -3
  471. package/dist/shared/types/questions/listen-and-speak-question-list.js +1 -1
  472. package/dist/shared/types/questions/listen-and-speak-with-story-images.js +1 -3
  473. package/dist/shared/types/questions/look-picture-choose-correct-answer.js +1 -5
  474. package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.js +1 -9
  475. package/dist/shared/types/questions/look-picture-fill-word-hint.js +1 -7
  476. package/dist/shared/types/questions/read-displayed-content.js +1 -1
  477. package/dist/shared/types/questions/speaking-conversation.js +1 -7
  478. package/dist/shared/types/questions/speaking-describe-image.js +1 -1
  479. package/dist/shared/types/questions/spontaneous-qa.js +1 -1
  480. package/dist/shared/types/questions/write-correct-verb-form.js +1 -12
  481. package/dist/shared/types/role.types.js +1 -1
  482. package/dist/shared/types/structure-management.js +1 -28
  483. package/dist/shared/types/student.types.js +1 -54
  484. package/dist/shared/types/teacher-dashboard-rooms.js +1 -2
  485. package/package.json +4 -2
@@ -1,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})]})]})]})})}