@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,11 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import Image from 'next/image';
3
- import { CambridgeYleTimer } from './CambridgeYleTimer';
4
- import { Loader2 } from 'lucide-react';
5
- import arrowLeftImg from '../summer-sky/assets/images/arrow-left.png';
6
- import titleLogoImg from '../summer-sky/assets/images/title-logo.png';
7
- import submitImg from '../summer-sky/assets/images/submit.png';
8
- import hasAnsweredImg from '../summer-sky/assets/images/has_answered.png';
9
- export function CambridgeYleHeader({ totalQuestions, answeredCount, remainingSeconds, isSubmitting, isCameraActive, onSubmit, onClose, }) {
10
- return (_jsxs("header", { className: "w-full bg-transparent px-4 pt-4 pb-0 sm:px-8 relative flex flex-wrap sm:flex-nowrap items-start sm:items-center justify-between z-50", children: [_jsx("div", { onClick: onClose, className: "cursor-pointer hover:scale-105 active:scale-95 transition-transform shrink-0", title: "Tho\u00E1t b\u00E0i thi", children: _jsx(Image, { src: arrowLeftImg, alt: "Quay l\u1EA1i", className: "w-[50px] sm:w-[80px]" }) }), _jsx("div", { className: "absolute left-1/2 -translate-x-1/2 -top-2 sm:top-0 pointer-events-none hidden sm:block", children: _jsx(Image, { src: titleLogoImg, alt: "Title Logo", className: "w-[200px] sm:w-[320px] h-auto" }) }), _jsx("div", { className: "sm:hidden flex-1 flex justify-center pointer-events-none", children: _jsx(Image, { src: titleLogoImg, alt: "Title Logo", className: "w-[150px] h-auto -mt-2" }) }), _jsxs("div", { className: "absolute right-4 sm:right-8 top-8 flex flex-row items-center gap-3 sm:gap-4 z-[100]", children: [isCameraActive && (_jsx("div", { className: "flex items-center justify-center rounded-full bg-white/20 p-2 backdrop-blur-sm shrink-0", title: "Camera \u0111ang ghi h\u00ECnh", children: _jsx("div", { className: "h-3 w-3 animate-pulse rounded-full bg-red-500" }) })), _jsx(CambridgeYleTimer, { remainingSeconds: remainingSeconds, totalQuestions: totalQuestions, answeredCount: answeredCount }), _jsxs("div", { className: "flex items-center w-[130px] sm:w-[170px] h-[40px] sm:h-[50px] rounded-[33.5px] bg-[#FF9900] shadow-[0_4px_20px_rgba(0,0,0,0.25)] border-none shrink-0", title: "S\u1ED1 c\u00E2u h\u1ECFi \u0111\u00E3 ho\u00E0n th\u00E0nh", children: [_jsx(Image, { src: hasAnsweredImg, alt: "Progress", width: 75, height: 75, className: "w-[50px] sm:w-[65px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none z-10" }), _jsxs("span", { className: "flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]", style: { fontFamily: '"SVN-Volte Rounded", "Quicksand", sans-serif', textShadow: '0 2px 4px rgba(0,0,0,0.2)' }, children: [answeredCount, "/", totalQuestions] })] }), _jsxs("button", { onClick: onSubmit, disabled: isSubmitting, className: `group cursor-pointer flex items-center h-[40px] sm:h-[50px] w-[130px] sm:w-[170px] rounded-[33.5px] shadow-[0_4px_20px_rgba(0,0,0,0.25)] transition-all duration-300 hover:scale-105 active:scale-95 disabled:pointer-events-none disabled:opacity-60 border-none shrink-0 ${isSubmitting ? 'bg-slate-400' : 'bg-[#16CA3B] hover:bg-[#15b736]'}`, children: [_jsx(Image, { src: submitImg, alt: "Submit", width: 75, height: 75, className: "w-[50px] sm:w-[65px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none transition-transform duration-300 group-hover:scale-110 z-10" }), isSubmitting ? (_jsx("div", { className: "flex-1 flex justify-center pr-[10px] sm:pr-[16px]", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-white" }) })) : (_jsx("span", { className: "flex-1 text-center font-bold text-[18px] sm:text-[20px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]", style: { fontFamily: '"SVN-Volte Rounded", "Quicksand", sans-serif', textShadow: '0 2px 4px rgba(0,0,0,0.2)' }, children: "N\u1ED9p b\u00E0i" }))] })] })] }));
11
- }
1
+ import{jsx as e,jsxs as s}from"react/jsx-runtime";import t from"next/image";import{CambridgeYleTimer as r}from"./CambridgeYleTimer";import{Loader2 as a}from"lucide-react";import i from"../summer-sky/assets/images/arrow-left.png";import n from"../summer-sky/assets/images/title-logo.png";import o from"../summer-sky/assets/images/submit.png";import m from"../summer-sky/assets/images/has_answered.png";export function CambridgeYleHeader({totalQuestions:l,answeredCount:p,remainingSeconds:x,isSubmitting:d,isCameraActive:c,onSubmit:h,onClose:u}){return s("header",{className:"w-full bg-transparent px-4 pt-4 pb-0 sm:px-8 relative flex flex-wrap sm:flex-nowrap items-start sm:items-center justify-between z-50",children:[e("div",{onClick:u,className:"cursor-pointer hover:scale-105 active:scale-95 transition-transform shrink-0",title:"Thoát bài thi",children:e(t,{src:i,alt:"Quay lại",className:"w-[50px] sm:w-[80px]"})}),e("div",{className:"absolute left-1/2 -translate-x-1/2 -top-2 sm:top-0 pointer-events-none hidden sm:block",children:e(t,{src:n,alt:"Title Logo",className:"w-[200px] sm:w-[320px] h-auto"})}),e("div",{className:"sm:hidden flex-1 flex justify-center pointer-events-none",children:e(t,{src:n,alt:"Title Logo",className:"w-[150px] h-auto -mt-2"})}),s("div",{className:"absolute right-4 sm:right-8 top-8 flex flex-row items-center gap-3 sm:gap-4 z-[100]",children:[c&&e("div",{className:"flex items-center justify-center rounded-full bg-white/20 p-2 backdrop-blur-sm shrink-0",title:"Camera đang ghi hình",children:e("div",{className:"h-3 w-3 animate-pulse rounded-full bg-red-500"})}),e(r,{remainingSeconds:x,totalQuestions:l,answeredCount:p}),s("div",{className:"flex items-center w-[130px] sm:w-[170px] h-[40px] sm:h-[50px] rounded-[33.5px] bg-[#FF9900] shadow-[0_4px_20px_rgba(0,0,0,0.25)] border-none shrink-0",title:"Số câu hỏi đã hoàn thành",children:[e(t,{src:m,alt:"Progress",width:75,height:75,className:"w-[50px] sm:w-[65px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none z-10"}),s("span",{className:"flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]",style:{fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif',textShadow:"0 2px 4px rgba(0,0,0,0.2)"},children:[p,"/",l]})]}),s("button",{onClick:h,disabled:d,className:"group cursor-pointer flex items-center h-[40px] sm:h-[50px] w-[130px] sm:w-[170px] rounded-[33.5px] shadow-[0_4px_20px_rgba(0,0,0,0.25)] transition-all duration-300 hover:scale-105 active:scale-95 disabled:pointer-events-none disabled:opacity-60 border-none shrink-0 "+(d?"bg-slate-400":"bg-[#16CA3B] hover:bg-[#15b736]"),children:[e(t,{src:o,alt:"Submit",width:75,height:75,className:"w-[50px] sm:w-[65px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none transition-transform duration-300 group-hover:scale-110 z-10"}),d?e("div",{className:"flex-1 flex justify-center pr-[10px] sm:pr-[16px]",children:e(a,{className:"h-6 w-6 animate-spin text-white"})}):e("span",{className:"flex-1 text-center font-bold text-[18px] sm:text-[20px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]",style:{fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif',textShadow:"0 2px 4px rgba(0,0,0,0.2)"},children:"Nộp bài"})]})]})]})}
@@ -1,9 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Info, Megaphone } from 'lucide-react';
4
- export default function CambridgeYleInstructionBanner({ instruction, instructions, hasExample = false, children, isReviewMode = false, }) {
5
- if (isReviewMode)
6
- return null;
7
- const hasInstructionsList = instructions && instructions.length > 0;
8
- return (_jsxs("div", { className: "shrink-0 space-y-3 px-2 sm:px-6 mb-2 sm:mb-4", children: [instruction && (_jsxs("div", { className: "flex w-full items-center gap-4 sm:gap-5 rounded-[24px] bg-[#F8FBFF] border-2 border-dashed border-blue-300 px-5 py-4 transition-all hover:bg-blue-50/50", children: [_jsx("div", { className: "flex items-center justify-center w-12 h-12 sm:w-14 sm:h-14 rounded-[16px] bg-[#0070FF] shadow-[4px_4px_0px_rgba(191,219,254,1)] shrink-0 -rotate-6 transition-transform hover:rotate-0", children: _jsx(Megaphone, { className: "h-6 w-6 sm:h-7 sm:w-7 text-white", strokeWidth: 2.5 }) }), _jsx("div", { className: "flex-1 flex flex-col justify-center", children: _jsxs("p", { className: "text-[15px] sm:text-[18px] font-black uppercase tracking-wide text-[#002868] leading-snug", style: { fontFamily: '"SVN-Volte Rounded", "Quicksand", sans-serif' }, children: [instruction, hasExample && _jsx("span", { className: "inline-block text-[#0070FF] ml-2 text-[14px] sm:text-[16px] font-bold tracking-normal bg-blue-100 px-3 py-0.5 rounded-full align-middle -mt-1", children: "THERE IS ONE EXAMPLE" })] }) })] })), children, hasInstructionsList && (_jsx("div", { className: "rounded-lg border border-blue-200 bg-white p-4 shadow-sm", children: _jsxs("div", { className: "space-y-3", children: [_jsxs("h4", { className: "flex items-center gap-2 font-semibold text-blue-900", children: [_jsx(Info, { className: "h-4 w-4" }), "Instructions"] }), _jsx("ol", { className: "list-inside list-decimal space-y-1.5 text-sm text-gray-700", children: instructions.map((item, index) => (_jsx("li", { className: "leading-relaxed", children: item }, index))) })] }) }))] }));
9
- }
1
+ "use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import{Info as t,Megaphone as l}from"lucide-react";export default function a({instruction:a,instructions:i,hasExample:r=!1,children:n,isReviewMode:d=!1}){if(d)return null;const c=i&&i.length>0;return s("div",{className:"shrink-0 space-y-3 px-2 sm:px-6 mb-2 sm:mb-4",children:[a&&s("div",{className:"flex w-full items-center gap-4 sm:gap-5 rounded-[24px] bg-[#F8FBFF] border-2 border-dashed border-blue-300 px-5 py-4 transition-all hover:bg-blue-50/50",children:[e("div",{className:"flex items-center justify-center w-12 h-12 sm:w-14 sm:h-14 rounded-[16px] bg-[#0070FF] shadow-[4px_4px_0px_rgba(191,219,254,1)] shrink-0 -rotate-6 transition-transform hover:rotate-0",children:e(l,{className:"h-6 w-6 sm:h-7 sm:w-7 text-white",strokeWidth:2.5})}),e("div",{className:"flex-1 flex flex-col justify-center",children:s("p",{className:"text-[15px] sm:text-[18px] font-black uppercase tracking-wide text-[#002868] leading-snug",style:{fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif'},children:[a,r&&e("span",{className:"inline-block text-[#0070FF] ml-2 text-[14px] sm:text-[16px] font-bold tracking-normal bg-blue-100 px-3 py-0.5 rounded-full align-middle -mt-1",children:"THERE IS ONE EXAMPLE"})]})})]}),n,c&&e("div",{className:"rounded-lg border border-blue-200 bg-white p-4 shadow-sm",children:s("div",{className:"space-y-3",children:[s("h4",{className:"flex items-center gap-2 font-semibold text-blue-900",children:[e(t,{className:"h-4 w-4"}),"Instructions"]}),e("ol",{className:"list-inside list-decimal space-y-1.5 text-sm text-gray-700",children:i.map((s,t)=>e("li",{className:"leading-relaxed",children:s},t))})]})})]})}
@@ -1,13 +1 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import Image from 'next/image';
3
- import prevBtnImg from '../summer-sky/assets/images/prev-question-btn.png';
4
- import nextBtnImg from '../summer-sky/assets/images/next-question-btn.png';
5
- export function CambridgeYleNavButton({ direction, onClick, disabled = false, }) {
6
- const imgSrc = direction === 'prev' ? prevBtnImg : nextBtnImg;
7
- const altText = direction === 'prev' ? 'Câu trước' : 'Câu tiếp theo';
8
- return (_jsx("button", { onClick: onClick, disabled: disabled, className: `flex items-center justify-center transition-transform outline-none bg-transparent border-none
9
- ${disabled
10
- ? 'cursor-not-allowed opacity-45 grayscale pointer-events-none'
11
- : 'cursor-pointer hover:scale-[1.05] active:scale-[0.95]'}
12
- `, "aria-label": altText, title: disabled ? 'Không thể chuyển câu' : undefined, children: _jsx(Image, { src: imgSrc, alt: altText, className: "w-16 h-auto sm:w-20" }) }));
13
- }
1
+ import{jsx as e}from"react/jsx-runtime";import t from"next/image";import n from"../summer-sky/assets/images/prev-question-btn.png";import r from"../summer-sky/assets/images/next-question-btn.png";export function CambridgeYleNavButton({direction:s,onClick:o,disabled:i=!1}){const a="prev"===s?"Câu trước":"Câu tiếp theo";return e("button",{onClick:o,disabled:i,className:`flex items-center justify-center transition-transform outline-none bg-transparent border-none\n ${i?"cursor-not-allowed opacity-45 grayscale pointer-events-none":"cursor-pointer hover:scale-[1.05] active:scale-[0.95]"}\n `,"aria-label":a,title:i?"Không thể chuyển câu":void 0,children:e(t,{src:"prev"===s?n:r,alt:a,className:"w-16 h-auto sm:w-20"})})}
@@ -1,8 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import Image from 'next/image';
3
- import backgroundTitleImg from '../summer-sky/assets/images/background_title.png';
4
- export default function CambridgeYlePartBanner({ partName, isReviewMode = false, }) {
5
- if (!partName || isReviewMode)
6
- return null;
7
- return (_jsxs("div", { className: "relative mx-auto flex shrink-0 items-center justify-center w-[260px] sm:w-[320px] h-[55px] sm:h-[70px] drop-shadow-[0_4px_6px_rgba(0,0,0,0.3)] mb-1 sm:mb-2 mt-0", children: [_jsx(Image, { src: backgroundTitleImg, alt: "Part Badge", fill: true, className: "object-fill pointer-events-none" }), _jsx("span", { className: "relative z-10 text-yellow-300 font-black uppercase text-[24px] sm:text-[30px] tracking-[0.08em] -translate-y-0.5 sm:-translate-y-1", style: { textShadow: '0px 2px 4px rgba(0,0,0,0.8)', fontFamily: '"SVN-Volte Rounded", "Quicksand", sans-serif' }, children: partName })] }));
8
- }
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import s from"next/image";import a from"../summer-sky/assets/images/background_title.png";export default function r({partName:r,isReviewMode:m=!1}){return!r||m?null:t("div",{className:"relative mx-auto flex shrink-0 items-center justify-center w-[260px] sm:w-[320px] h-[55px] sm:h-[70px] drop-shadow-[0_4px_6px_rgba(0,0,0,0.3)] mb-1 sm:mb-2 mt-0",children:[e(s,{src:a,alt:"Part Badge",fill:!0,className:"object-fill pointer-events-none"}),e("span",{className:"relative z-10 text-yellow-300 font-black uppercase text-[24px] sm:text-[30px] tracking-[0.08em] -translate-y-0.5 sm:-translate-y-1",style:{textShadow:"0px 2px 4px rgba(0,0,0,0.8)",fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif'},children:r})]})}
@@ -1,6 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Trophy } from 'lucide-react';
3
- export function CambridgeYleProgressBar({ progress, className = '', }) {
4
- const clampedProgress = Math.min(100, Math.max(0, progress));
5
- return (_jsxs("div", { className: `flex items-center gap-2 sm:gap-3 ${className}`, children: [_jsx("div", { className: "relative h-2 w-full max-w-md overflow-hidden rounded-full bg-gray-200 sm:h-3", children: _jsx("div", { className: "h-full rounded-full bg-gradient-to-r from-orange-400 via-red-400 to-red-500 transition-all duration-300 ease-out", style: { width: `${clampedProgress}%` } }) }), _jsx("div", { className: "flex h-6 w-6 flex-shrink-0 items-center justify-center sm:h-8 sm:w-8", children: _jsx(Trophy, { className: "h-5 w-5 text-yellow-500 sm:h-6 sm:w-6" }) })] }));
6
- }
1
+ import{jsx as e,jsxs as r}from"react/jsx-runtime";import{Trophy as s}from"lucide-react";export function CambridgeYleProgressBar({progress:a,className:l=""}){const t=Math.min(100,Math.max(0,a));return r("div",{className:`flex items-center gap-2 sm:gap-3 ${l}`,children:[e("div",{className:"relative h-2 w-full max-w-md overflow-hidden rounded-full bg-gray-200 sm:h-3",children:e("div",{className:"h-full rounded-full bg-gradient-to-r from-orange-400 via-red-400 to-red-500 transition-all duration-300 ease-out",style:{width:`${t}%`}})}),e("div",{className:"flex h-6 w-6 flex-shrink-0 items-center justify-center sm:h-8 sm:w-8",children:e(s,{className:"h-5 w-5 text-yellow-500 sm:h-6 sm:w-6"})})]})}
@@ -1,5 +1 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { cn } from '../../../shared/lib/utils';
3
- export default function CambridgeYleQuestionCard({ children, className, }) {
4
- return _jsx("div", { className: cn('relative w-full h-full flex flex-col', className), children: children });
5
- }
1
+ import{jsx as l}from"react/jsx-runtime";import{cn as e}from"../../../shared/lib/utils";export default function r({children:r,className:i}){return l("div",{className:e("relative w-full h-full flex flex-col",i),children:r})}
@@ -1,9 +1 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { cn } from '../../../shared/lib/utils';
3
- /**
4
- * Full-width question card container for coloring/painting questions.
5
- * Uses background without dashed separator (unlike CambridgeYleQuestionCard).
6
- */
7
- export default function CambridgeYleQuestionCardFullWidth({ children, className, }) {
8
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: cn('relative mx-auto flex min-h-[70vh] w-full flex-1 flex-col rounded-2xl bg-white p-4 shadow-lg lg:hidden', className), children: _jsx("div", { className: "flex-1 overflow-auto", children: children }) }), _jsx("div", { className: cn('relative mx-auto hidden w-full max-w-[1400px] flex-1 min-h-0 flex-col rounded-[24px] border-[12px] border-[#3182CE] bg-white shadow-xl lg:flex', className), children: _jsx("div", { className: "flex-1 overflow-auto p-6 md:p-8", children: children }) })] }));
9
- }
1
+ import{jsx as e,Fragment as l,jsxs as r}from"react/jsx-runtime";import{cn as a}from"../../../shared/lib/utils";export default function d({children:d,className:i}){return r(l,{children:[e("div",{className:a("relative mx-auto flex min-h-[70vh] w-full flex-1 flex-col rounded-2xl bg-white p-4 shadow-lg lg:hidden",i),children:e("div",{className:"flex-1 overflow-auto",children:d})}),e("div",{className:a("relative mx-auto hidden w-full max-w-[1400px] flex-1 min-h-0 flex-col rounded-[24px] border-[12px] border-[#3182CE] bg-white shadow-xl lg:flex",i),children:e("div",{className:"flex-1 overflow-auto p-6 md:p-8",children:d})})]})}
@@ -1,41 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { cn } from '../../../shared/lib/utils';
3
- import Image from 'next/image';
4
- import phaoImg from './assets/images/phao.png';
5
- import sanhoImg from './assets/images/sanho.png';
6
- import saoImg from './assets/images/sao.png';
7
- import voocImg from './assets/images/vooc.png';
8
- const PART_ICONS = [phaoImg, sanhoImg, saoImg, voocImg];
9
- export function CambridgeYleSidebar({ parts, questions, currentQuestionGlobalIndex, onPartClick, onQuestionClick, isNavDisabled, className, }) {
10
- const currentQuestion = questions[currentQuestionGlobalIndex];
11
- const currentPartIndex = currentQuestion ? currentQuestion.partIndex : 0;
12
- return (_jsxs("div", { className: cn("flex flex-col w-full h-full pb-4", className), children: [_jsxs("div", { className: "flex-1 overflow-y-auto custom-scrollbar p-4 lg:p-6 pb-2", children: [_jsxs("div", { className: "flex items-center gap-2 mb-4 justify-center uppercase tracking-widest text-[16px]", children: [_jsx("div", { className: "flex items-center justify-center p-1.5 bg-gradient-to-br from-blue-400 to-blue-600 rounded-xl text-white", children: _jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }), _jsx("polyline", { points: "2 17 12 22 22 17" }), _jsx("polyline", { points: "2 12 12 17 22 12" })] }) }), _jsx("span", { className: "font-black bg-gradient-to-r from-blue-700 to-blue-500 bg-clip-text text-transparent", children: "Parts" })] }), _jsx("div", { className: "flex flex-col gap-2.5", children: parts.map((part, idx) => {
13
- const isCurrent = idx === currentPartIndex;
14
- const iconSrc = PART_ICONS[idx % PART_ICONS.length];
15
- const prevCategory = idx > 0 ? parts[idx - 1].category : null;
16
- const showCategoryTitle = part.category && part.category !== prevCategory;
17
- return (_jsxs("div", { className: "flex flex-col", children: [showCategoryTitle && (_jsxs("div", { className: "flex items-center gap-2 mt-5 mb-3 px-1", children: [_jsx("div", { className: "h-[4px] w-4 rounded-full bg-blue-500" }), _jsx("span", { className: "text-[14px] font-black uppercase tracking-[0.15em] text-blue-800", children: part.category?.replace(/_/g, ' ') }), _jsx("div", { className: "h-[2px] flex-1 rounded-full bg-blue-100" })] })), _jsxs("button", { type: "button", onClick: () => onPartClick(idx), disabled: isNavDisabled, className: cn("flex items-center justify-between p-2 px-[15px] rounded-[15px] transition-all border font-medium shadow-sm", isCurrent
18
- ? "bg-blue-600 text-white border-blue-600"
19
- : "bg-white text-slate-800 border-transparent", !isCurrent && !isNavDisabled ? "hover:border-blue-200" : "", isNavDisabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"), children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex items-center justify-center w-8 h-8 shrink-0", children: _jsx(Image, { src: iconSrc, alt: `part icon ${idx}`, className: "w-[30px] h-auto object-contain" }) }), _jsx("span", { className: "font-black text-[15px]", children: part.name || `Part ${part.partNo}` })] }), _jsxs("span", { className: cn("text-[13px] font-bold tracking-wide", isCurrent ? "text-blue-100" : "text-blue-900/60"), children: [part.answeredCount, "/", part.totalQuestions] })] })] }, idx));
20
- }) })] }), _jsx("div", { className: "px-6", children: _jsx("hr", { className: "border-t-2 border-dashed border-blue-100" }) }), _jsxs("div", { className: "flex-1 p-4 lg:p-6 pt-4 flex flex-col min-h-0", children: [_jsxs("div", { className: "flex items-center gap-2 mb-4 justify-center uppercase tracking-widest text-[16px] shrink-0", children: [_jsx("div", { className: "flex items-center justify-center p-1.5 bg-gradient-to-br from-blue-400 to-blue-600 rounded-xl text-white", children: _jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("rect", { width: "8", height: "4", x: "8", y: "2", rx: "1", ry: "1" }), _jsx("path", { d: "M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" }), _jsx("path", { d: "M12 11h4" }), _jsx("path", { d: "M12 16h4" }), _jsx("path", { d: "M8 11h.01" }), _jsx("path", { d: "M8 16h.01" })] }) }), _jsx("span", { className: "font-black bg-gradient-to-r from-blue-700 to-blue-500 bg-clip-text text-transparent", children: "Question List" })] }), _jsx("div", { className: "flex-1 overflow-y-auto custom-scrollbar pr-1", children: _jsx("div", { className: "grid grid-cols-5 gap-2", children: questions.map((q) => {
21
- const isCurrent = q.globalIndex === currentQuestionGlobalIndex;
22
- const isAnswered = q.isAnswered;
23
- let btnStyle = "bg-white text-slate-800 shadow-sm border-transparent";
24
- if (isCurrent) {
25
- btnStyle = "bg-blue-600 text-white border-blue-600 shadow-md";
26
- }
27
- else if (isAnswered) {
28
- btnStyle = "bg-[#4ade80] text-white border-transparent shadow-sm";
29
- }
30
- if (!isCurrent && !isNavDisabled) {
31
- btnStyle += " hover:shadow-md hover:text-blue-600";
32
- }
33
- if (isNavDisabled) {
34
- btnStyle += " opacity-50 cursor-not-allowed";
35
- }
36
- else {
37
- btnStyle += " cursor-pointer";
38
- }
39
- return (_jsx("button", { type: "button", onClick: () => onQuestionClick(q.globalIndex), disabled: isNavDisabled, className: cn("h-[44px] w-full rounded-[10px] flex items-center justify-center font-bold text-[15px] transition-all border", btnStyle), children: q.questionNumber }, q.globalIndex));
40
- }) }) }), _jsx("div", { className: "shrink-0 mt-4 pt-4 border-t border-blue-200/50", children: _jsxs("div", { className: "flex items-center justify-between text-[11px] xl:text-[11.5px] font-bold text-gray-700", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("div", { className: "w-3.5 h-3.5 rounded-full bg-blue-600 shadow-sm" }), _jsx("span", { children: "Current" })] }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("div", { className: "w-3.5 h-3.5 rounded-full bg-green-500 shadow-sm" }), _jsx("span", { children: "Answered" })] }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("div", { className: "w-3.5 h-3.5 rounded-full bg-[#f4f9ff] border border-blue-200 shadow-sm" }), _jsx("span", { children: "Not answered" })] })] }) })] })] }));
41
- }
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import{cn as r}from"../../../shared/lib/utils";import s from"next/image";import l from"./assets/images/phao.png";import a from"./assets/images/sanho.png";import n from"./assets/images/sao.png";import i from"./assets/images/vooc.png";const o=[l,a,n,i];export function CambridgeYleSidebar({parts:l,questions:a,currentQuestionGlobalIndex:n,onPartClick:i,onQuestionClick:d,isNavDisabled:c,className:p}){const m=a[n],h=m?m.partIndex:0;return t("div",{className:r("flex flex-col w-full h-full pb-4",p),children:[t("div",{className:"flex-1 overflow-y-auto custom-scrollbar p-4 lg:p-6 pb-2",children:[t("div",{className:"flex items-center gap-2 mb-4 justify-center uppercase tracking-widest text-[16px]",children:[e("div",{className:"flex items-center justify-center p-1.5 bg-gradient-to-br from-blue-400 to-blue-600 rounded-xl text-white",children:t("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",children:[e("polygon",{points:"12 2 2 7 12 12 22 7 12 2"}),e("polyline",{points:"2 17 12 22 22 17"}),e("polyline",{points:"2 12 12 17 22 12"})]})}),e("span",{className:"font-black bg-gradient-to-r from-blue-700 to-blue-500 bg-clip-text text-transparent",children:"Parts"})]}),e("div",{className:"flex flex-col gap-2.5",children:l.map((a,n)=>{const d=n===h,p=o[n%o.length],m=n>0?l[n-1].category:null,b=a.category&&a.category!==m;return t("div",{className:"flex flex-col",children:[b&&t("div",{className:"flex items-center gap-2 mt-5 mb-3 px-1",children:[e("div",{className:"h-[4px] w-4 rounded-full bg-blue-500"}),e("span",{className:"text-[14px] font-black uppercase tracking-[0.15em] text-blue-800",children:a.category?.replace(/_/g," ")}),e("div",{className:"h-[2px] flex-1 rounded-full bg-blue-100"})]}),t("button",{type:"button",onClick:()=>i(n),disabled:c,className:r("flex items-center justify-between p-2 px-[15px] rounded-[15px] transition-all border font-medium shadow-sm",d?"bg-blue-600 text-white border-blue-600":"bg-white text-slate-800 border-transparent",d||c?"":"hover:border-blue-200",c?"opacity-50 cursor-not-allowed":"cursor-pointer"),children:[t("div",{className:"flex items-center gap-3",children:[e("div",{className:"flex items-center justify-center w-8 h-8 shrink-0",children:e(s,{src:p,alt:`part icon ${n}`,className:"w-[30px] h-auto object-contain"})}),e("span",{className:"font-black text-[15px]",children:a.name||`Part ${a.partNo}`})]}),t("span",{className:r("text-[13px] font-bold tracking-wide",d?"text-blue-100":"text-blue-900/60"),children:[a.answeredCount,"/",a.totalQuestions]})]})]},n)})})]}),e("div",{className:"px-6",children:e("hr",{className:"border-t-2 border-dashed border-blue-100"})}),t("div",{className:"flex-1 p-4 lg:p-6 pt-4 flex flex-col min-h-0",children:[t("div",{className:"flex items-center gap-2 mb-4 justify-center uppercase tracking-widest text-[16px] shrink-0",children:[e("div",{className:"flex items-center justify-center p-1.5 bg-gradient-to-br from-blue-400 to-blue-600 rounded-xl text-white",children:t("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",children:[e("rect",{width:"8",height:"4",x:"8",y:"2",rx:"1",ry:"1"}),e("path",{d:"M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"}),e("path",{d:"M12 11h4"}),e("path",{d:"M12 16h4"}),e("path",{d:"M8 11h.01"}),e("path",{d:"M8 16h.01"})]})}),e("span",{className:"font-black bg-gradient-to-r from-blue-700 to-blue-500 bg-clip-text text-transparent",children:"Question List"})]}),e("div",{className:"flex-1 overflow-y-auto custom-scrollbar pr-1",children:e("div",{className:"grid grid-cols-5 gap-2",children:a.map(t=>{const s=t.globalIndex===n,l=t.isAnswered;let a="bg-white text-slate-800 shadow-sm border-transparent";return s?a="bg-blue-600 text-white border-blue-600 shadow-md":l&&(a="bg-[#4ade80] text-white border-transparent shadow-sm"),s||c||(a+=" hover:shadow-md hover:text-blue-600"),a+=c?" opacity-50 cursor-not-allowed":" cursor-pointer",e("button",{type:"button",onClick:()=>d(t.globalIndex),disabled:c,className:r("h-[44px] w-full rounded-[10px] flex items-center justify-center font-bold text-[15px] transition-all border",a),children:t.questionNumber},t.globalIndex)})})}),e("div",{className:"shrink-0 mt-4 pt-4 border-t border-blue-200/50",children:t("div",{className:"flex items-center justify-between text-[11px] xl:text-[11.5px] font-bold text-gray-700",children:[t("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"w-3.5 h-3.5 rounded-full bg-blue-600 shadow-sm"}),e("span",{children:"Current"})]}),t("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"w-3.5 h-3.5 rounded-full bg-green-500 shadow-sm"}),e("span",{children:"Answered"})]}),t("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"w-3.5 h-3.5 rounded-full bg-[#f4f9ff] border border-blue-200 shadow-sm"}),e("span",{children:"Not answered"})]})]})})]})]})}
@@ -1,25 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import Image from 'next/image';
3
- import summerSkyClockImg from '@/components/themes/summer-sky/assets/images/clock.png';
4
- export function CambridgeYleTimer({ remainingSeconds, totalQuestions, answeredCount, }) {
5
- const minutes = Math.floor(remainingSeconds / 60);
6
- const seconds = remainingSeconds % 60;
7
- const formattedTime = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
8
- // Use the same styles as the Speaking exam timer but relative positioning
9
- // Warning colors can be added if needed based on remainingSeconds,
10
- // but for now we'll match the default blue theme.
11
- let bgColorClass = 'bg-[#001590]';
12
- let shadowClass = 'shadow-[0_4px_20px_rgba(0,0,0,0.25)]';
13
- // Optional warning states (similar to ExamTimer.module.css)
14
- if (remainingSeconds <= 120) {
15
- bgColorClass = 'bg-[rgba(220,38,38,0.85)]'; // Critical
16
- shadowClass = 'shadow-[0_0_24px_rgba(220,38,38,0.5)] animate-pulse';
17
- }
18
- else if (remainingSeconds <= 300) {
19
- bgColorClass = 'bg-[rgba(180,120,0,0.85)]'; // Warning
20
- }
21
- return (_jsxs("div", { className: `flex items-center w-[130px] sm:w-[170px] h-[40px] sm:h-[50px] rounded-[33.5px] backdrop-blur-[8px] transition-all duration-300 ease-in-out border-none ${bgColorClass} ${shadowClass}`, children: [_jsx(Image, { src: summerSkyClockImg, alt: "clock", width: 75, height: 75, className: "w-[50px] h-[50px] sm:w-[75px] sm:h-[75px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none z-10" }), _jsx("span", { className: "flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]", style: {
22
- fontFamily: "'SVN-Volte Rounded', 'Quicksand', sans-serif",
23
- textShadow: "0 2px 4px rgba(0, 0, 0, 0.2)"
24
- }, children: formattedTime })] }));
25
- }
1
+ import{jsx as e,jsxs as t}from"react/jsx-runtime";import s from"next/image";import r from"../../../components/themes/summer-sky/assets/images/clock.png";export function CambridgeYleTimer({remainingSeconds:a,totalQuestions:n,answeredCount:p}){const o=a%60,x=`${Math.floor(a/60).toString().padStart(2,"0")}:${o.toString().padStart(2,"0")}`;let m="bg-[#001590]",i="shadow-[0_4px_20px_rgba(0,0,0,0.25)]";return a<=120?(m="bg-[rgba(220,38,38,0.85)]",i="shadow-[0_0_24px_rgba(220,38,38,0.5)] animate-pulse"):a<=300&&(m="bg-[rgba(180,120,0,0.85)]"),t("div",{className:`flex items-center w-[130px] sm:w-[170px] h-[40px] sm:h-[50px] rounded-[33.5px] backdrop-blur-[8px] transition-all duration-300 ease-in-out border-none ${m} ${i}`,children:[e(s,{src:r,alt:"clock",width:75,height:75,className:"w-[50px] h-[50px] sm:w-[75px] sm:h-[75px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none z-10"}),e("span",{className:"flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]",style:{fontFamily:"'SVN-Volte Rounded', 'Quicksand', sans-serif",textShadow:"0 2px 4px rgba(0, 0, 0, 0.2)"},children:x})]})}
@@ -1,13 +1 @@
1
- // Cambridge YLE Theme Layout & UI components
2
- // Previously known as the "Movers" theme
3
- export { CambridgeYleExamLayout } from './CambridgeYleExamLayout';
4
- export { CambridgeYleHeader } from './CambridgeYleHeader';
5
- export { CambridgeYleNavButton } from './CambridgeYleNavButton';
6
- export { CambridgeYleProgressBar } from './CambridgeYleProgressBar';
7
- export { CambridgeYleTimer } from './CambridgeYleTimer';
8
- export { default as CambridgeYleQuestionCard } from './CambridgeYleQuestionCard';
9
- export { default as CambridgeYleQuestionCardFullWidth } from './CambridgeYleQuestionCardFullWidth';
10
- export { default as CambridgeYlePartBanner } from './CambridgeYlePartBanner';
11
- export { default as CambridgeYleInstructionBanner } from './CambridgeYleInstructionBanner';
12
- export { default as CambridgeYleAudioPlayer } from './CambridgeYleAudioPlayer';
13
- export { default as CambridgeYleExampleText } from './CambridgeYleExampleText';
1
+ export{CambridgeYleExamLayout}from"./CambridgeYleExamLayout";export{CambridgeYleHeader}from"./CambridgeYleHeader";export{CambridgeYleNavButton}from"./CambridgeYleNavButton";export{CambridgeYleProgressBar}from"./CambridgeYleProgressBar";export{CambridgeYleTimer}from"./CambridgeYleTimer";export{default as CambridgeYleQuestionCard}from"./CambridgeYleQuestionCard";export{default as CambridgeYleQuestionCardFullWidth}from"./CambridgeYleQuestionCardFullWidth";export{default as CambridgeYlePartBanner}from"./CambridgeYlePartBanner";export{default as CambridgeYleInstructionBanner}from"./CambridgeYleInstructionBanner";export{default as CambridgeYleAudioPlayer}from"./CambridgeYleAudioPlayer";export{default as CambridgeYleExampleText}from"./CambridgeYleExampleText";
@@ -1,24 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useMemo } from 'react';
4
- import { ResolvedImage } from '../../../components/common/ResolvedImage';
5
- import { cn } from '../../../shared/lib/utils';
6
- import { transformAnswerTheQuestion } from '../../../components/exams/take/exam-taking.utils';
7
- /**
8
- * Branded English Certification renderer for `ANSWER_THE_QUESTION`.
9
- *
10
- * Lists each question with an inline text input (plus optional prefix/suffix and
11
- * suggested answers). Reuses {@link transformAnswerTheQuestion} so the stored
12
- * answer shape (`{ [questionId]: { answer: string } }`) stays compatible with
13
- * the grading store.
14
- */
15
- export function EcAnswerTheQuestion({ part, answers, onAnswerChange, isReviewMode = false, }) {
16
- const { questions, instruction, imageUrl, title, groupContent } = useMemo(() => transformAnswerTheQuestion(part.questions), [part.questions]);
17
- const handleChange = (questionId, value) => {
18
- onAnswerChange(questionId, { answer: value });
19
- };
20
- return (_jsxs("div", { className: "flex flex-col gap-4", children: [instruction && (_jsx("div", { className: "rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]", children: instruction })), imageUrl && (_jsx("div", { className: "flex items-center justify-center", children: _jsx(ResolvedImage, { src: imageUrl, alt: title || 'Group image', className: "max-h-[280px] rounded-lg object-contain shadow-md" }) })), _jsx("div", { className: "flex flex-col gap-3", children: questions.map((q) => {
21
- const stored = answers[q.id]?.answer ?? q.exampleAnswer ?? '';
22
- return (_jsx("div", { id: `question-${q.id}`, className: cn('rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]', q.isExample && 'opacity-90'), children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("span", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white", children: q.questionNumber }), _jsxs("div", { className: "min-w-0 flex-1 space-y-2", children: [q.imageUrl && (_jsx(ResolvedImage, { src: q.imageUrl, alt: `Question ${q.questionNumber}`, className: "max-h-28 w-auto rounded object-contain" })), _jsx("p", { className: "text-sm text-[#0f1730]", children: q.question }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [q.prefixText && (_jsx("span", { className: "text-sm text-[#64748b]", children: q.prefixText })), q.isExample ? (_jsx("span", { className: "rounded-lg border border-[#b9edc8] bg-[#ddf8e7] px-3 py-1.5 text-sm font-semibold text-[#15803d]", children: q.exampleAnswer })) : (_jsx("input", { type: "text", value: stored, disabled: isReviewMode, placeholder: "Nh\u1EADp c\u00E2u tr\u1EA3 l\u1EDDi\u2026", onChange: (e) => handleChange(q.id, e.target.value), className: cn('min-w-[200px] flex-1 rounded-lg border-2 border-[#9cc4f5] bg-white px-3 py-2 text-sm font-medium text-[#0f1730] outline-none transition-all focus:border-[#1167e8]', isReviewMode && 'cursor-not-allowed opacity-70') })), q.suffixText && (_jsx("span", { className: "text-sm text-[#64748b]", children: q.suffixText }))] }), q.suggestedAnswers && q.suggestedAnswers.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-1.5", children: q.suggestedAnswers.map((sa, idx) => (_jsx("span", { className: "rounded-full border border-[#e2ecf8] bg-[#f4f9ff] px-2.5 py-0.5 text-xs text-[#0b57d0]", children: sa }, `${q.id}-sa-${idx}`))) }))] })] }) }, q.id));
23
- }) })] }));
24
- }
1
+ "use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import{useMemo as t}from"react";import{ResolvedImage as r}from"../../../components/common/ResolvedImage";import{cn as a}from"../../../shared/lib/utils";import{transformAnswerTheQuestion as n}from"../../../components/exams/take/exam-taking.utils";export function EcAnswerTheQuestion({part:i,answers:l,onAnswerChange:d,isReviewMode:o=!1}){const{questions:c,instruction:m,imageUrl:x,title:p,groupContent:f}=t(()=>n(i.questions),[i.questions]);return s("div",{className:"flex flex-col gap-4",children:[m&&e("div",{className:"rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]",children:m}),x&&e("div",{className:"flex items-center justify-center",children:e(r,{src:x,alt:p||"Group image",className:"max-h-[280px] rounded-lg object-contain shadow-md"})}),e("div",{className:"flex flex-col gap-3",children:c.map(t=>{const n=l[t.id]?.answer??t.exampleAnswer??"";return e("div",{id:`question-${t.id}`,className:a("rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",t.isExample&&"opacity-90"),children:s("div",{className:"flex items-start gap-3",children:[e("span",{className:"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white",children:t.questionNumber}),s("div",{className:"min-w-0 flex-1 space-y-2",children:[t.imageUrl&&e(r,{src:t.imageUrl,alt:`Question ${t.questionNumber}`,className:"max-h-28 w-auto rounded object-contain"}),e("p",{className:"text-sm text-[#0f1730]",children:t.question}),s("div",{className:"flex flex-wrap items-center gap-2",children:[t.prefixText&&e("span",{className:"text-sm text-[#64748b]",children:t.prefixText}),t.isExample?e("span",{className:"rounded-lg border border-[#b9edc8] bg-[#ddf8e7] px-3 py-1.5 text-sm font-semibold text-[#15803d]",children:t.exampleAnswer}):e("input",{type:"text",value:n,disabled:o,placeholder:"Nhập câu trả lời…",onChange:e=>{return s=t.id,r=e.target.value,void d(s,{answer:r});var s,r},className:a("min-w-[200px] flex-1 rounded-lg border-2 border-[#9cc4f5] bg-white px-3 py-2 text-sm font-medium text-[#0f1730] outline-none transition-all focus:border-[#1167e8]",o&&"cursor-not-allowed opacity-70")}),t.suffixText&&e("span",{className:"text-sm text-[#64748b]",children:t.suffixText})]}),t.suggestedAnswers&&t.suggestedAnswers.length>0&&e("div",{className:"flex flex-wrap gap-1.5",children:t.suggestedAnswers.map((s,r)=>e("span",{className:"rounded-full border border-[#e2ecf8] bg-[#f4f9ff] px-2.5 py-0.5 text-xs text-[#0b57d0]",children:s},`${t.id}-sa-${r}`))})]})]})},t.id)})})]})}
@@ -1,88 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useMemo } from 'react';
4
- import { ResolvedImage } from '../../../components/common/ResolvedImage';
5
- import { cn } from '../../../shared/lib/utils';
6
- import { transformMatchByWritingAnswer } from '../../../components/exams/take/exam-taking.utils';
7
- /** Letters A, B, C, … used to label the answer options. */
8
- const OPTION_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
9
- const BADGE_TONE_CLASS = {
10
- empty: 'bg-[#eef3fb] text-[#94a3b8] border border-[#dbe5f2]',
11
- filled: 'bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-white border border-transparent',
12
- correct: 'bg-[#16a34a] text-white border border-transparent',
13
- wrong: 'bg-[#ef4444] text-white border border-transparent',
14
- };
15
- /** Big rounded badge that mirrors the currently selected letter. */
16
- function LetterBadge({ letter, tone }) {
17
- return (_jsx("span", { className: cn('flex h-9 w-9 shrink-0 items-center justify-center rounded-xl text-base font-bold transition-colors', BADGE_TONE_CLASS[tone]), children: letter || '—' }));
18
- }
19
- /**
20
- * Branded English Certification renderer for `MATCH_BY_WRITING_ANSWER`.
21
- *
22
- * Shows a lettered answer bank (A–H) at the top, then each question with a
23
- * dropdown to pick its matching letter plus a big letter badge mirroring the
24
- * current selection. Selected letters are dimmed in the bank (take mode) so the
25
- * student can track which options are still free. Reuses
26
- * {@link transformMatchByWritingAnswer} so the stored answer shape
27
- * (`{ [questionId]: { answer: string } }`) stays compatible with the grading
28
- * store.
29
- */
30
- export function EcMatchByWritingAnswer({ part, answers, onAnswerChange, isReviewMode = false, }) {
31
- const { questions, options, instruction, groupImageUrl } = useMemo(() => transformMatchByWritingAnswer(part.questions), [part.questions]);
32
- /** Map each option's stored answer value → its display letter (A, B, C…). */
33
- const answerToLetter = useMemo(() => {
34
- const map = new Map();
35
- options.forEach((opt, idx) => {
36
- map.set(opt.answer, OPTION_LETTERS[idx] ?? String(idx + 1));
37
- });
38
- return map;
39
- }, [options]);
40
- /** Resolve the stored value for a question (selection or example fallback). */
41
- const getStored = (q) => answers[q.id]?.answer ?? q.exampleAnswer ?? '';
42
- /** Letters currently assigned across all questions — drives bank dimming. */
43
- const usedLetters = useMemo(() => {
44
- const set = new Set();
45
- questions.forEach((q) => {
46
- const value = getStored(q);
47
- const letter = answerToLetter.get(value);
48
- if (letter)
49
- set.add(letter);
50
- });
51
- return set;
52
- // eslint-disable-next-line react-hooks/exhaustive-deps
53
- }, [questions, answers, answerToLetter]);
54
- const handleSelect = (questionId, value) => {
55
- onAnswerChange(questionId, { answer: value });
56
- };
57
- return (_jsxs("div", { className: "flex flex-col gap-4", children: [instruction && (_jsx("div", { className: "rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]", children: instruction })), groupImageUrl && (_jsx("div", { className: "flex items-center justify-center", children: _jsx(ResolvedImage, { src: groupImageUrl, alt: "Group image", className: "max-h-[280px] rounded-lg object-contain shadow-md" }) })), options.length > 0 && (_jsxs("div", { className: "rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]", children: [_jsx("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-[#64748b]", children: "ANSWER OPTIONS" }), _jsx("div", { className: "mt-2 grid grid-cols-1 gap-2 sm:grid-cols-2", children: options.map((opt, idx) => {
58
- const letter = OPTION_LETTERS[idx] ?? String(idx + 1);
59
- // Dim used options only in take mode so review stays comparable.
60
- const isUsed = !isReviewMode && usedLetters.has(letter);
61
- return (_jsxs("div", { className: cn('flex items-start gap-2.5 rounded-xl border border-[#e2ecf8] bg-[#f4f9ff] px-3 py-2 transition-opacity', isUsed && 'opacity-50'), children: [_jsxs("span", { className: "relative flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white", children: [letter, isUsed && (_jsx("span", { className: "absolute -right-1 -top-1 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-[#16a34a] text-[8px] text-white", children: "\u2713" }))] }), _jsxs("div", { className: "min-w-0 text-sm text-[#0f1730]", children: [opt.imageUrl && (_jsx(ResolvedImage, { src: opt.imageUrl, alt: opt.answer, className: "mb-1 max-h-24 w-auto rounded object-contain" })), _jsx("span", { className: "font-medium", children: opt.content || opt.answer })] })] }, `${opt.answer}-${idx}`));
62
- }) })] })), _jsx("div", { className: "flex flex-col gap-3", children: questions.map((q) => {
63
- const stored = getStored(q);
64
- const selectedLetter = answerToLetter.get(stored) ?? '';
65
- // Review correctness is only known for example rows (the
66
- // transformer exposes `exampleAnswer`); other rows stay neutral.
67
- const reviewCorrect = isReviewMode && q.isExample
68
- ? stored === (q.exampleAnswer ?? '')
69
- : undefined;
70
- const rowTint = reviewCorrect === true
71
- ? 'border-[#bbf7d0] bg-[#f0fdf4]'
72
- : reviewCorrect === false
73
- ? 'border-[#fecaca] bg-[#fef2f2]'
74
- : 'border-[#d9e4f2] bg-white/90';
75
- const badgeTone = reviewCorrect === true
76
- ? 'correct'
77
- : reviewCorrect === false
78
- ? 'wrong'
79
- : selectedLetter
80
- ? 'filled'
81
- : 'empty';
82
- return (_jsxs("div", { id: `question-${q.id}`, className: cn('flex items-center gap-3 rounded-xl border p-3 shadow-sm transition-colors', rowTint, q.isExample && 'opacity-90'), children: [_jsx("span", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white", children: q.questionNumber }), _jsxs("div", { className: "min-w-0 flex-1", children: [q.imageUrl && (_jsx(ResolvedImage, { src: q.imageUrl, alt: `Question ${q.questionNumber}`, className: "mb-2 max-h-28 w-auto rounded object-contain" })), _jsx("p", { className: "text-sm text-[#0f1730]", children: q.question })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsx(LetterBadge, { letter: selectedLetter, tone: badgeTone }), q.isExample ? (_jsx("span", { className: "rounded-lg border border-[#b9edc8] bg-[#ddf8e7] px-3 py-1.5 text-sm font-semibold text-[#15803d]", children: q.exampleAnswer })) : (_jsxs("select", { value: stored, disabled: isReviewMode, onChange: (e) => handleSelect(q.id, e.target.value), className: cn('h-9 min-w-[150px] rounded-lg border-2 border-[#9cc4f5] bg-white px-3 text-sm font-semibold text-[#0f1730] outline-none transition-all focus:border-[#1167e8]', isReviewMode && 'cursor-not-allowed opacity-70'), children: [_jsx("option", { value: "", children: "\u2014" }), options.map((opt, idx) => {
83
- const letter = OPTION_LETTERS[idx] ?? String(idx + 1);
84
- const label = opt.content || opt.answer;
85
- return (_jsx("option", { value: opt.answer, children: label ? `${letter} — ${label}` : letter }, `${q.id}-${idx}`));
86
- })] }))] })] }, q.id));
87
- }) })] }));
88
- }
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useMemo as r}from"react";import{ResolvedImage as n}from"../../../components/common/ResolvedImage";import{cn as s}from"../../../shared/lib/utils";import{transformMatchByWritingAnswer as a}from"../../../components/exams/take/exam-taking.utils";const o="ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""),i={empty:"bg-[#eef3fb] text-[#94a3b8] border border-[#dbe5f2]",filled:"bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-white border border-transparent",correct:"bg-[#16a34a] text-white border border-transparent",wrong:"bg-[#ef4444] text-white border border-transparent"};function d({letter:t,tone:r}){return e("span",{className:s("flex h-9 w-9 shrink-0 items-center justify-center rounded-xl text-base font-bold transition-colors",i[r]),children:t||"—"})}export function EcMatchByWritingAnswer({part:i,answers:l,onAnswerChange:c,isReviewMode:m=!1}){const{questions:f,options:b,instruction:p,groupImageUrl:x}=r(()=>a(i.questions),[i.questions]),u=r(()=>{const e=new Map;return b.forEach((t,r)=>{e.set(t.answer,o[r]??String(r+1))}),e},[b]),g=e=>l[e.id]?.answer??e.exampleAnswer??"",h=r(()=>{const e=new Set;return f.forEach(t=>{const r=g(t),n=u.get(r);n&&e.add(n)}),e},[f,l,u]);return t("div",{className:"flex flex-col gap-4",children:[p&&e("div",{className:"rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]",children:p}),x&&e("div",{className:"flex items-center justify-center",children:e(n,{src:x,alt:"Group image",className:"max-h-[280px] rounded-lg object-contain shadow-md"})}),b.length>0&&t("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:[e("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-[#64748b]",children:"ANSWER OPTIONS"}),e("div",{className:"mt-2 grid grid-cols-1 gap-2 sm:grid-cols-2",children:b.map((r,a)=>{const i=o[a]??String(a+1),d=!m&&h.has(i);return t("div",{className:s("flex items-start gap-2.5 rounded-xl border border-[#e2ecf8] bg-[#f4f9ff] px-3 py-2 transition-opacity",d&&"opacity-50"),children:[t("span",{className:"relative flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white",children:[i,d&&e("span",{className:"absolute -right-1 -top-1 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-[#16a34a] text-[8px] text-white",children:"✓"})]}),t("div",{className:"min-w-0 text-sm text-[#0f1730]",children:[r.imageUrl&&e(n,{src:r.imageUrl,alt:r.answer,className:"mb-1 max-h-24 w-auto rounded object-contain"}),e("span",{className:"font-medium",children:r.content||r.answer})]})]},`${r.answer}-${a}`)})})]}),e("div",{className:"flex flex-col gap-3",children:f.map(r=>{const a=g(r),i=u.get(a)??"",l=m&&r.isExample?a===(r.exampleAnswer??""):void 0,f=!0===l?"border-[#bbf7d0] bg-[#f0fdf4]":!1===l?"border-[#fecaca] bg-[#fef2f2]":"border-[#d9e4f2] bg-white/90",p=!0===l?"correct":!1===l?"wrong":i?"filled":"empty";return t("div",{id:`question-${r.id}`,className:s("flex items-center gap-3 rounded-xl border p-3 shadow-sm transition-colors",f,r.isExample&&"opacity-90"),children:[e("span",{className:"flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-gradient-to-b from-[#1f7cff] to-[#0b57d0] text-xs font-bold text-white",children:r.questionNumber}),t("div",{className:"min-w-0 flex-1",children:[r.imageUrl&&e(n,{src:r.imageUrl,alt:`Question ${r.questionNumber}`,className:"mb-2 max-h-28 w-auto rounded object-contain"}),e("p",{className:"text-sm text-[#0f1730]",children:r.question})]}),t("div",{className:"flex shrink-0 items-center gap-2",children:[e(d,{letter:i,tone:p}),r.isExample?e("span",{className:"rounded-lg border border-[#b9edc8] bg-[#ddf8e7] px-3 py-1.5 text-sm font-semibold text-[#15803d]",children:r.exampleAnswer}):t("select",{value:a,disabled:m,onChange:e=>{return t=r.id,n=e.target.value,void c(t,{answer:n});var t,n},className:s("h-9 min-w-[150px] rounded-lg border-2 border-[#9cc4f5] bg-white px-3 text-sm font-semibold text-[#0f1730] outline-none transition-all focus:border-[#1167e8]",m&&"cursor-not-allowed opacity-70"),children:[e("option",{value:"",children:"—"}),b.map((t,n)=>{const s=o[n]??String(n+1),a=t.content||t.answer;return e("option",{value:t.answer,children:a?`${s} — ${a}`:s},`${r.id}-${n}`)})]})]})]},r.id)})})]})}
@@ -1,55 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useMemo } from 'react';
4
- import { ResolvedImage } from '../../../components/common/ResolvedImage';
5
- import { cn } from '../../../shared/lib/utils';
6
- import { transformWordFillParagraph } from '../../../components/exams/take/exam-taking.utils';
7
- /**
8
- * Branded English Certification renderer for `WORD_FILL_PARAGRAPH`.
9
- *
10
- * Shows an optional word bank, then the paragraph with inline blanks. Supports
11
- * `WITH_WORD_BANK` (dropdown selecting a bank word) and `DEFAULT` (free text
12
- * input). Reuses {@link transformWordFillParagraph} so the stored answer shape
13
- * (`{ [questionId]: string[] }` indexed by blank) stays compatible with the
14
- * grading store.
15
- */
16
- export function EcWordFillParagraph({ part, answers, onAnswerChange, isReviewMode = false, }) {
17
- const data = useMemo(() => transformWordFillParagraph(part.questions), [part.questions]);
18
- const { questionId, paragraph, title, imageUrl, wordBank, viewMode, instruction } = data;
19
- const currentAnswers = answers[questionId] || [];
20
- const segments = useMemo(() => paragraph.split(/(\{\d+\})/), [paragraph]);
21
- const useWordBank = viewMode === 'WITH_WORD_BANK';
22
- const usedWords = new Set(currentAnswers.filter(Boolean));
23
- const setBlank = (blankIndex, value) => {
24
- if (isReviewMode)
25
- return;
26
- const next = [...currentAnswers];
27
- next[blankIndex] = value;
28
- onAnswerChange(questionId, next);
29
- };
30
- return (_jsxs("div", { className: "flex flex-col gap-4", children: [instruction && (_jsx("div", { className: "rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]", children: instruction })), imageUrl && (_jsx("div", { className: "flex items-center justify-center", children: _jsx(ResolvedImage, { src: imageUrl, alt: title || 'Illustration', className: "max-h-[280px] rounded-lg object-contain shadow-md" }) })), useWordBank && wordBank.length > 0 && (_jsxs("div", { className: "rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]", children: [_jsx("span", { className: "text-[10px] font-semibold uppercase tracking-wider text-[#64748b]", children: "Word bank" }), _jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: wordBank.map((item, idx) => {
31
- const isUsed = usedWords.has(item.word);
32
- return (_jsx("span", { className: cn('rounded-full border px-3 py-1 text-sm font-semibold transition-all', item.isExample
33
- ? 'border-[#b9edc8] bg-[#ddf8e7] text-[#15803d]'
34
- : isUsed
35
- ? 'border-[#d9e4f2] bg-[#f4f9ff] text-[#94a3b8] line-through'
36
- : 'border-[#9cc4f5] bg-white text-[#0b57d0]'), children: item.word }, `${item.word}-${idx}`));
37
- }) })] })), _jsx("div", { className: "rounded-2xl border border-[#d9e4f2] bg-white/90 p-5 text-base leading-loose text-[#0f1730] shadow-[0_14px_35px_rgba(13,71,161,0.10)]", children: segments.map((segment, idx) => {
38
- const blankMatch = segment.match(/^\{(\d+)\}$/);
39
- if (!blankMatch) {
40
- return _jsx("span", { children: segment }, idx);
41
- }
42
- const blankIndex = parseInt(blankMatch[1], 10);
43
- const studentAnswer = currentAnswers[blankIndex] || '';
44
- if (useWordBank) {
45
- return (_jsxs("span", { className: "mx-1 inline-flex items-baseline gap-1 align-baseline", children: [_jsxs("span", { className: "text-[11px] font-bold text-[#1f7cff]", children: ["(", blankIndex + 1, ")"] }), _jsxs("select", { value: studentAnswer, disabled: isReviewMode, onChange: (e) => setBlank(blankIndex, e.target.value), className: cn('rounded-lg border-2 px-2 py-1 text-sm font-semibold outline-none transition-all', studentAnswer
46
- ? 'border-[#1167e8] text-[#0b57d0]'
47
- : 'border-[#9cc4f5] text-[#64748b]', isReviewMode && 'cursor-not-allowed opacity-70'), children: [_jsx("option", { value: "", children: "\u2014\u2014\u2014" }), wordBank
48
- .filter((w) => !w.isExample)
49
- .map((w, wi) => (_jsx("option", { value: w.word, children: w.word }, `${blankIndex}-${wi}`)))] })] }, idx));
50
- }
51
- return (_jsxs("span", { className: "mx-1 inline-flex items-baseline gap-1 align-baseline", children: [_jsxs("span", { className: "text-[11px] font-bold text-[#1f7cff]", children: ["(", blankIndex + 1, ")"] }), _jsx("input", { type: "text", value: studentAnswer, disabled: isReviewMode, placeholder: "\u00B7\u00B7\u00B7", onChange: (e) => setBlank(blankIndex, e.target.value), style: { width: `${Math.max(4, studentAnswer.length + 1)}ch` }, className: cn('inline-block min-w-[4ch] max-w-[16ch] border-b-2 bg-transparent px-1 text-center text-sm font-semibold outline-none transition-colors', studentAnswer
52
- ? 'border-[#1167e8] text-[#0b57d0]'
53
- : 'border-[#9cc4f5] text-[#64748b]', isReviewMode && 'cursor-not-allowed opacity-70') })] }, idx));
54
- }) })] }));
55
- }
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useMemo as r}from"react";import{ResolvedImage as a}from"../../../components/common/ResolvedImage";import{cn as n}from"../../../shared/lib/utils";import{transformWordFillParagraph as o}from"../../../components/exams/take/exam-taking.utils";export function EcWordFillParagraph({part:l,answers:s,onAnswerChange:i,isReviewMode:d=!1}){const c=r(()=>o(l.questions),[l.questions]),{questionId:m,paragraph:p,title:x,imageUrl:b,wordBank:f,viewMode:h,instruction:u}=c,g=s[m]||[],w=r(()=>p.split(/(\{\d+\})/),[p]),N="WITH_WORD_BANK"===h,v=new Set(g.filter(Boolean)),y=(e,t)=>{if(d)return;const r=[...g];r[e]=t,i(m,r)};return t("div",{className:"flex flex-col gap-4",children:[u&&e("div",{className:"rounded-xl border border-[#d9e4f2] bg-[#e9f3ff] px-4 py-2.5 text-sm font-semibold uppercase tracking-wide text-[#0b57d0]",children:u}),b&&e("div",{className:"flex items-center justify-center",children:e(a,{src:b,alt:x||"Illustration",className:"max-h-[280px] rounded-lg object-contain shadow-md"})}),N&&f.length>0&&t("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-4 shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:[e("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-[#64748b]",children:"Word bank"}),e("div",{className:"mt-2 flex flex-wrap gap-2",children:f.map((t,r)=>{const a=v.has(t.word);return e("span",{className:n("rounded-full border px-3 py-1 text-sm font-semibold transition-all",t.isExample?"border-[#b9edc8] bg-[#ddf8e7] text-[#15803d]":a?"border-[#d9e4f2] bg-[#f4f9ff] text-[#94a3b8] line-through":"border-[#9cc4f5] bg-white text-[#0b57d0]"),children:t.word},`${t.word}-${r}`)})})]}),e("div",{className:"rounded-2xl border border-[#d9e4f2] bg-white/90 p-5 text-base leading-loose text-[#0f1730] shadow-[0_14px_35px_rgba(13,71,161,0.10)]",children:w.map((r,a)=>{const o=r.match(/^\{(\d+)\}$/);if(!o)return e("span",{children:r},a);const l=parseInt(o[1],10),s=g[l]||"";return t("span",N?{className:"mx-1 inline-flex items-baseline gap-1 align-baseline",children:[t("span",{className:"text-[11px] font-bold text-[#1f7cff]",children:["(",l+1,")"]}),t("select",{value:s,disabled:d,onChange:e=>y(l,e.target.value),className:n("rounded-lg border-2 px-2 py-1 text-sm font-semibold outline-none transition-all",s?"border-[#1167e8] text-[#0b57d0]":"border-[#9cc4f5] text-[#64748b]",d&&"cursor-not-allowed opacity-70"),children:[e("option",{value:"",children:"———"}),f.filter(e=>!e.isExample).map((t,r)=>e("option",{value:t.word,children:t.word},`${l}-${r}`))]})]}:{className:"mx-1 inline-flex items-baseline gap-1 align-baseline",children:[t("span",{className:"text-[11px] font-bold text-[#1f7cff]",children:["(",l+1,")"]}),e("input",{type:"text",value:s,disabled:d,placeholder:"···",onChange:e=>y(l,e.target.value),style:{width:`${Math.max(4,s.length+1)}ch`},className:n("inline-block min-w-[4ch] max-w-[16ch] border-b-2 bg-transparent px-1 text-center text-sm font-semibold outline-none transition-colors",s?"border-[#1167e8] text-[#0b57d0]":"border-[#9cc4f5] text-[#64748b]",d&&"cursor-not-allowed opacity-70")})]},a)})})]})}