@tinyweb_dev/oe-exam-sdk 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (485) hide show
  1. package/dist/api/exam-create.js +1 -179
  2. package/dist/api/exam-create.types.js +1 -1
  3. package/dist/api/exam-questions.js +1 -98
  4. package/dist/api/exam-questions.types.js +1 -1
  5. package/dist/api/exam-taking.js +1 -73
  6. package/dist/api/exam-taking.types.js +1 -1
  7. package/dist/api/index.js +1 -6
  8. package/dist/api/result-review.js +1 -50
  9. package/dist/api/result-review.types.js +1 -1
  10. package/dist/components/CueCardEditor.js +1 -58
  11. package/dist/components/common/ResolvedImage.js +1 -15
  12. package/dist/components/exams/CreateExamInfoForm.js +1 -35
  13. package/dist/components/exams/CreateExamPageContainer.js +1 -103
  14. package/dist/components/exams/ExamCreator.js +1 -89
  15. package/dist/components/exams/ExamPartTabs.js +1 -40
  16. package/dist/components/exams/ExamQuestionGrid.js +1 -18
  17. package/dist/components/exams/ExamQuestionsPageContainer.js +1 -90
  18. package/dist/components/exams/PartAudioUploader.js +1 -9
  19. package/dist/components/exams/TemplateSelector.js +1 -66
  20. package/dist/components/exams/api.js +1 -3
  21. package/dist/components/exams/create-exam.validation.js +1 -18
  22. package/dist/components/exams/exam-template.utils.js +1 -18
  23. package/dist/components/exams/index.js +1 -10
  24. package/dist/components/exams/take/ExamTakingPageContainer.js +1 -153
  25. package/dist/components/exams/take/GenericQuestionRenderer.js +1 -14
  26. package/dist/components/exams/take/exam-taking.utils.js +1 -88
  27. package/dist/components/exams/take/hooks/useSpeakingRecorder.js +1 -24
  28. package/dist/components/exams/take/index.js +1 -2
  29. package/dist/components/exams/take/types.js +1 -1
  30. package/dist/components/index.js +1 -42
  31. package/dist/components/questions/_shared/config/question-types.config.js +1 -333
  32. package/dist/components/questions/_shared/constants/color-palette.js +1 -21
  33. package/dist/components/questions/_shared/hooks/useAnswerGroupQuestionGroup.js +1 -105
  34. package/dist/components/questions/_shared/hooks/useBasicQuestionGroup.js +1 -222
  35. package/dist/components/questions/_shared/hooks/useCompareImagesGroup.js +1 -140
  36. package/dist/components/questions/_shared/hooks/useImageQuestionGroup.js +1 -123
  37. package/dist/components/questions/_shared/hooks/useInfoExchangeGroup.js +1 -50
  38. package/dist/components/questions/_shared/hooks/useQuestionFormState.js +1 -54
  39. package/dist/components/questions/_shared/hooks/useQuestionInitialization.js +1 -123
  40. package/dist/components/questions/_shared/hooks/useQuestionListGroup.js +1 -121
  41. package/dist/components/questions/_shared/hooks/useQuestionOnChange.js +1 -70
  42. package/dist/components/questions/_shared/hooks/useSceneQuestionGroup.js +1 -194
  43. package/dist/components/questions/_shared/index.js +1 -7
  44. package/dist/components/questions/_shared/types/answer-the-question.type.js +1 -1
  45. package/dist/components/questions/_shared/types/arrange-letters-into-words.type.js +1 -1
  46. package/dist/components/questions/_shared/types/choose-correct-adjective.type.js +1 -3
  47. package/dist/components/questions/_shared/types/color-region.config.js +1 -1
  48. package/dist/components/questions/_shared/types/fill-in-blank.type.js +1 -1
  49. package/dist/components/questions/_shared/types/fill-missing-words-in-grid.type.js +1 -1
  50. package/dist/components/questions/_shared/types/gn-speaking-interview.type.js +1 -1
  51. package/dist/components/questions/_shared/types/index.js +1 -12
  52. package/dist/components/questions/_shared/types/label-the-picture.type.js +1 -1
  53. package/dist/components/questions/_shared/types/listen-and-choose-from-answer-group.type.js +1 -1
  54. package/dist/components/questions/_shared/types/listen-and-choose-objects-in-scene.type.js +1 -1
  55. package/dist/components/questions/_shared/types/listen-and-drag-objects-into-scene.type.js +1 -1
  56. package/dist/components/questions/_shared/types/listen-and-speak-answer.type.js +1 -1
  57. package/dist/components/questions/_shared/types/listen-and-speak-compare-images.type.js +1 -1
  58. package/dist/components/questions/_shared/types/listen-and-speak-image-group.type.js +1 -1
  59. package/dist/components/questions/_shared/types/listen-and-speak-info-exchange.type.js +1 -1
  60. package/dist/components/questions/_shared/types/listen-and-speak-odd-one-out.type.js +1 -3
  61. package/dist/components/questions/_shared/types/listen-and-speak-question-list.type.js +1 -1
  62. package/dist/components/questions/_shared/types/listen-and-speak-with-story-images.type.js +1 -3
  63. package/dist/components/questions/_shared/types/listen-and-tick-answer.type.js +1 -1
  64. package/dist/components/questions/_shared/types/listening-drawline.type.js +1 -1
  65. package/dist/components/questions/_shared/types/look-and-choose-answer.type.js +1 -1
  66. package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.js +1 -1
  67. package/dist/components/questions/_shared/types/match-by-writing-answer.type.js +1 -1
  68. package/dist/components/questions/_shared/types/multiple-choice.type.js +1 -1
  69. package/dist/components/questions/_shared/types/question-group.type.js +1 -11
  70. package/dist/components/questions/_shared/types/read-and-color-objects.type.js +1 -1
  71. package/dist/components/questions/_shared/types/read-displayed-content.type.js +1 -1
  72. package/dist/components/questions/_shared/types/read-passage-and-answer-questions.type.js +1 -1
  73. package/dist/components/questions/_shared/types/speaking-describe-image.type.js +1 -1
  74. package/dist/components/questions/_shared/types/spontaneous-qa.type.js +1 -1
  75. package/dist/components/questions/_shared/types/word-fill-paragraph-with-options.type.js +1 -1
  76. package/dist/components/questions/_shared/types/word-fill-paragraph.type.js +1 -1
  77. package/dist/components/questions/_shared/types/word-fill-structured-form.type.js +1 -1
  78. package/dist/components/questions/_shared/types/word-ordering.type.js +1 -1
  79. package/dist/components/questions/_shared/types/write-a-short-letter.type.js +1 -1
  80. package/dist/components/questions/_shared/types/write-correct-verb-form.type.js +1 -3
  81. package/dist/components/questions/_shared/types/write-sentences.type.js +1 -1
  82. package/dist/components/questions/_shared/types/write-short-paragraph.type.js +1 -1
  83. package/dist/components/questions/_shared/utils/answer-builder.js +1 -79
  84. package/dist/components/questions/_shared/utils/createColorRegionRegistration.js +1 -39
  85. package/dist/components/questions/_shared/utils/id-generator.js +1 -3
  86. package/dist/components/questions/_shared/utils/question-validation.js +1 -21
  87. package/dist/components/questions/components/ColorNode.js +1 -85
  88. package/dist/components/questions/components/ColorRegionClient.js +1 -545
  89. package/dist/components/questions/components/ColorRegionCreator.js +1 -420
  90. package/dist/components/questions/components/ColorRegionNode.js +1 -59
  91. package/dist/components/questions/components/CreatorGuide.js +1 -103
  92. package/dist/components/questions/components/NameNode.js +1 -26
  93. package/dist/components/questions/components/QuestionBankOption.js +1 -46
  94. package/dist/components/questions/components/QuestionBasicInfoForm.js +1 -9
  95. package/dist/components/questions/components/QuestionCommonFields.js +1 -33
  96. package/dist/components/questions/components/QuestionSearchDropdown.js +1 -258
  97. package/dist/components/questions/components/QuestionTypeSelector.js +1 -32
  98. package/dist/components/questions/components/QuestionTypeSpecificForms.js +1 -6
  99. package/dist/components/questions/components/RegionNode.js +1 -94
  100. package/dist/components/questions/components/index.js +1 -14
  101. package/dist/components/questions/creator/QuestionCreator.js +1 -90
  102. package/dist/components/questions/creator/QuestionGroupCreator.js +1 -119
  103. package/dist/components/questions/creator/dedicated-component-router.js +1 -79
  104. package/dist/components/questions/creator/index.js +1 -3
  105. package/dist/components/questions/creator/question-type-registry.js +1 -80
  106. package/dist/components/questions/groups/ArticlesGroupCard.js +1 -121
  107. package/dist/components/questions/groups/BasicQuestionGroupCard.js +1 -50
  108. package/dist/components/questions/groups/DocumentGroupCard.js +1 -114
  109. package/dist/components/questions/groups/MatchAnswerGroupCard.js +1 -25
  110. package/dist/components/questions/index.js +1 -10
  111. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +1 -37
  112. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionCreator.js +1 -351
  113. package/dist/components/questions/types/answer-the-question/register.js +1 -67
  114. package/dist/components/questions/types/answer-the-question/transform.js +1 -36
  115. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +1 -141
  116. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsCreator.js +1 -118
  117. package/dist/components/questions/types/arrange-letters-into-words/index.js +1 -2
  118. package/dist/components/questions/types/arrange-letters-into-words/register.js +1 -4
  119. package/dist/components/questions/types/arrange-letters-into-words/transform.js +1 -24
  120. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +1 -64
  121. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js +1 -169
  122. package/dist/components/questions/types/choose-correct-adjective/index.js +1 -2
  123. package/dist/components/questions/types/choose-correct-adjective/register.js +1 -55
  124. package/dist/components/questions/types/choose-correct-adjective/transform.js +1 -16
  125. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +1 -131
  126. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +1 -581
  127. package/dist/components/questions/types/choose-the-correct-answer/index.js +1 -2
  128. package/dist/components/questions/types/choose-the-correct-answer/register.js +1 -101
  129. package/dist/components/questions/types/choose-the-correct-answer/transform.js +1 -43
  130. package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +1 -275
  131. package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +1 -448
  132. package/dist/components/questions/types/fill-in-blank/index.js +1 -2
  133. package/dist/components/questions/types/fill-in-blank/register.js +1 -138
  134. package/dist/components/questions/types/fill-in-blank/transform.js +1 -59
  135. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +1 -117
  136. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridCreator.js +1 -671
  137. package/dist/components/questions/types/fill-missing-words-in-grid/index.js +1 -2
  138. package/dist/components/questions/types/fill-missing-words-in-grid/register.js +1 -37
  139. package/dist/components/questions/types/fill-missing-words-in-grid/transform.js +1 -15
  140. package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.js +1 -262
  141. package/dist/components/questions/types/gn-speaking-interview/register.js +1 -121
  142. package/dist/components/questions/types/gn-speaking-interview/transform.js +1 -48
  143. package/dist/components/questions/types/image-object-matching/ImageObjectMatchingClient.js +1 -16
  144. package/dist/components/questions/types/image-object-matching/ImageObjectMatchingCreator.js +1 -27
  145. package/dist/components/questions/types/image-object-matching/index.js +1 -2
  146. package/dist/components/questions/types/image-object-matching/register.js +1 -3
  147. package/dist/components/questions/types/image-object-matching/transform.js +1 -2
  148. package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +1 -102
  149. package/dist/components/questions/types/label-the-picture/LabelThePictureCreator.js +1 -344
  150. package/dist/components/questions/types/label-the-picture/index.js +1 -2
  151. package/dist/components/questions/types/label-the-picture/register.js +1 -54
  152. package/dist/components/questions/types/label-the-picture/transform.js +1 -28
  153. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +1 -78
  154. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupCreator.js +1 -232
  155. package/dist/components/questions/types/listen-and-choose-from-answer-group/index.js +1 -2
  156. package/dist/components/questions/types/listen-and-choose-from-answer-group/register.js +1 -82
  157. package/dist/components/questions/types/listen-and-choose-from-answer-group/transform.js +1 -27
  158. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneClient.js +1 -70
  159. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneCreator.js +1 -386
  160. package/dist/components/questions/types/listen-and-choose-objects-in-scene/index.js +1 -2
  161. package/dist/components/questions/types/listen-and-choose-objects-in-scene/register.js +1 -100
  162. package/dist/components/questions/types/listen-and-choose-objects-in-scene/transform.js +1 -33
  163. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneClient.js +1 -106
  164. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneCreator.js +1 -457
  165. package/dist/components/questions/types/listen-and-drag-objects-into-scene/index.js +1 -2
  166. package/dist/components/questions/types/listen-and-drag-objects-into-scene/register.js +1 -110
  167. package/dist/components/questions/types/listen-and-drag-objects-into-scene/transform.js +1 -35
  168. package/dist/components/questions/types/listen-and-speak-answer/ArrowIndicator.js +1 -8
  169. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +1 -22
  170. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerCreator.js +1 -291
  171. package/dist/components/questions/types/listen-and-speak-answer/index.js +1 -2
  172. package/dist/components/questions/types/listen-and-speak-answer/register.js +1 -84
  173. package/dist/components/questions/types/listen-and-speak-answer/transform.js +1 -27
  174. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +1 -32
  175. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesCreator.js +1 -295
  176. package/dist/components/questions/types/listen-and-speak-compare-images/register.js +1 -79
  177. package/dist/components/questions/types/listen-and-speak-compare-images/transform.js +1 -27
  178. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +1 -34
  179. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupCreator.js +1 -285
  180. package/dist/components/questions/types/listen-and-speak-image-group/register.js +1 -81
  181. package/dist/components/questions/types/listen-and-speak-image-group/transform.js +1 -26
  182. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +1 -38
  183. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeCreator.js +1 -385
  184. package/dist/components/questions/types/listen-and-speak-info-exchange/register.js +1 -87
  185. package/dist/components/questions/types/listen-and-speak-info-exchange/transform.js +1 -32
  186. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +1 -26
  187. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutCreator.js +1 -247
  188. package/dist/components/questions/types/listen-and-speak-odd-one-out/register.js +1 -59
  189. package/dist/components/questions/types/listen-and-speak-odd-one-out/transform.js +1 -18
  190. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +1 -26
  191. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListCreator.js +1 -256
  192. package/dist/components/questions/types/listen-and-speak-question-list/register.js +1 -81
  193. package/dist/components/questions/types/listen-and-speak-question-list/transform.js +1 -26
  194. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +1 -26
  195. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesCreator.js +1 -230
  196. package/dist/components/questions/types/listen-and-speak-with-story-images/register.js +1 -56
  197. package/dist/components/questions/types/listen-and-speak-with-story-images/transform.js +1 -16
  198. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.js +1 -72
  199. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.js +1 -230
  200. package/dist/components/questions/types/look-picture-choose-correct-answer/index.js +1 -1
  201. package/dist/components/questions/types/look-picture-choose-correct-answer/register.js +1 -66
  202. package/dist/components/questions/types/look-picture-choose-correct-answer/transform.js +1 -42
  203. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.js +1 -96
  204. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.js +1 -238
  205. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.js +1 -2
  206. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.js +1 -76
  207. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.js +1 -19
  208. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.js +1 -134
  209. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.js +1 -617
  210. package/dist/components/questions/types/look-picture-fill-word-hint/index.js +1 -2
  211. package/dist/components/questions/types/look-picture-fill-word-hint/register.js +1 -82
  212. package/dist/components/questions/types/look-picture-fill-word-hint/transform.js +1 -29
  213. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +1 -38
  214. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerCreator.js +1 -359
  215. package/dist/components/questions/types/match-by-writing-answer/index.js +1 -3
  216. package/dist/components/questions/types/match-by-writing-answer/register.js +1 -58
  217. package/dist/components/questions/types/match-by-writing-answer/transform.js +1 -61
  218. package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsClient.js +1 -16
  219. package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsCreator.js +1 -23
  220. package/dist/components/questions/types/read-and-color-objects/index.js +1 -2
  221. package/dist/components/questions/types/read-and-color-objects/register.js +1 -3
  222. package/dist/components/questions/types/read-and-color-objects/transform.js +1 -36
  223. package/dist/components/questions/types/read-displayed-content/ReadDisplayedContentCreator.js +1 -125
  224. package/dist/components/questions/types/read-displayed-content/register.js +1 -64
  225. package/dist/components/questions/types/read-displayed-content/transform.js +1 -12
  226. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +1 -64
  227. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsCreator.js +1 -511
  228. package/dist/components/questions/types/read-passage-and-answer-questions/index.js +1 -2
  229. package/dist/components/questions/types/read-passage-and-answer-questions/register.js +1 -58
  230. package/dist/components/questions/types/read-passage-and-answer-questions/transform.js +1 -28
  231. package/dist/components/questions/types/speaking-conversation/SpeakingConversationCreator.js +1 -373
  232. package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +1 -41
  233. package/dist/components/questions/types/speaking-conversation/register.js +1 -110
  234. package/dist/components/questions/types/speaking-conversation/transform.js +1 -34
  235. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +1 -74
  236. package/dist/components/questions/types/speaking-cue-card/register.js +1 -52
  237. package/dist/components/questions/types/speaking-cue-card/transform.js +1 -12
  238. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +1 -10
  239. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageCreator.js +1 -161
  240. package/dist/components/questions/types/speaking-describe-image/index.js +1 -2
  241. package/dist/components/questions/types/speaking-describe-image/register.js +1 -69
  242. package/dist/components/questions/types/speaking-describe-image/transform.js +1 -16
  243. package/dist/components/questions/types/spontaneous-qa/SpontaneousQACreator.js +1 -234
  244. package/dist/components/questions/types/spontaneous-qa/register.js +1 -93
  245. package/dist/components/questions/types/spontaneous-qa/transform.js +1 -34
  246. package/dist/components/questions/types/true-false/TrueFalseClient.js +1 -75
  247. package/dist/components/questions/types/true-false/TrueFalseCreator.js +1 -244
  248. package/dist/components/questions/types/true-false/index.js +1 -2
  249. package/dist/components/questions/types/true-false/register.js +1 -77
  250. package/dist/components/questions/types/true-false/transform.js +1 -32
  251. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +1 -233
  252. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphCreator.js +1 -631
  253. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphWrapper.js +1 -28
  254. package/dist/components/questions/types/word-fill-paragraph/index.js +1 -2
  255. package/dist/components/questions/types/word-fill-paragraph/register.js +1 -136
  256. package/dist/components/questions/types/word-fill-paragraph/transform.js +1 -56
  257. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -138
  258. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +1 -261
  259. package/dist/components/questions/types/word-fill-structured-form/index.js +1 -2
  260. package/dist/components/questions/types/word-fill-structured-form/register.js +1 -67
  261. package/dist/components/questions/types/word-fill-structured-form/transform.js +1 -40
  262. package/dist/components/questions/types/word-ordering/WordOrderingClient.js +1 -84
  263. package/dist/components/questions/types/word-ordering/WordOrderingCreator.js +1 -192
  264. package/dist/components/questions/types/word-ordering/index.js +1 -2
  265. package/dist/components/questions/types/word-ordering/register.js +1 -46
  266. package/dist/components/questions/types/word-ordering/transform.js +1 -24
  267. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +1 -98
  268. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +1 -320
  269. package/dist/components/questions/types/write-a-short-letter/index.js +1 -2
  270. package/dist/components/questions/types/write-a-short-letter/register.js +1 -68
  271. package/dist/components/questions/types/write-a-short-letter/transform.js +1 -25
  272. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +1 -61
  273. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js +1 -196
  274. package/dist/components/questions/types/write-correct-verb-form/index.js +1 -2
  275. package/dist/components/questions/types/write-correct-verb-form/register.js +1 -62
  276. package/dist/components/questions/types/write-correct-verb-form/transform.js +1 -17
  277. package/dist/components/questions/types/write-sentences/WriteSentencesClient.js +1 -22
  278. package/dist/components/questions/types/write-sentences/WriteSentencesCreator.js +1 -174
  279. package/dist/components/questions/types/write-sentences/index.js +1 -2
  280. package/dist/components/questions/types/write-sentences/register.js +1 -58
  281. package/dist/components/questions/types/write-sentences/transform.js +1 -28
  282. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphClient.js +1 -96
  283. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphCreator.js +1 -161
  284. package/dist/components/questions/types/write-short-paragraph/index.js +1 -2
  285. package/dist/components/questions/types/write-short-paragraph/register.js +1 -4
  286. package/dist/components/questions/types/write-short-paragraph/transform.js +1 -21
  287. package/dist/components/questions/viewer/QuestionGroupViewer.js +1 -36
  288. package/dist/components/questions/viewer/QuestionViewer.js +1 -446
  289. package/dist/components/questions/viewer/index.js +1 -2
  290. package/dist/components/results/ResultReviewPageContainer.js +1 -98
  291. package/dist/components/results/ReviewQuestionRenderer.js +1 -72
  292. package/dist/components/results/index.js +1 -2
  293. package/dist/components/results/result-review.utils.js +1 -6
  294. package/dist/components/results/review-data.js +1 -150
  295. package/dist/components/results/review-renderer.utils.js +1 -97
  296. package/dist/components/results/review-types.js +1 -1
  297. package/dist/components/themes/cambridge-yle/CambridgeYleAudioPlayer.js +1 -138
  298. package/dist/components/themes/cambridge-yle/CambridgeYleBottomNav.js +1 -12
  299. package/dist/components/themes/cambridge-yle/CambridgeYleExamLayout.js +1 -18
  300. package/dist/components/themes/cambridge-yle/CambridgeYleExampleText.js +1 -11
  301. package/dist/components/themes/cambridge-yle/CambridgeYleHeader.js +1 -11
  302. package/dist/components/themes/cambridge-yle/CambridgeYleInstructionBanner.js +1 -9
  303. package/dist/components/themes/cambridge-yle/CambridgeYleNavButton.js +1 -13
  304. package/dist/components/themes/cambridge-yle/CambridgeYlePartBanner.js +1 -8
  305. package/dist/components/themes/cambridge-yle/CambridgeYleProgressBar.js +1 -6
  306. package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCard.js +1 -5
  307. package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCardFullWidth.js +1 -9
  308. package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.js +1 -41
  309. package/dist/components/themes/cambridge-yle/CambridgeYleTimer.js +1 -25
  310. package/dist/components/themes/cambridge-yle/index.js +1 -13
  311. package/dist/components/themes/english-certification/EcAnswerTheQuestion.js +1 -24
  312. package/dist/components/themes/english-certification/EcMatchByWritingAnswer.js +1 -88
  313. package/dist/components/themes/english-certification/EcWordFillParagraph.js +1 -55
  314. package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -156
  315. package/dist/components/themes/english-certification/EcWritingTask.js +1 -34
  316. package/dist/components/themes/english-certification/EnglishCertificationAudioPlayer.js +1 -114
  317. package/dist/components/themes/english-certification/EnglishCertificationBrand.js +1 -11
  318. package/dist/components/themes/english-certification/EnglishCertificationExamLayout.js +1 -21
  319. package/dist/components/themes/english-certification/EnglishCertificationFlagButton.js +1 -15
  320. package/dist/components/themes/english-certification/EnglishCertificationFooterBar.js +1 -19
  321. package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.js +1 -148
  322. package/dist/components/themes/english-certification/EnglishCertificationHeader.js +1 -31
  323. package/dist/components/themes/english-certification/EnglishCertificationNavigationPanel.js +1 -71
  324. package/dist/components/themes/english-certification/EnglishCertificationOptionSelector.js +1 -33
  325. package/dist/components/themes/english-certification/EnglishCertificationPassagePanel.js +1 -16
  326. package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.js +1 -22
  327. package/dist/components/themes/english-certification/EnglishCertificationQuestionItem.js +1 -37
  328. package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -72
  329. package/dist/components/themes/english-certification/EnglishCertificationReadingSection.js +1 -90
  330. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestion.js +1 -18
  331. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js +1 -29
  332. package/dist/components/themes/english-certification/english-certification-theme.js +1 -58
  333. package/dist/components/themes/english-certification/grouped-question-utils.js +1 -218
  334. package/dist/components/themes/english-certification/index.js +1 -21
  335. package/dist/components/themes/index.js +1 -6
  336. package/dist/components/themes/summer-sky/SummerSkyAudioPlayer.js +1 -170
  337. package/dist/components/themes/summer-sky/SummerSkyLayout.js +1 -221
  338. package/dist/components/themes/summer-sky/SummerSkySubmitModal.js +1 -18
  339. package/dist/components/themes/summer-sky/SummerSkyWaitingRoom.js +1 -194
  340. package/dist/components/themes/types.js +1 -1
  341. package/dist/components/ui/alert-dialog.js +1 -26
  342. package/dist/components/ui/alert.js +1 -22
  343. package/dist/components/ui/avatar.js +1 -12
  344. package/dist/components/ui/badge.js +1 -38
  345. package/dist/components/ui/button.js +1 -35
  346. package/dist/components/ui/calendar.js +1 -76
  347. package/dist/components/ui/card.js +1 -16
  348. package/dist/components/ui/carousel.js +1 -91
  349. package/dist/components/ui/checkbox.js +1 -9
  350. package/dist/components/ui/collapsible.js +1 -13
  351. package/dist/components/ui/command.js +1 -34
  352. package/dist/components/ui/confirm-dialog.js +1 -49
  353. package/dist/components/ui/dialog.js +1 -23
  354. package/dist/components/ui/drawer.js +1 -35
  355. package/dist/components/ui/dropdown-menu.js +1 -33
  356. package/dist/components/ui/file-upload.js +1 -155
  357. package/dist/components/ui/form.js +1 -62
  358. package/dist/components/ui/hover-card.js +1 -10
  359. package/dist/components/ui/image-preview.js +1 -29
  360. package/dist/components/ui/input.js +1 -8
  361. package/dist/components/ui/label.js +1 -9
  362. package/dist/components/ui/language-switcher.js +1 -15
  363. package/dist/components/ui/multi-select.js +1 -90
  364. package/dist/components/ui/points-input.js +1 -33
  365. package/dist/components/ui/popover.js +1 -26
  366. package/dist/components/ui/progress.js +1 -16
  367. package/dist/components/ui/radio-group.js +1 -12
  368. package/dist/components/ui/scroll-area.js +1 -11
  369. package/dist/components/ui/select.js +1 -38
  370. package/dist/components/ui/separator.js +1 -8
  371. package/dist/components/ui/sheet.js +1 -40
  372. package/dist/components/ui/single-select.js +1 -76
  373. package/dist/components/ui/skeleton.js +1 -6
  374. package/dist/components/ui/switch.js +1 -8
  375. package/dist/components/ui/table.js +1 -20
  376. package/dist/components/ui/tabs.js +1 -17
  377. package/dist/components/ui/textarea.js +1 -8
  378. package/dist/components/ui/tooltip.js +1 -11
  379. package/dist/index.js +1 -19
  380. package/dist/mcp/config.js +1 -32
  381. package/dist/mcp/http-client.js +1 -48
  382. package/dist/mcp/index.js +1 -29
  383. package/dist/mcp/tools/_helpers.js +1 -25
  384. package/dist/mcp/tools/exams.js +1 -439
  385. package/dist/mcp/tools/index.js +1 -6
  386. package/dist/mcp/tools/results.js +1 -19
  387. package/dist/shared/constants/ApiConstant.js +1 -276
  388. package/dist/shared/constants/QueryKeyConstant.js +1 -112
  389. package/dist/shared/constants/exam-level.enum.js +1 -41
  390. package/dist/shared/constants/landings/placement-test.constants.js +1 -431
  391. package/dist/shared/constants/question-skills.js +1 -267
  392. package/dist/shared/constants/routes.js +1 -81
  393. package/dist/shared/index.js +1 -7
  394. package/dist/shared/lib/hooks/index.js +1 -10
  395. package/dist/shared/lib/hooks/useAlertDialog.js +1 -57
  396. package/dist/shared/lib/hooks/useAudioPlayCounter.js +1 -30
  397. package/dist/shared/lib/hooks/useAudioPreview.js +1 -81
  398. package/dist/shared/lib/hooks/useAudioUpload.js +1 -24
  399. package/dist/shared/lib/hooks/useConfirmDialog.js +1 -89
  400. package/dist/shared/lib/hooks/useDebouncedCallback.js +1 -32
  401. package/dist/shared/lib/hooks/useDelayedAutoPlay.js +1 -12
  402. package/dist/shared/lib/hooks/useFileUpload.js +1 -24
  403. package/dist/shared/lib/hooks/useImageUrl.js +1 -5
  404. package/dist/shared/lib/hooks/usePresignedFileUrl.js +1 -10
  405. package/dist/shared/lib/hooks/useReactHookForm.js +1 -31
  406. package/dist/shared/lib/hooks/useToast.js +1 -62
  407. package/dist/shared/lib/i18n/index.js +1 -54
  408. package/dist/shared/lib/i18n/messages/en/admin.js +1 -2104
  409. package/dist/shared/lib/i18n/messages/en/auth.js +1 -86
  410. package/dist/shared/lib/i18n/messages/en/common.js +1 -140
  411. package/dist/shared/lib/i18n/messages/en/file-upload.js +1 -18
  412. package/dist/shared/lib/i18n/messages/en/student.js +1 -133
  413. package/dist/shared/lib/i18n/messages/en/terms.js +1 -37
  414. package/dist/shared/lib/i18n/messages/en.js +1 -15
  415. package/dist/shared/lib/i18n/messages/vi/admin.js +1 -2104
  416. package/dist/shared/lib/i18n/messages/vi/auth.js +1 -86
  417. package/dist/shared/lib/i18n/messages/vi/common.js +1 -140
  418. package/dist/shared/lib/i18n/messages/vi/file-upload.js +1 -18
  419. package/dist/shared/lib/i18n/messages/vi/student.js +1 -133
  420. package/dist/shared/lib/i18n/messages/vi/terms.js +1 -37
  421. package/dist/shared/lib/i18n/messages/vi.js +1 -15
  422. package/dist/shared/lib/i18n/types.js +1 -1
  423. package/dist/shared/lib/stores/examQuestionStore.js +1 -212
  424. package/dist/shared/lib/stores/localeStore.js +1 -10
  425. package/dist/shared/lib/utils/public-page.js +1 -44
  426. package/dist/shared/lib/utils/question-transform-types.js +1 -1
  427. package/dist/shared/lib/utils/question-transform.js +1 -174
  428. package/dist/shared/lib/utils.js +1 -168
  429. package/dist/shared/lib/validation/choose-correct-answer.validation.js +1 -111
  430. package/dist/shared/lib/validation/label-the-picture.validation.js +1 -19
  431. package/dist/shared/lib/validation/listen-and-choose-from-answer-group.validation.js +1 -46
  432. package/dist/shared/lib/validation/listen-and-choose-objects-in-scene.validation.js +1 -21
  433. package/dist/shared/lib/validation/listen-and-drag-objects-into-scene.validation.js +1 -34
  434. package/dist/shared/lib/validation/listen-and-speak-answer.validation.js +1 -40
  435. package/dist/shared/lib/validation/listen-and-speak-compare-images.validation.js +1 -45
  436. package/dist/shared/lib/validation/listen-and-speak-image-group.validation.js +1 -19
  437. package/dist/shared/lib/validation/listen-and-speak-info-exchange.validation.js +1 -39
  438. package/dist/shared/lib/validation/listen-and-speak-odd-one-out.validation.js +1 -32
  439. package/dist/shared/lib/validation/listen-and-speak-question-list.validation.js +1 -19
  440. package/dist/shared/lib/validation/listen-and-speak-with-story-images.validation.js +1 -28
  441. package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.js +1 -12
  442. package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.js +1 -47
  443. package/dist/shared/lib/validation/read-and-color-objects.validation.js +1 -29
  444. package/dist/shared/lib/validation/read-displayed-content.validation.js +1 -28
  445. package/dist/shared/lib/validation/speaking-conversation.validation.js +1 -75
  446. package/dist/shared/lib/validation/speaking-describe-image.validation.js +1 -31
  447. package/dist/shared/lib/validation/spontaneous-qa.validation.js +1 -48
  448. package/dist/shared/lib/validation/word-fill-paragraph-default.validation.js +1 -38
  449. package/dist/shared/lib/validation/word-fill-paragraph-with-options.validation.js +1 -39
  450. package/dist/shared/lib/validation/word-fill-paragraph.validation.js +1 -43
  451. package/dist/shared/lib/validation/word-ordering.validation.js +1 -33
  452. package/dist/shared/types/branch.types.js +1 -6
  453. package/dist/shared/types/common.types.js +1 -50
  454. package/dist/shared/types/entities/exam-schedule.types.js +1 -5
  455. package/dist/shared/types/entities/exam.types.js +1 -1
  456. package/dist/shared/types/entities/question.types.js +1 -4
  457. package/dist/shared/types/entities/result.types.js +1 -4
  458. package/dist/shared/types/entities/user.types.js +1 -4
  459. package/dist/shared/types/exam-taking.types.js +1 -2
  460. package/dist/shared/types/history.types.js +1 -34
  461. package/dist/shared/types/index.js +1 -1
  462. package/dist/shared/types/questions/choose-correct-adjective.js +1 -4
  463. package/dist/shared/types/questions/choose-the-correct-answer.js +1 -9
  464. package/dist/shared/types/questions/fill-missing-words-in-grid.js +1 -11
  465. package/dist/shared/types/questions/index.js +1 -40
  466. package/dist/shared/types/questions/listen-and-speak-answer.js +1 -1
  467. package/dist/shared/types/questions/listen-and-speak-compare-images.js +1 -1
  468. package/dist/shared/types/questions/listen-and-speak-image-group.js +1 -1
  469. package/dist/shared/types/questions/listen-and-speak-info-exchange.js +1 -3
  470. package/dist/shared/types/questions/listen-and-speak-odd-one-out.js +1 -3
  471. package/dist/shared/types/questions/listen-and-speak-question-list.js +1 -1
  472. package/dist/shared/types/questions/listen-and-speak-with-story-images.js +1 -3
  473. package/dist/shared/types/questions/look-picture-choose-correct-answer.js +1 -5
  474. package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.js +1 -9
  475. package/dist/shared/types/questions/look-picture-fill-word-hint.js +1 -7
  476. package/dist/shared/types/questions/read-displayed-content.js +1 -1
  477. package/dist/shared/types/questions/speaking-conversation.js +1 -7
  478. package/dist/shared/types/questions/speaking-describe-image.js +1 -1
  479. package/dist/shared/types/questions/spontaneous-qa.js +1 -1
  480. package/dist/shared/types/questions/write-correct-verb-form.js +1 -12
  481. package/dist/shared/types/role.types.js +1 -1
  482. package/dist/shared/types/structure-management.js +1 -28
  483. package/dist/shared/types/student.types.js +1 -54
  484. package/dist/shared/types/teacher-dashboard-rooms.js +1 -2
  485. package/package.json +4 -2
@@ -1,153 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useEffect, useMemo, useState } from 'react';
4
- import { ArrowLeft, ArrowRight, Loader2, Send } from 'lucide-react';
5
- import { Button } from '../../../components/ui/button';
6
- import { CambridgeYleExamLayout, EnglishCertificationExamLayout, SummerSkyLayout } from '../../../components/themes';
7
- import { useToast } from '../../../shared/lib/hooks/useToast';
8
- import { GenericQuestionRenderer } from './GenericQuestionRenderer';
9
- import { groupQuestions, unwrap, unwrapAttempt } from './exam-taking.utils';
10
- export function ExamTakingPageContainer({ examId, api, exitPath = '/student/exams', onNavigate, onSubmitted }) {
11
- const { error: errorToast, success } = useToast();
12
- const [attempt, setAttempt] = useState(null);
13
- const [parts, setParts] = useState([]);
14
- const [questionsResult, setQuestionsResult] = useState(null);
15
- const [partIndex, setPartIndex] = useState(0);
16
- const [answers, setAnswers] = useState({});
17
- const [isLoading, setIsLoading] = useState(true);
18
- const [isSubmitting, setIsSubmitting] = useState(false);
19
- useEffect(() => {
20
- let ignore = false;
21
- setIsLoading(true);
22
- loadAttempt(api, examId)
23
- .then(async (loadedAttempt) => {
24
- const questions = unwrap(await api.getQuestions(loadedAttempt.id));
25
- if (ignore)
26
- return;
27
- setAttempt(loadedAttempt);
28
- setQuestionsResult(questions);
29
- setParts(groupQuestions(questions));
30
- })
31
- .catch((err) => errorToast({ message: 'Không tải được bài thi', description: err instanceof Error ? err.message : undefined }))
32
- .finally(() => { if (!ignore)
33
- setIsLoading(false); });
34
- return () => { ignore = true; };
35
- }, [api, examId, errorToast]);
36
- const currentPart = parts[partIndex];
37
- const flatQuestions = useMemo(() => parts.flatMap((part) => part.questions), [parts]);
38
- const currentQuestionIndex = useMemo(() => flatQuestions.findIndex((question) => currentPart?.questions[0]?.id === question.id), [currentPart?.questions, flatQuestions]);
39
- const answeredCount = useMemo(() => Object.values(answers).filter((value) => value !== '' && value !== null && value !== undefined).length, [answers]);
40
- const totalQuestions = flatQuestions.length;
41
- const theme = normalizeTheme(questionsResult?.examTemplate?.theme);
42
- const examName = questionsResult?.examTemplate?.title ?? 'Làm bài thi';
43
- const remainingSeconds = getRemainingSeconds(attempt);
44
- const navigate = (href) => {
45
- if (onNavigate)
46
- onNavigate(href);
47
- else if (typeof window !== 'undefined')
48
- window.location.href = href;
49
- };
50
- const handleAnswerChange = async (questionId, answer) => {
51
- setAnswers((prev) => ({ ...prev, [questionId]: answer }));
52
- if (attempt && api.saveAnswers)
53
- await api.saveAnswers({ attemptId: attempt.id, answers: [{ questionId, answer }] });
54
- };
55
- const handleSubmit = async () => {
56
- if (!attempt)
57
- return;
58
- setIsSubmitting(true);
59
- try {
60
- await api.submitAttempt(attempt.id);
61
- success({ message: 'Đã nộp bài' });
62
- onSubmitted?.(attempt.id);
63
- }
64
- catch (err) {
65
- errorToast({ message: 'Không nộp được bài', description: err instanceof Error ? err.message : undefined });
66
- }
67
- finally {
68
- setIsSubmitting(false);
69
- }
70
- };
71
- if (isLoading)
72
- return _jsx(Loading, {});
73
- if (!attempt || !currentPart)
74
- return _jsx(Empty, { onExit: () => navigate(exitPath) });
75
- const content = _jsx(QuestionList, { part: currentPart, answers: answers, onAnswerChange: handleAnswerChange });
76
- const goPrev = () => setPartIndex((prev) => Math.max(0, prev - 1));
77
- const goNext = () => setPartIndex((prev) => Math.min(parts.length - 1, prev + 1));
78
- const isFirstPart = partIndex === 0;
79
- const isLastPart = partIndex >= parts.length - 1;
80
- if (theme === 'ENGLISH_CERTIFICATION') {
81
- return (_jsx(EnglishCertificationExamLayout, { headerProps: { examName, remainingSeconds, totalQuestions, answeredCount, isSubmitting, onSubmit: handleSubmit, onClose: () => navigate(exitPath), lastSavedAt: null, isSaving: false, partLabel: currentPart.name, questionRange: getQuestionRange(currentPart) }, navigationProps: { parts: toStoreParts(parts), questions: toStudentQuestions(flatQuestions), answers, flaggedQuestions: new Set(), currentIndex: Math.max(0, currentQuestionIndex), onQuestionClick: (index) => setPartIndex(findPartIndex(parts, index)), onPartClick: setPartIndex }, footerProps: { onPrevious: goPrev, onNext: goNext, onClear: () => undefined, onToggleMark: () => undefined, isPreviousDisabled: isFirstPart, isNextDisabled: isLastPart, isMarked: false }, children: content }));
82
- }
83
- if (theme === 'CAMBRIDGE_YLE') {
84
- return (_jsx(CambridgeYleExamLayout, { onPrevious: goPrev, onNext: goNext, onClose: () => navigate(exitPath), isFirstQuestion: isFirstPart, isLastQuestion: isLastPart, headerProps: { examName, examType: 'Exam', totalQuestions, answeredCount, remainingSeconds, isSubmitting, onSubmit: handleSubmit }, sidebarProps: toCambridgeSidebar(parts, answers, Math.max(0, currentQuestionIndex), setPartIndex), children: content }));
85
- }
86
- if (theme === 'SUMMER_SKY') {
87
- return (_jsx(SummerSkyLayout, { onExit: () => navigate(exitPath), partName: currentPart.name, instruction: currentPart.instructions ?? '', onPrev: goPrev, onNext: goNext, canGoPrev: !isFirstPart, canGoNext: !isLastPart, audioUrl: currentPart.audioUrl ?? '', questionNumber: partIndex + 1, recorder: null, children: content }));
88
- }
89
- return _jsx(DefaultLayout, { title: examName, answeredCount: answeredCount, totalQuestions: totalQuestions, onExit: () => navigate(exitPath), onPrev: goPrev, onNext: goNext, isFirst: isFirstPart, isLast: isLastPart, currentPart: currentPart, onSubmit: handleSubmit, isSubmitting: isSubmitting, children: content });
90
- }
91
- async function loadAttempt(api, examId) {
92
- const activeAttempt = unwrap(await api.getActiveAttempt(examId));
93
- if (activeAttempt)
94
- return activeAttempt;
95
- return unwrapAttempt(unwrap(await api.startAttempt(examId)));
96
- }
97
- function QuestionList({ part, answers, onAnswerChange }) {
98
- return _jsx("div", { className: "space-y-4", children: part.questions.map((question) => _jsx(GenericQuestionRenderer, { question: question, value: answers[question.id], onChange: onAnswerChange }, question.id)) });
99
- }
100
- function DefaultLayout({ title, answeredCount, totalQuestions, onExit, onPrev, onNext, isFirst, isLast, currentPart, onSubmit, isSubmitting, children }) {
101
- return (_jsxs("div", { className: "min-h-screen bg-slate-50", children: [_jsx("header", { className: "sticky top-0 z-10 border-b bg-white px-4 py-3 shadow-sm", children: _jsxs("div", { className: "mx-auto flex max-w-5xl items-center justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h1", { className: "font-semibold text-gray-900", children: title }), _jsxs("p", { className: "text-sm text-gray-500", children: ["\u0110\u00E3 tr\u1EA3 l\u1EDDi ", answeredCount, "/", totalQuestions] })] }), _jsx(Button, { variant: "outline", onClick: onExit, children: "Tho\u00E1t" })] }) }), _jsxs("main", { className: "mx-auto max-w-5xl space-y-4 p-4", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg bg-white p-4 shadow-sm", children: [_jsxs(Button, { variant: "outline", disabled: isFirst, onClick: onPrev, children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), "Ph\u1EA7n tr\u01B0\u1EDBc"] }), _jsx("div", { className: "text-center", children: _jsx("h2", { className: "font-medium", children: currentPart.name }) }), _jsxs(Button, { variant: "outline", disabled: isLast, onClick: onNext, children: ["Ph\u1EA7n sau", _jsx(ArrowRight, { className: "ml-2 h-4 w-4" })] })] }), children, _jsx("div", { className: "flex justify-end", children: _jsxs(Button, { onClick: onSubmit, disabled: isSubmitting, className: "bg-blue-600 hover:bg-blue-700", children: [isSubmitting ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(Send, { className: "mr-2 h-4 w-4" }), "N\u1ED9p b\u00E0i"] }) })] })] }));
102
- }
103
- function normalizeTheme(theme) {
104
- if (theme === 'ENGLISH_CERTIFICATION')
105
- return theme;
106
- if (theme === 'CAMBRIDGE_YLE')
107
- return theme;
108
- if (theme === 'SUMMER_SKY')
109
- return theme;
110
- return 'DEFAULT';
111
- }
112
- function getRemainingSeconds(attempt) {
113
- if (!attempt)
114
- return 0;
115
- const end = new Date(attempt.startedAt).getTime() + attempt.durationMinutes * 60000;
116
- return Math.max(0, Math.floor((end - Date.now()) / 1000));
117
- }
118
- function getQuestionRange(part) {
119
- const numbers = part.questions.map((question) => question.question_number).filter((value) => Number.isFinite(value));
120
- if (numbers.length === 0)
121
- return '';
122
- return `${Math.min(...numbers)}–${Math.max(...numbers)}`;
123
- }
124
- function toStoreParts(parts) {
125
- let index = 0;
126
- return parts.map((part) => {
127
- const startIndex = index;
128
- index += part.questions.length;
129
- return { id: part.id, name: part.name, category: part.template?.category, startIndex, endIndex: index - 1, questionCount: part.questions.length, audioUrl: part.audioUrl, isGroup: part.isGroup };
130
- });
131
- }
132
- function toStudentQuestions(questions) {
133
- return questions.map((question) => ({ id: question.id, question_type: question.question_type, content: question.content ?? {}, is_example: Boolean(question.is_example), total_points: String(question.total_points ?? 0), part_id: question.part_id ?? '', part_no: question.part_no ?? 0, question_number: question.question_number }));
134
- }
135
- function findPartIndex(parts, questionIndex) {
136
- let cursor = 0;
137
- for (let index = 0; index < parts.length; index += 1) {
138
- cursor += parts[index].questions.length;
139
- if (questionIndex < cursor)
140
- return index;
141
- }
142
- return 0;
143
- }
144
- function toCambridgeSidebar(parts, answers, currentQuestionGlobalIndex, onPartClick) {
145
- const questions = parts.flatMap((part, partIndex) => part.questions.map((question, index) => ({ globalIndex: parts.slice(0, partIndex).reduce((sum, item) => sum + item.questions.length, 0) + index, partIndex, questionNumber: question.question_number, isAnswered: answers[question.id] !== undefined && answers[question.id] !== '' })));
146
- return { parts: parts.map((part, partIndex) => ({ partIndex, partNo: part.partNo ?? partIndex + 1, name: part.name, category: part.template?.category, totalQuestions: part.questions.length, answeredCount: part.questions.filter((question) => answers[question.id] !== undefined && answers[question.id] !== '').length })), questions, currentQuestionGlobalIndex, onPartClick, onQuestionClick: (index) => onPartClick(findPartIndex(parts, index)) };
147
- }
148
- function Loading() {
149
- return _jsx("div", { className: "flex h-screen items-center justify-center", children: _jsx(Loader2, { className: "h-8 w-8 animate-spin text-blue-600" }) });
150
- }
151
- function Empty({ onExit }) {
152
- return _jsxs("div", { className: "flex h-screen flex-col items-center justify-center gap-4", children: [_jsx("p", { children: "Kh\u00F4ng c\u00F3 c\u00E2u h\u1ECFi." }), _jsx(Button, { onClick: onExit, children: "Quay l\u1EA1i" })] });
153
- }
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useEffect as n,useMemo as i,useState as s}from"react";import{ArrowLeft as a,ArrowRight as r,Loader2 as o,Send as l}from"lucide-react";import{Button as u}from"../../../components/ui/button";import{CambridgeYleExamLayout as c,EnglishCertificationExamLayout as m,SummerSkyLayout as d}from"../../../components/themes";import{useToast as h}from"../../../shared/lib/hooks/useToast";import{GenericQuestionRenderer as p}from"./GenericQuestionRenderer";import{groupQuestions as x,unwrap as g,unwrapAttempt as f}from"./exam-taking.utils";export function ExamTakingPageContainer({examId:t,api:a,exitPath:r="/student/exams",onNavigate:o,onSubmitted:l}){const{error:u,success:p}=h(),[S,E]=s(null),[P,_]=s([]),[M,A]=s(null),[k,Q]=s(0),[T,G]=s({}),[L,j]=s(!0),[R,D]=s(!1);n(()=>{let e=!1;return j(!0),async function(e,t){const n=g(await e.getActiveAttempt(t));return n||f(g(await e.startAttempt(t)))}(a,t).then(async t=>{const n=g(await a.getQuestions(t.id));e||(E(t),A(n),_(x(n)))}).catch(e=>u({message:"Không tải được bài thi",description:e instanceof Error?e.message:void 0})).finally(()=>{e||j(!1)}),()=>{e=!0}},[a,t,u]);const F=P[k],U=i(()=>P.flatMap(e=>e.questions),[P]),K=i(()=>U.findIndex(e=>F?.questions[0]?.id===e.id),[F?.questions,U]),Y=i(()=>Object.values(T).filter(e=>""!==e&&null!=e).length,[T]),B=U.length,O=function(e){return"ENGLISH_CERTIFICATION"===e||"CAMBRIDGE_YLE"===e||"SUMMER_SKY"===e?e:"DEFAULT"}(M?.examTemplate?.theme),H=M?.examTemplate?.title??"Làm bài thi",$=function(e){if(!e)return 0;const t=new Date(e.startedAt).getTime()+6e4*e.durationMinutes;return Math.max(0,Math.floor((t-Date.now())/1e3))}(S),z=e=>{o?o(e):"undefined"!=typeof window&&(window.location.href=e)},J=async()=>{if(S){D(!0);try{await a.submitAttempt(S.id),p({message:"Đã nộp bài"}),l?.(S.id)}catch(e){u({message:"Không nộp được bài",description:e instanceof Error?e.message:void 0})}finally{D(!1)}}};if(L)return e(q,{});if(!S||!F)return e(I,{onExit:()=>z(r)});const V=e(b,{part:F,answers:T,onAnswerChange:async(e,t)=>{G(n=>({...n,[e]:t})),S&&a.saveAnswers&&await a.saveAnswers({attemptId:S.id,answers:[{questionId:e,answer:t}]})}}),W=()=>Q(e=>Math.max(0,e-1)),X=()=>Q(e=>Math.min(P.length-1,e+1)),Z=0===k,ee=k>=P.length-1;return"ENGLISH_CERTIFICATION"===O?e(m,{headerProps:{examName:H,remainingSeconds:$,totalQuestions:B,answeredCount:Y,isSubmitting:R,onSubmit:J,onClose:()=>z(r),lastSavedAt:null,isSaving:!1,partLabel:F.name,questionRange:N(F)},navigationProps:{parts:v(P),questions:(te=U,te.map(e=>({id:e.id,question_type:e.question_type,content:e.content??{},is_example:Boolean(e.is_example),total_points:String(e.total_points??0),part_id:e.part_id??"",part_no:e.part_no??0,question_number:e.question_number}))),answers:T,flaggedQuestions:new Set,currentIndex:Math.max(0,K),onQuestionClick:e=>Q(C(P,e)),onPartClick:Q},footerProps:{onPrevious:W,onNext:X,onClear:()=>{},onToggleMark:()=>{},isPreviousDisabled:Z,isNextDisabled:ee,isMarked:!1},children:V}):"CAMBRIDGE_YLE"===O?e(c,{onPrevious:W,onNext:X,onClose:()=>z(r),isFirstQuestion:Z,isLastQuestion:ee,headerProps:{examName:H,examType:"Exam",totalQuestions:B,answeredCount:Y,remainingSeconds:$,isSubmitting:R,onSubmit:J},sidebarProps:y(P,T,Math.max(0,K),Q),children:V}):"SUMMER_SKY"===O?e(d,{onExit:()=>z(r),partName:F.name,instruction:F.instructions??"",onPrev:W,onNext:X,canGoPrev:!Z,canGoNext:!ee,audioUrl:F.audioUrl??"",questionNumber:k+1,recorder:null,children:V}):e(w,{title:H,answeredCount:Y,totalQuestions:B,onExit:()=>z(r),onPrev:W,onNext:X,isFirst:Z,isLast:ee,currentPart:F,onSubmit:J,isSubmitting:R,children:V});var te}function b({part:t,answers:n,onAnswerChange:i}){return e("div",{className:"space-y-4",children:t.questions.map(t=>e(p,{question:t,value:n[t.id],onChange:i},t.id))})}function w({title:n,answeredCount:i,totalQuestions:s,onExit:c,onPrev:m,onNext:d,isFirst:h,isLast:p,currentPart:x,onSubmit:g,isSubmitting:f,children:b}){return t("div",{className:"min-h-screen bg-slate-50",children:[e("header",{className:"sticky top-0 z-10 border-b bg-white px-4 py-3 shadow-sm",children:t("div",{className:"mx-auto flex max-w-5xl items-center justify-between gap-4",children:[t("div",{children:[e("h1",{className:"font-semibold text-gray-900",children:n}),t("p",{className:"text-sm text-gray-500",children:["Đã trả lời ",i,"/",s]})]}),e(u,{variant:"outline",onClick:c,children:"Thoát"})]})}),t("main",{className:"mx-auto max-w-5xl space-y-4 p-4",children:[t("div",{className:"flex items-center justify-between rounded-lg bg-white p-4 shadow-sm",children:[t(u,{variant:"outline",disabled:h,onClick:m,children:[e(a,{className:"mr-2 h-4 w-4"}),"Phần trước"]}),e("div",{className:"text-center",children:e("h2",{className:"font-medium",children:x.name})}),t(u,{variant:"outline",disabled:p,onClick:d,children:["Phần sau",e(r,{className:"ml-2 h-4 w-4"})]})]}),b,e("div",{className:"flex justify-end",children:t(u,{onClick:g,disabled:f,className:"bg-blue-600 hover:bg-blue-700",children:[f?e(o,{className:"mr-2 h-4 w-4 animate-spin"}):e(l,{className:"mr-2 h-4 w-4"}),"Nộp bài"]})})]})]})}function N(e){const t=e.questions.map(e=>e.question_number).filter(e=>Number.isFinite(e));return 0===t.length?"":`${Math.min(...t)}–${Math.max(...t)}`}function v(e){let t=0;return e.map(e=>{const n=t;return t+=e.questions.length,{id:e.id,name:e.name,category:e.template?.category,startIndex:n,endIndex:t-1,questionCount:e.questions.length,audioUrl:e.audioUrl,isGroup:e.isGroup}})}function C(e,t){let n=0;for(let i=0;i<e.length;i+=1)if(n+=e[i].questions.length,t<n)return i;return 0}function y(e,t,n,i){const s=e.flatMap((n,i)=>n.questions.map((n,s)=>({globalIndex:e.slice(0,i).reduce((e,t)=>e+t.questions.length,0)+s,partIndex:i,questionNumber:n.question_number,isAnswered:void 0!==t[n.id]&&""!==t[n.id]})));return{parts:e.map((e,n)=>({partIndex:n,partNo:e.partNo??n+1,name:e.name,category:e.template?.category,totalQuestions:e.questions.length,answeredCount:e.questions.filter(e=>void 0!==t[e.id]&&""!==t[e.id]).length})),questions:s,currentQuestionGlobalIndex:n,onPartClick:i,onQuestionClick:t=>i(C(e,t))}}function q(){return e("div",{className:"flex h-screen items-center justify-center",children:e(o,{className:"h-8 w-8 animate-spin text-blue-600"})})}function I({onExit:n}){return t("div",{className:"flex h-screen flex-col items-center justify-center gap-4",children:[e("p",{children:"Không có câu hỏi."}),e(u,{onClick:n,children:"Quay lại"})]})}
@@ -1,14 +1 @@
1
- 'use client';
2
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
- import { Textarea } from '../../../components/ui/textarea';
4
- import { Label } from '../../../components/ui/label';
5
- export function GenericQuestionRenderer({ question, value, onChange }) {
6
- return (_jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4 shadow-sm", children: [_jsxs("div", { className: "mb-3 flex items-center justify-between gap-3", children: [_jsxs("h3", { className: "font-medium text-gray-900", children: ["C\u00E2u ", question.question_number] }), _jsx("span", { className: "rounded bg-gray-100 px-2 py-1 text-xs text-gray-600", children: question.question_type })] }), _jsx(QuestionContent, { content: question.content }), _jsxs("div", { className: "mt-4 space-y-2", children: [_jsx(Label, { htmlFor: `answer-${question.id}`, children: "C\u00E2u tr\u1EA3 l\u1EDDi" }), _jsx(Textarea, { id: `answer-${question.id}`, value: typeof value === 'string' ? value : value ? JSON.stringify(value) : '', onChange: (event) => onChange(question.id, event.target.value), placeholder: "Nh\u1EADp c\u00E2u tr\u1EA3 l\u1EDDi" })] })] }));
7
- }
8
- function QuestionContent({ content }) {
9
- if (typeof content === 'string')
10
- return _jsx("p", { className: "whitespace-pre-wrap text-sm text-gray-700", children: content });
11
- if (typeof content === 'object' && content !== null)
12
- return _jsx("pre", { className: "max-h-48 overflow-auto rounded bg-gray-50 p-3 text-xs text-gray-600", children: JSON.stringify(content, null, 2) });
13
- return _jsx("p", { className: "text-sm text-gray-500", children: "Kh\u00F4ng c\u00F3 n\u1ED9i dung c\u00E2u h\u1ECFi." });
14
- }
1
+ "use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{Textarea as r}from"../../../components/ui/textarea";import{Label as n}from"../../../components/ui/label";export function GenericQuestionRenderer({question:s,value:i,onChange:o}){return e("div",{className:"rounded-lg border border-gray-200 bg-white p-4 shadow-sm",children:[e("div",{className:"mb-3 flex items-center justify-between gap-3",children:[e("h3",{className:"font-medium text-gray-900",children:["Câu ",s.question_number]}),t("span",{className:"rounded bg-gray-100 px-2 py-1 text-xs text-gray-600",children:s.question_type})]}),t(a,{content:s.content}),e("div",{className:"mt-4 space-y-2",children:[t(n,{htmlFor:`answer-${s.id}`,children:"Câu trả lời"}),t(r,{id:`answer-${s.id}`,value:"string"==typeof i?i:i?JSON.stringify(i):"",onChange:e=>o(s.id,e.target.value),placeholder:"Nhập câu trả lời"})]})]})}function a({content:e}){return"string"==typeof e?t("p",{className:"whitespace-pre-wrap text-sm text-gray-700",children:e}):"object"==typeof e&&null!==e?t("pre",{className:"max-h-48 overflow-auto rounded bg-gray-50 p-3 text-xs text-gray-600",children:JSON.stringify(e,null,2)}):t("p",{className:"text-sm text-gray-500",children:"Không có nội dung câu hỏi."})}
@@ -1,88 +1 @@
1
- export function unwrap(value) {
2
- return hasData(value) ? value.data : value;
3
- }
4
- export function unwrapAttempt(value) {
5
- return 'attempt' in value ? value.attempt : value;
6
- }
7
- export function groupQuestions(result) {
8
- const templates = result.examTemplate?.parts ?? [];
9
- const parts = new Map();
10
- for (const question of result.questions) {
11
- const key = question.part_id ?? String(question.part_no ?? 'default');
12
- parts.set(key, [...(parts.get(key) ?? []), question]);
13
- }
14
- return Array.from(parts.entries()).map(([id, questions]) => {
15
- const template = templates.find((part) => String(part.id) === id);
16
- return {
17
- id,
18
- name: template?.name ?? `Part ${questions[0]?.part_no ?? id}`,
19
- template,
20
- partId: id,
21
- partNo: questions[0]?.part_no,
22
- instructions: template?.instructions,
23
- audioUrl: template?.audioUrl,
24
- questionType: template?.questionType ?? questions[0]?.question_type,
25
- isGroup: template?.isGroup,
26
- group: template?.group,
27
- sections: template?.sections,
28
- viewMode: typeof template?.group?.viewMode === 'string' ? template.group.viewMode : undefined,
29
- startIndex: template?.startIndex,
30
- endIndex: template?.endIndex,
31
- questions: questions.sort((a, b) => a.question_number - b.question_number),
32
- };
33
- });
34
- }
35
- export function transformAnswerTheQuestion(questions) {
36
- return {
37
- instruction: readString(questions[0]?.content, 'instruction'),
38
- imageUrl: readString(questions[0]?.content, 'imageUrl'),
39
- title: readString(questions[0]?.content, 'title'),
40
- groupContent: readString(questions[0]?.content, 'groupContent'),
41
- questions: questions.map((question) => ({ id: question.id, questionNumber: question.question_number, question: readString(question.content, 'question') || readString(question.content, 'text'), imageUrl: readString(question.content, 'imageUrl'), prefixText: readString(question.content, 'prefixText'), suffixText: readString(question.content, 'suffixText'), exampleAnswer: readString(question.content, 'exampleAnswer'), suggestedAnswers: readStringArray(question.content, 'suggestedAnswers'), isExample: Boolean(question.is_example) })),
42
- };
43
- }
44
- export function transformMatchByWritingAnswer(questions) {
45
- return {
46
- instruction: readString(questions[0]?.content, 'instruction'),
47
- groupImageUrl: readString(questions[0]?.content, 'groupImageUrl'),
48
- options: readObjectArray(questions[0]?.content, 'options').map((option) => ({ answer: String(option.answer ?? option.value ?? ''), text: String(option.text ?? option.label ?? ''), content: String(option.content ?? option.text ?? option.label ?? ''), imageUrl: typeof option.imageUrl === 'string' ? option.imageUrl : undefined })),
49
- questions: questions.map((question) => ({ id: question.id, questionNumber: question.question_number, question: readString(question.content, 'question') || readString(question.content, 'text'), imageUrl: readString(question.content, 'imageUrl'), exampleAnswer: readString(question.content, 'exampleAnswer'), isExample: Boolean(question.is_example) })),
50
- };
51
- }
52
- export function transformWordFillParagraph(questions) {
53
- const first = questions[0];
54
- return { questionId: first?.id ?? '', paragraph: readString(first?.content, 'paragraph') || readString(first?.content, 'text'), title: readString(first?.content, 'title'), imageUrl: readString(first?.content, 'imageUrl'), wordBank: readObjectArray(first?.content, 'wordBank').map((item) => ({ word: String(item.word ?? item.text ?? ''), isExample: Boolean(item.isExample) })), viewMode: readString(first?.content, 'viewMode'), instruction: readString(first?.content, 'instruction') };
55
- }
56
- export function transformWriteShortLetter(question) {
57
- return { prompt: readString(question?.content, 'prompt') || readString(question?.content, 'question'), requirements: readStringArray(question?.content, 'requirements'), minWords: readNumber(question?.content, 'minWords'), maxWords: readNumber(question?.content, 'maxWords'), guideImages: readStringArray(question?.content, 'guideImages') };
58
- }
59
- export function transformWordFillStructuredForm(questions) {
60
- return { instruction: readString(questions[0]?.content, 'instruction'), groupTitle: readString(questions[0]?.content, 'groupTitle'), groupContent: readString(questions[0]?.content, 'groupContent'), groupImageUrl: readString(questions[0]?.content, 'groupImageUrl'), questions: questions.map((question) => ({ id: question.id, title: readString(question.content, 'title'), content: readString(question.content, 'content') || readString(question.content, 'html') || readString(question.content, 'text'), answers: readRecord(question.content, 'answers'), caseSensitive: Boolean(asRecord(question.content).caseSensitive), imageUrl: readString(question.content, 'imageUrl'), questionNumber: question.question_number })) };
61
- }
62
- function hasData(value) {
63
- return typeof value === 'object' && value !== null && 'data' in value;
64
- }
65
- function asRecord(value) {
66
- return typeof value === 'object' && value !== null ? value : {};
67
- }
68
- function readString(value, key) {
69
- const item = asRecord(value)[key];
70
- return typeof item === 'string' ? item : '';
71
- }
72
- function readNumber(value, key) {
73
- const item = asRecord(value)[key];
74
- return typeof item === 'number' ? item : undefined;
75
- }
76
- function readStringArray(value, key) {
77
- const item = asRecord(value)[key];
78
- return Array.isArray(item) ? item.filter((entry) => typeof entry === 'string') : [];
79
- }
80
- function readObjectArray(value, key) {
81
- const item = asRecord(value)[key];
82
- return Array.isArray(item) ? item.map(asRecord) : [];
83
- }
84
- function readRecord(value, key) {
85
- const item = asRecord(value)[key];
86
- const record = asRecord(item);
87
- return Object.fromEntries(Object.entries(record).map(([entryKey, entryValue]) => [entryKey, String(entryValue ?? '')]));
88
- }
1
+ export function unwrap(t){return function(t){return"object"==typeof t&&null!==t&&"data"in t}(t)?t.data:t}export function unwrapAttempt(t){return"attempt"in t?t.attempt:t}export function groupQuestions(t){const n=t.examTemplate?.parts??[],e=new Map;for(const n of t.questions){const t=n.part_id??String(n.part_no??"default");e.set(t,[...e.get(t)??[],n])}return Array.from(e.entries()).map(([t,e])=>{const o=n.find(n=>String(n.id)===t);return{id:t,name:o?.name??`Part ${e[0]?.part_no??t}`,template:o,partId:t,partNo:e[0]?.part_no,instructions:o?.instructions,audioUrl:o?.audioUrl,questionType:o?.questionType??e[0]?.question_type,isGroup:o?.isGroup,group:o?.group,sections:o?.sections,viewMode:"string"==typeof o?.group?.viewMode?o.group.viewMode:void 0,startIndex:o?.startIndex,endIndex:o?.endIndex,questions:e.sort((t,n)=>t.question_number-n.question_number)}})}export function transformAnswerTheQuestion(t){return{instruction:n(t[0]?.content,"instruction"),imageUrl:n(t[0]?.content,"imageUrl"),title:n(t[0]?.content,"title"),groupContent:n(t[0]?.content,"groupContent"),questions:t.map(t=>({id:t.id,questionNumber:t.question_number,question:n(t.content,"question")||n(t.content,"text"),imageUrl:n(t.content,"imageUrl"),prefixText:n(t.content,"prefixText"),suffixText:n(t.content,"suffixText"),exampleAnswer:n(t.content,"exampleAnswer"),suggestedAnswers:o(t.content,"suggestedAnswers"),isExample:Boolean(t.is_example)}))}}export function transformMatchByWritingAnswer(t){return{instruction:n(t[0]?.content,"instruction"),groupImageUrl:n(t[0]?.content,"groupImageUrl"),options:r(t[0]?.content,"options").map(t=>({answer:String(t.answer??t.value??""),text:String(t.text??t.label??""),content:String(t.content??t.text??t.label??""),imageUrl:"string"==typeof t.imageUrl?t.imageUrl:void 0})),questions:t.map(t=>({id:t.id,questionNumber:t.question_number,question:n(t.content,"question")||n(t.content,"text"),imageUrl:n(t.content,"imageUrl"),exampleAnswer:n(t.content,"exampleAnswer"),isExample:Boolean(t.is_example)}))}}export function transformWordFillParagraph(t){const e=t[0];return{questionId:e?.id??"",paragraph:n(e?.content,"paragraph")||n(e?.content,"text"),title:n(e?.content,"title"),imageUrl:n(e?.content,"imageUrl"),wordBank:r(e?.content,"wordBank").map(t=>({word:String(t.word??t.text??""),isExample:Boolean(t.isExample)})),viewMode:n(e?.content,"viewMode"),instruction:n(e?.content,"instruction")}}export function transformWriteShortLetter(t){return{prompt:n(t?.content,"prompt")||n(t?.content,"question"),requirements:o(t?.content,"requirements"),minWords:e(t?.content,"minWords"),maxWords:e(t?.content,"maxWords"),guideImages:o(t?.content,"guideImages")}}export function transformWordFillStructuredForm(e){return{instruction:n(e[0]?.content,"instruction"),groupTitle:n(e[0]?.content,"groupTitle"),groupContent:n(e[0]?.content,"groupContent"),groupImageUrl:n(e[0]?.content,"groupImageUrl"),questions:e.map(e=>({id:e.id,title:n(e.content,"title"),content:n(e.content,"content")||n(e.content,"html")||n(e.content,"text"),answers:i(e.content,"answers"),caseSensitive:Boolean(t(e.content).caseSensitive),imageUrl:n(e.content,"imageUrl"),questionNumber:e.question_number}))}}function t(t){return"object"==typeof t&&null!==t?t:{}}function n(n,e){const o=t(n)[e];return"string"==typeof o?o:""}function e(n,e){const o=t(n)[e];return"number"==typeof o?o:void 0}function o(n,e){const o=t(n)[e];return Array.isArray(o)?o.filter(t=>"string"==typeof t):[]}function r(n,e){const o=t(n)[e];return Array.isArray(o)?o.map(t):[]}function i(n,e){const o=t(n)[e],r=t(o);return Object.fromEntries(Object.entries(r).map(([t,n])=>[t,String(n??"")]))}
@@ -1,24 +1 @@
1
- 'use client';
2
- import { useRef, useState } from 'react';
3
- export function useSpeakingRecorder(_options) {
4
- const mediaRecorderRef = useRef(null);
5
- const chunksRef = useRef([]);
6
- const [status, setStatus] = useState('idle');
7
- const [previewUrl, setPreviewUrl] = useState(null);
8
- const startRecording = async () => {
9
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
10
- chunksRef.current = [];
11
- const recorder = new MediaRecorder(stream);
12
- mediaRecorderRef.current = recorder;
13
- recorder.ondataavailable = (event) => chunksRef.current.push(event.data);
14
- recorder.onstop = () => {
15
- stream.getTracks().forEach((track) => track.stop());
16
- setPreviewUrl(URL.createObjectURL(new Blob(chunksRef.current, { type: 'audio/webm' })));
17
- setStatus('recorded');
18
- };
19
- recorder.start();
20
- setStatus('recording');
21
- };
22
- const stopRecording = () => mediaRecorderRef.current?.stop();
23
- return { status, previewUrl, remainingSeconds: 0, startRecording, stopRecording };
24
- }
1
+ "use client";import{useRef as e,useState as r}from"react";export function useSpeakingRecorder(t){const n=e(null),a=e([]),[o,c]=r("idle"),[i,s]=r(null);return{status:o,previewUrl:i,remainingSeconds:0,startRecording:async()=>{const e=await navigator.mediaDevices.getUserMedia({audio:!0});a.current=[];const r=new MediaRecorder(e);n.current=r,r.ondataavailable=e=>a.current.push(e.data),r.onstop=()=>{e.getTracks().forEach(e=>e.stop()),s(URL.createObjectURL(new Blob(a.current,{type:"audio/webm"}))),c("recorded")},r.start(),c("recording")},stopRecording:()=>n.current?.stop()}}
@@ -1,2 +1 @@
1
- export { ExamTakingPageContainer } from './ExamTakingPageContainer';
2
- export { GenericQuestionRenderer } from './GenericQuestionRenderer';
1
+ export{ExamTakingPageContainer}from"./ExamTakingPageContainer";export{GenericQuestionRenderer}from"./GenericQuestionRenderer";
@@ -1 +1 @@
1
- export {};
1
+ export{};
@@ -1,42 +1 @@
1
- export * from './CueCardEditor';
2
- export * from './exams';
3
- export * from './themes';
4
- export * from './results';
5
- export * from './ui/alert-dialog';
6
- export * from './ui/alert';
7
- export * from './ui/avatar';
8
- export * from './ui/badge';
9
- export * from './ui/button';
10
- export * from './ui/calendar';
11
- export * from './ui/card';
12
- export * from './ui/carousel';
13
- export * from './ui/checkbox';
14
- export * from './ui/collapsible';
15
- export * from './ui/command';
16
- export * from './ui/confirm-dialog';
17
- export * from './ui/dialog';
18
- export * from './ui/drawer';
19
- export * from './ui/dropdown-menu';
20
- export * from './ui/file-upload';
21
- export * from './ui/form';
22
- export * from './ui/hover-card';
23
- export * from './ui/image-preview';
24
- export * from './ui/input';
25
- export * from './ui/label';
26
- export * from './ui/language-switcher';
27
- export * from './ui/multi-select';
28
- export * from './ui/points-input';
29
- export * from './ui/popover';
30
- export * from './ui/progress';
31
- export * from './ui/radio-group';
32
- export * from './ui/scroll-area';
33
- export * from './ui/select';
34
- export * from './ui/separator';
35
- export * from './ui/sheet';
36
- export * from './ui/single-select';
37
- export * from './ui/skeleton';
38
- export * from './ui/switch';
39
- export * from './ui/table';
40
- export * from './ui/tabs';
41
- export * from './ui/textarea';
42
- export * from './ui/tooltip';
1
+ export*from"./CueCardEditor";export*from"./exams";export*from"./themes";export*from"./results";export*from"./ui/alert-dialog";export*from"./ui/alert";export*from"./ui/avatar";export*from"./ui/badge";export*from"./ui/button";export*from"./ui/calendar";export*from"./ui/card";export*from"./ui/carousel";export*from"./ui/checkbox";export*from"./ui/collapsible";export*from"./ui/command";export*from"./ui/confirm-dialog";export*from"./ui/dialog";export*from"./ui/drawer";export*from"./ui/dropdown-menu";export*from"./ui/file-upload";export*from"./ui/form";export*from"./ui/hover-card";export*from"./ui/image-preview";export*from"./ui/input";export*from"./ui/label";export*from"./ui/language-switcher";export*from"./ui/multi-select";export*from"./ui/points-input";export*from"./ui/popover";export*from"./ui/progress";export*from"./ui/radio-group";export*from"./ui/scroll-area";export*from"./ui/select";export*from"./ui/separator";export*from"./ui/sheet";export*from"./ui/single-select";export*from"./ui/skeleton";export*from"./ui/switch";export*from"./ui/table";export*from"./ui/tabs";export*from"./ui/textarea";export*from"./ui/tooltip";