@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,212 +1 @@
1
- import { create } from 'zustand';
2
- const createEmptyQuestionEntry = () => ({
3
- data: {},
4
- isCompleted: false,
5
- });
6
- export const useExamQuestionStore = create((set, get) => ({
7
- examId: null,
8
- templateId: null,
9
- totalQuestions: 0,
10
- currentQuestionIndex: 0,
11
- questions: {},
12
- initialized: false,
13
- sharedHintLetters: {},
14
- sharedPassageData: {},
15
- sharedSceneData: {},
16
- sharedAnswerGroupData: {},
17
- sharedListData: {},
18
- sharedCompareImagesData: {},
19
- sharedInfoExchangeData: {},
20
- initializeExam: ({ examId, templateId, totalQuestions }) => {
21
- const questions = {};
22
- // Initialize empty questions (no localStorage loading)
23
- for (let index = 0; index < totalQuestions; index++) {
24
- questions[index] = createEmptyQuestionEntry();
25
- }
26
- set({
27
- examId,
28
- templateId,
29
- totalQuestions,
30
- currentQuestionIndex: 0,
31
- questions,
32
- initialized: true,
33
- });
34
- },
35
- setCurrentQuestionIndex: (questionIndex) => {
36
- set({ currentQuestionIndex: questionIndex });
37
- },
38
- upsertQuestionData: (questionIndex, data) => {
39
- set((state) => {
40
- const existingEntry = state.questions[questionIndex] ?? createEmptyQuestionEntry();
41
- return {
42
- questions: {
43
- ...state.questions,
44
- [questionIndex]: {
45
- ...existingEntry,
46
- data: {
47
- ...existingEntry.data,
48
- ...data,
49
- },
50
- },
51
- },
52
- };
53
- });
54
- },
55
- // Clear/reset question data to empty state (used when discarding unsaved changes for new questions)
56
- clearQuestionData: (questionIndex) => {
57
- set((state) => ({
58
- questions: {
59
- ...state.questions,
60
- [questionIndex]: createEmptyQuestionEntry(),
61
- },
62
- }));
63
- },
64
- markQuestionCompleted: (questionIndex, isCompleted) => {
65
- set((state) => {
66
- const existingEntry = state.questions[questionIndex] ?? createEmptyQuestionEntry();
67
- return {
68
- questions: {
69
- ...state.questions,
70
- [questionIndex]: {
71
- ...existingEntry,
72
- data: {
73
- ...existingEntry.data,
74
- isCompleted,
75
- },
76
- isCompleted,
77
- },
78
- },
79
- };
80
- });
81
- },
82
- getQuestionData: (questionIndex) => {
83
- return get().questions[questionIndex]?.data;
84
- },
85
- getCompletedQuestionIndices: () => {
86
- return Object.entries(get().questions)
87
- .filter(([, entry]) => entry.isCompleted)
88
- .map(([index]) => Number(index))
89
- .sort((a, b) => a - b);
90
- },
91
- // Set shared hintLetters for a specific partId + groupNumber combination
92
- setSharedHintLetters: (partId, groupNumber, hintLetters) => {
93
- const key = `${partId}_${groupNumber}`;
94
- set((state) => ({
95
- sharedHintLetters: {
96
- ...state.sharedHintLetters,
97
- [key]: hintLetters,
98
- },
99
- }));
100
- },
101
- // Get shared hintLetters for a specific partId + groupNumber combination
102
- getSharedHintLetters: (partId, groupNumber) => {
103
- const key = `${partId}_${groupNumber}`;
104
- return get().sharedHintLetters[key];
105
- },
106
- // Set shared passage data for a specific partId + groupNumber combination
107
- setSharedPassageData: (partId, groupNumber, data) => {
108
- const key = `${partId}_${groupNumber}`;
109
- set((state) => ({
110
- sharedPassageData: {
111
- ...state.sharedPassageData,
112
- [key]: data,
113
- },
114
- }));
115
- },
116
- // Get shared passage data for a specific partId + groupNumber combination
117
- getSharedPassageData: (partId, groupNumber) => {
118
- const key = `${partId}_${groupNumber}`;
119
- return get().sharedPassageData[key];
120
- },
121
- // Set shared scene data for a specific partId + groupNumber combination
122
- setSharedSceneData: (partId, groupNumber, data) => {
123
- const key = `${partId}_${groupNumber}`;
124
- set((state) => ({
125
- sharedSceneData: {
126
- ...state.sharedSceneData,
127
- [key]: data,
128
- },
129
- }));
130
- },
131
- // Get shared scene data for a specific partId + groupNumber combination
132
- getSharedSceneData: (partId, groupNumber) => {
133
- const key = `${partId}_${groupNumber}`;
134
- return get().sharedSceneData[key];
135
- },
136
- // Set shared answer group data for a specific partId + groupNumber combination
137
- setSharedAnswerGroupData: (partId, groupNumber, data) => {
138
- const key = `${partId}_${groupNumber}`;
139
- set((state) => ({
140
- sharedAnswerGroupData: {
141
- ...state.sharedAnswerGroupData,
142
- [key]: data,
143
- },
144
- }));
145
- },
146
- // Get shared answer group data for a specific partId + groupNumber combination
147
- getSharedAnswerGroupData: (partId, groupNumber) => {
148
- const key = `${partId}_${groupNumber}`;
149
- return get().sharedAnswerGroupData[key];
150
- },
151
- // Set shared list data for a specific partId + groupNumber combination
152
- setSharedListData: (partId, groupNumber, data) => {
153
- const key = `${partId}_${groupNumber}`;
154
- set((state) => ({
155
- sharedListData: {
156
- ...state.sharedListData,
157
- [key]: data,
158
- },
159
- }));
160
- },
161
- // Get shared list data for a specific partId + groupNumber combination
162
- getSharedListData: (partId, groupNumber) => {
163
- const key = `${partId}_${groupNumber}`;
164
- return get().sharedListData[key];
165
- },
166
- // Set shared compare images data for a specific partId + groupNumber combination
167
- setSharedCompareImagesData: (partId, groupNumber, data) => {
168
- const key = `${partId}_${groupNumber}`;
169
- set((state) => ({
170
- sharedCompareImagesData: {
171
- ...state.sharedCompareImagesData,
172
- [key]: data,
173
- },
174
- }));
175
- },
176
- // Get shared compare images data for a specific partId + groupNumber combination
177
- getSharedCompareImagesData: (partId, groupNumber) => {
178
- const key = `${partId}_${groupNumber}`;
179
- return get().sharedCompareImagesData[key];
180
- },
181
- // Set shared info exchange data for a specific partId + groupNumber combination
182
- setSharedInfoExchangeData: (partId, groupNumber, data) => {
183
- const key = `${partId}_${groupNumber}`;
184
- set((state) => ({
185
- sharedInfoExchangeData: {
186
- ...state.sharedInfoExchangeData,
187
- [key]: data,
188
- },
189
- }));
190
- },
191
- // Get shared info exchange data for a specific partId + groupNumber combination
192
- getSharedInfoExchangeData: (partId, groupNumber) => {
193
- const key = `${partId}_${groupNumber}`;
194
- return get().sharedInfoExchangeData[key];
195
- },
196
- resetStore: () => {
197
- set({
198
- examId: null,
199
- templateId: null,
200
- totalQuestions: 0,
201
- currentQuestionIndex: 0,
202
- questions: {},
203
- initialized: false,
204
- sharedHintLetters: {},
205
- sharedPassageData: {},
206
- sharedSceneData: {},
207
- sharedAnswerGroupData: {},
208
- sharedListData: {},
209
- sharedCompareImagesData: {},
210
- });
211
- },
212
- }));
1
+ import{create as e}from"zustand";const a=()=>({data:{},isCompleted:!1});export const useExamQuestionStore=e((e,t)=>({examId:null,templateId:null,totalQuestions:0,currentQuestionIndex:0,questions:{},initialized:!1,sharedHintLetters:{},sharedPassageData:{},sharedSceneData:{},sharedAnswerGroupData:{},sharedListData:{},sharedCompareImagesData:{},sharedInfoExchangeData:{},initializeExam:({examId:t,templateId:s,totalQuestions:r})=>{const n={};for(let e=0;e<r;e++)n[e]=a();e({examId:t,templateId:s,totalQuestions:r,currentQuestionIndex:0,questions:n,initialized:!0})},setCurrentQuestionIndex:a=>{e({currentQuestionIndex:a})},upsertQuestionData:(a,t)=>{e(e=>{const s=e.questions[a]??{data:{},isCompleted:!1};return{questions:{...e.questions,[a]:{...s,data:{...s.data,...t}}}}})},clearQuestionData:a=>{e(e=>({questions:{...e.questions,[a]:{data:{},isCompleted:!1}}}))},markQuestionCompleted:(a,t)=>{e(e=>{const s=e.questions[a]??{data:{},isCompleted:!1};return{questions:{...e.questions,[a]:{...s,data:{...s.data,isCompleted:t},isCompleted:t}}}})},getQuestionData:e=>t().questions[e]?.data,getCompletedQuestionIndices:()=>Object.entries(t().questions).filter(([,e])=>e.isCompleted).map(([e])=>Number(e)).sort((e,a)=>e-a),setSharedHintLetters:(a,t,s)=>{const r=`${a}_${t}`;e(e=>({sharedHintLetters:{...e.sharedHintLetters,[r]:s}}))},getSharedHintLetters:(e,a)=>{const s=`${e}_${a}`;return t().sharedHintLetters[s]},setSharedPassageData:(a,t,s)=>{const r=`${a}_${t}`;e(e=>({sharedPassageData:{...e.sharedPassageData,[r]:s}}))},getSharedPassageData:(e,a)=>{const s=`${e}_${a}`;return t().sharedPassageData[s]},setSharedSceneData:(a,t,s)=>{const r=`${a}_${t}`;e(e=>({sharedSceneData:{...e.sharedSceneData,[r]:s}}))},getSharedSceneData:(e,a)=>{const s=`${e}_${a}`;return t().sharedSceneData[s]},setSharedAnswerGroupData:(a,t,s)=>{const r=`${a}_${t}`;e(e=>({sharedAnswerGroupData:{...e.sharedAnswerGroupData,[r]:s}}))},getSharedAnswerGroupData:(e,a)=>{const s=`${e}_${a}`;return t().sharedAnswerGroupData[s]},setSharedListData:(a,t,s)=>{const r=`${a}_${t}`;e(e=>({sharedListData:{...e.sharedListData,[r]:s}}))},getSharedListData:(e,a)=>{const s=`${e}_${a}`;return t().sharedListData[s]},setSharedCompareImagesData:(a,t,s)=>{const r=`${a}_${t}`;e(e=>({sharedCompareImagesData:{...e.sharedCompareImagesData,[r]:s}}))},getSharedCompareImagesData:(e,a)=>{const s=`${e}_${a}`;return t().sharedCompareImagesData[s]},setSharedInfoExchangeData:(a,t,s)=>{const r=`${a}_${t}`;e(e=>({sharedInfoExchangeData:{...e.sharedInfoExchangeData,[r]:s}}))},getSharedInfoExchangeData:(e,a)=>{const s=`${e}_${a}`;return t().sharedInfoExchangeData[s]},resetStore:()=>{e({examId:null,templateId:null,totalQuestions:0,currentQuestionIndex:0,questions:{},initialized:!1,sharedHintLetters:{},sharedPassageData:{},sharedSceneData:{},sharedAnswerGroupData:{},sharedListData:{},sharedCompareImagesData:{}})}}));
@@ -1,10 +1 @@
1
- import { create } from 'zustand';
2
- import { persist } from 'zustand/middleware';
3
- export const useLocaleStore = create()(persist((set) => ({
4
- locale: 'vi',
5
- setLocale: (locale) => {
6
- set({ locale });
7
- },
8
- }), {
9
- name: 'locale-storage',
10
- }));
1
+ import{create as e}from"zustand";import{persist as o}from"zustand/middleware";export const useLocaleStore=e()(o(e=>({locale:"vi",setLocale:o=>{e({locale:o})}}),{name:"locale-storage"}));
@@ -1,44 +1 @@
1
- /** Known sub-routes under /student/contests/ that are NOT contest slugs */
2
- const CONTEST_KNOWN_SUBROUTES = ['discover', 'my-contests'];
3
- /** Static paths that are always publicly accessible (no auth required) */
4
- const STATIC_PUBLIC_PATHS = [
5
- '/',
6
- '/login',
7
- '/register',
8
- '/terms',
9
- '/student/contests/discover',
10
- '/upload-sheet',
11
- '/result',
12
- '/tra-cuu-ket-qua-oea',
13
- '/placement-test',
14
- ];
15
- /**
16
- * Check if the current browser page is a public page or a contest detail page
17
- * (which may be publicly accessible depending on contest visibility).
18
- *
19
- * Used by both the axios response interceptor and AuthSessionSync to decide
20
- * whether to redirect to /login on 401 responses.
21
- */
22
- export function isPublicOrContestPage() {
23
- if (typeof window === 'undefined')
24
- return false;
25
- const pathname = window.location.pathname;
26
- // Check static public paths
27
- const isStaticPublic = STATIC_PUBLIC_PATHS.some((path) => pathname === path || (path !== '/' && pathname.startsWith(path + '/')));
28
- if (isStaticPublic)
29
- return true;
30
- // Contest detail pages (/student/contests/[slug]) may be public depending on visibility.
31
- // We can't call the API here (sync context), so we optimistically skip the redirect
32
- // and let the page itself handle the "not found / not public" case.
33
- const isContestDetailPage = pathname.startsWith('/student/contests/') &&
34
- !CONTEST_KNOWN_SUBROUTES.includes(pathname.split('/')[3] || '');
35
- if (isContestDetailPage)
36
- return true;
37
- // Result review pages with a token are public
38
- const isPublicResultReview = pathname.startsWith('/student/results/') &&
39
- pathname.endsWith('/review') &&
40
- window.location.search.includes('token=');
41
- if (isPublicResultReview)
42
- return true;
43
- return false;
44
- }
1
+ const t=["discover","my-contests"],e=["/","/login","/register","/terms","/student/contests/discover","/upload-sheet","/result","/tra-cuu-ket-qua-oea","/placement-test"];export function isPublicOrContestPage(){if("undefined"==typeof window)return!1;const s=window.location.pathname;if(e.some(t=>s===t||"/"!==t&&s.startsWith(t+"/")))return!0;if(s.startsWith("/student/contests/")&&!t.includes(s.split("/")[3]||""))return!0;return!!(s.startsWith("/student/results/")&&s.endsWith("/review")&&window.location.search.includes("token="))}
@@ -1 +1 @@
1
- export {};
1
+ export{};
@@ -1,174 +1 @@
1
- // ─── Import transforms từ từng question type ────────────────────────────────
2
- import { transformLookPictureChooseCorrectAnswer } from '../../../components/questions/types/look-picture-choose-correct-answer/transform';
3
- import { transformLookPictureFillBlankChooseAnswer } from '../../../components/questions/types/look-picture-fill-blank-choose-answer/transform';
4
- import { transformLookPictureFillWordHint } from '../../../components/questions/types/look-picture-fill-word-hint/transform';
5
- import { transformReadAndColorObjects } from '../../../components/questions/types/read-and-color-objects/transform';
6
- import { transformReadPassageAndAnswerQuestions } from '../../../components/questions/types/read-passage-and-answer-questions/transform';
7
- import { transformArrangeLettersIntoWords } from '../../../components/questions/types/arrange-letters-into-words/transform';
8
- import { transformWriteShortParagraph } from '../../../components/questions/types/write-short-paragraph/transform';
9
- import { transformWriteAShortLetter } from '../../../components/questions/types/write-a-short-letter/transform';
10
- import { transformFillMissingWordsInGrid } from '../../../components/questions/types/fill-missing-words-in-grid/transform';
11
- import { transformLabelThePicture } from '../../../components/questions/types/label-the-picture/transform';
12
- import { transformChooseTheCorrectAnswer } from '../../../components/questions/types/choose-the-correct-answer/transform';
13
- import { transformFillInBlank } from '../../../components/questions/types/fill-in-blank/transform';
14
- import { transformWriteCorrectVerbForm } from '../../../components/questions/types/write-correct-verb-form/transform';
15
- import { transformChooseCorrectAdjective } from '../../../components/questions/types/choose-correct-adjective/transform';
16
- import { transformAnswerTheQuestion } from '../../../components/questions/types/answer-the-question/transform';
17
- import { transformTrueFalse } from '../../../components/questions/types/true-false/transform';
18
- import { transformWordOrdering } from '../../../components/questions/types/word-ordering/transform';
19
- import { transformWordFillParagraph } from '../../../components/questions/types/word-fill-paragraph/transform';
20
- import { transformMatchByWritingAnswer } from '../../../components/questions/types/match-by-writing-answer/transform';
21
- import { transformWriteSentences } from '../../../components/questions/types/write-sentences/transform';
22
- import { transformListenAndChooseFromAnswerGroup } from '../../../components/questions/types/listen-and-choose-from-answer-group/transform';
23
- import { transformListenAndChooseObjectsInScene } from '../../../components/questions/types/listen-and-choose-objects-in-scene/transform';
24
- import { transformListenAndDragObjectsIntoScene } from '../../../components/questions/types/listen-and-drag-objects-into-scene/transform';
25
- import { transformListenAndSpeakAnswer } from '../../../components/questions/types/listen-and-speak-answer/transform';
26
- import { transformListenAndSpeakImageGroup } from '../../../components/questions/types/listen-and-speak-image-group/transform';
27
- import { transformListenAndSpeakQuestionList } from '../../../components/questions/types/listen-and-speak-question-list/transform';
28
- import { transformListenAndSpeakCompareImages } from '../../../components/questions/types/listen-and-speak-compare-images/transform';
29
- import { transformListenAndSpeakOddOneOut } from '../../../components/questions/types/listen-and-speak-odd-one-out/transform';
30
- import { transformListenAndSpeakWithStoryImages } from '../../../components/questions/types/listen-and-speak-with-story-images/transform';
31
- import { transformListenAndSpeakInfoExchange } from '../../../components/questions/types/listen-and-speak-info-exchange/transform';
32
- import { transformSpeakingDescribeImage } from '../../../components/questions/types/speaking-describe-image/transform';
33
- import { transformReadDisplayedContent } from '../../../components/questions/types/read-displayed-content/transform';
34
- import { transformSpontaneousQA } from '../../../components/questions/types/spontaneous-qa/transform';
35
- import { transformSpeakingConversation } from '../../../components/questions/types/speaking-conversation/transform';
36
- import { transformSpeakingCueCard } from '../../../components/questions/types/speaking-cue-card/transform';
37
- import { transformGNSpeakingInterview } from '../../../components/questions/types/gn-speaking-interview/transform';
38
- import { transformWordFillStructuredForm } from '../../../components/questions/types/word-fill-structured-form/transform';
39
- // ─── Handler map ────────────────────────────────────────────────────────────
40
- const questionTransformHandlers = {
41
- // Look picture
42
- LOOK_PICTURE_CHOOSE_CORRECT_ANSWER: transformLookPictureChooseCorrectAnswer,
43
- LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER: transformLookPictureFillBlankChooseAnswer,
44
- LOOK_PICTURE_FILL_WORD_HINT: transformLookPictureFillWordHint,
45
- // Reading
46
- READ_AND_COLOR_OBJECTS: transformReadAndColorObjects,
47
- IMAGE_OBJECT_MATCHING: transformReadAndColorObjects,
48
- READ_PASSAGE_AND_ANSWER_QUESTIONS: transformReadPassageAndAnswerQuestions,
49
- // Fill / Write / General
50
- ARRANGE_LETTERS_INTO_WORDS: transformArrangeLettersIntoWords,
51
- WRITE_SHORT_PARAGRAPH: transformWriteShortParagraph,
52
- WRITE_A_SHORT_LETTER: transformWriteAShortLetter,
53
- FILL_MISSING_WORDS_IN_GRID: transformFillMissingWordsInGrid,
54
- LABEL_THE_PICTURE: transformLabelThePicture,
55
- CHOOSE_THE_CORRECT_ANSWER: transformChooseTheCorrectAnswer,
56
- FILL_IN_BLANK: transformFillInBlank,
57
- WRITE_CORRECT_VERB_FORM: transformWriteCorrectVerbForm,
58
- CHOOSE_CORRECT_ADJECTIVE: transformChooseCorrectAdjective,
59
- ANSWER_THE_QUESTION: transformAnswerTheQuestion,
60
- TRUE_FALSE: transformTrueFalse,
61
- WORD_ORDERING: transformWordOrdering,
62
- WORD_FILL_PARAGRAPH: transformWordFillParagraph,
63
- MATCH_BY_WRITING_ANSWER: transformMatchByWritingAnswer,
64
- WRITE_SENTENCES: transformWriteSentences,
65
- LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP: transformListenAndChooseFromAnswerGroup,
66
- LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE: transformListenAndChooseObjectsInScene,
67
- LISTEN_AND_DRAG_OBJECTS_INTO_SCENE: transformListenAndDragObjectsIntoScene,
68
- LISTEN_AND_SPEAK_ANSWER: transformListenAndSpeakAnswer,
69
- LISTEN_AND_SPEAK_IMAGE_GROUP: transformListenAndSpeakImageGroup,
70
- LISTEN_AND_SPEAK_QUESTION_LIST: transformListenAndSpeakQuestionList,
71
- LISTEN_AND_SPEAK_COMPARE_IMAGES: transformListenAndSpeakCompareImages,
72
- LISTEN_AND_SPEAK_ODD_ONE_OUT: transformListenAndSpeakOddOneOut,
73
- LISTEN_AND_SPEAK_WITH_STORY_IMAGES: transformListenAndSpeakWithStoryImages,
74
- LISTEN_AND_SPEAK_INFO_EXCHANGE: transformListenAndSpeakInfoExchange,
75
- SPEAKING_DESCRIBE_IMAGE: transformSpeakingDescribeImage,
76
- READ_DISPLAYED_CONTENT: transformReadDisplayedContent,
77
- SPONTANEOUS_QA: transformSpontaneousQA,
78
- SPEAKING_CONVERSATION: transformSpeakingConversation,
79
- SPEAKING_CUE_CARD: transformSpeakingCueCard,
80
- GN_SPEAKING_INTERVIEW: transformGNSpeakingInterview,
81
- WORD_FILL_STRUCTURED_FORM: transformWordFillStructuredForm,
82
- };
83
- /**
84
- * Transform frontend question format to API format.
85
- * API expects camelCase: questionType, content, correctAnswer, points, explanation, questionNumber.
86
- */
87
- export function transformQuestionToApiFormat(question, options = {}) {
88
- const { partId, partNo, questionNumber, addToQuestionBank, questionBankCode, questionBankTitle, sectionId } = options;
89
- const { id, type, points, explanation } = question;
90
- const handler = type ? questionTransformHandlers[type] : undefined;
91
- const handlerResult = handler ? handler(question) : { apiContent: {}, apiCorrectAnswer: {} };
92
- const { apiContent, apiCorrectAnswer, totalPoints, hintLetters, groupNumber, passageData, imageData, basicGroupData, questionListGroupData, sceneData, answerGroupData, compareImagesGroupData, infoExchangeGroupData, conversationGroupData, isExample, suggestedAnswers, } = handlerResult;
93
- const answerData = question.answer;
94
- const contentData = question.content;
95
- const handlerExplanation = handlerResult.explanation;
96
- const finalExplanation = handlerExplanation || explanation || answerData?.explanation || contentData?.explanation || '';
97
- const finalPoints = totalPoints ?? points ?? 1;
98
- const payload = {
99
- id,
100
- questionType: type || '',
101
- content: apiContent,
102
- correctAnswer: apiCorrectAnswer || {},
103
- points: finalPoints,
104
- explanation: finalExplanation,
105
- questionNumber,
106
- partId,
107
- partNo,
108
- ...(sectionId != null ? { sectionId } : {}),
109
- questionSkillType: question.skill,
110
- addToQuestionBank: addToQuestionBank ?? false,
111
- questionBank: addToQuestionBank && questionBankCode && questionBankTitle
112
- ? { code: questionBankCode, title: questionBankTitle }
113
- : undefined,
114
- isExample: isExample || false,
115
- };
116
- if (suggestedAnswers && suggestedAnswers.length > 0) {
117
- payload.suggestedAnswers = suggestedAnswers;
118
- }
119
- const groupPayload = resolveQuestionGroupPayload({
120
- hintLetters,
121
- passageData,
122
- imageData,
123
- basicGroupData,
124
- sceneData,
125
- answerGroupData,
126
- questionListGroupData,
127
- compareImagesGroupData,
128
- infoExchangeGroupData,
129
- conversationGroupData,
130
- });
131
- if (groupPayload) {
132
- payload.isGroup = true;
133
- payload.questionGroup = { payload: groupPayload, groupNumber: groupNumber || 1 };
134
- }
135
- return payload;
136
- }
137
- function resolveQuestionGroupPayload(sources) {
138
- const { hintLetters, passageData, imageData, basicGroupData, sceneData, answerGroupData, questionListGroupData, compareImagesGroupData, infoExchangeGroupData, conversationGroupData, } = sources;
139
- if (hintLetters && hintLetters.length > 0)
140
- return { hintLetters };
141
- if (passageData)
142
- return passageData;
143
- if (imageData)
144
- return imageData;
145
- if (basicGroupData && (basicGroupData.title || basicGroupData.subtitle || basicGroupData.content || basicGroupData.imageUrl || basicGroupData.articles)) {
146
- return basicGroupData;
147
- }
148
- if (sceneData)
149
- return sceneData;
150
- if (answerGroupData)
151
- return answerGroupData;
152
- if (questionListGroupData)
153
- return questionListGroupData;
154
- if (compareImagesGroupData)
155
- return compareImagesGroupData;
156
- if (infoExchangeGroupData)
157
- return infoExchangeGroupData;
158
- if (conversationGroupData)
159
- return conversationGroupData;
160
- return undefined;
161
- }
162
- /**
163
- * Transform multiple questions to API format. Mirrors the reference FE behaviour
164
- * but without the standalone validation pass (validation lives in the creator UI).
165
- */
166
- export function transformQuestionsToApiFormat(questions) {
167
- const validQuestions = [];
168
- questions.forEach((item, index) => {
169
- const { question, partId, partNo, sectionId, addToQuestionBank, questionBankCode, questionBankTitle } = item;
170
- const questionNumber = question.questionNumber ?? index + 1;
171
- validQuestions.push(transformQuestionToApiFormat(question, { partId, partNo, questionNumber, addToQuestionBank, questionBankCode, questionBankTitle, sectionId }));
172
- });
173
- return { validQuestions, invalidQuestions: [] };
174
- }
1
+ import{transformLookPictureChooseCorrectAnswer as o}from"../../../components/questions/types/look-picture-choose-correct-answer/transform";import{transformLookPictureFillBlankChooseAnswer as t}from"../../../components/questions/types/look-picture-fill-blank-choose-answer/transform";import{transformLookPictureFillWordHint as s}from"../../../components/questions/types/look-picture-fill-word-hint/transform";import{transformReadAndColorObjects as e}from"../../../components/questions/types/read-and-color-objects/transform";import{transformReadPassageAndAnswerQuestions as n}from"../../../components/questions/types/read-passage-and-answer-questions/transform";import{transformArrangeLettersIntoWords as r}from"../../../components/questions/types/arrange-letters-into-words/transform";import{transformWriteShortParagraph as a}from"../../../components/questions/types/write-short-paragraph/transform";import{transformWriteAShortLetter as i}from"../../../components/questions/types/write-a-short-letter/transform";import{transformFillMissingWordsInGrid as p}from"../../../components/questions/types/fill-missing-words-in-grid/transform";import{transformLabelThePicture as m}from"../../../components/questions/types/label-the-picture/transform";import{transformChooseTheCorrectAnswer as u}from"../../../components/questions/types/choose-the-correct-answer/transform";import{transformFillInBlank as _}from"../../../components/questions/types/fill-in-blank/transform";import{transformWriteCorrectVerbForm as c}from"../../../components/questions/types/write-correct-verb-form/transform";import{transformChooseCorrectAdjective as E}from"../../../components/questions/types/choose-correct-adjective/transform";import{transformAnswerTheQuestion as f}from"../../../components/questions/types/answer-the-question/transform";import{transformTrueFalse as N}from"../../../components/questions/types/true-false/transform";import{transformWordOrdering as A}from"../../../components/questions/types/word-ordering/transform";import{transformWordFillParagraph as T}from"../../../components/questions/types/word-fill-paragraph/transform";import{transformMatchByWritingAnswer as I}from"../../../components/questions/types/match-by-writing-answer/transform";import{transformWriteSentences as S}from"../../../components/questions/types/write-sentences/transform";import{transformListenAndChooseFromAnswerGroup as R}from"../../../components/questions/types/listen-and-choose-from-answer-group/transform";import{transformListenAndChooseObjectsInScene as d}from"../../../components/questions/types/listen-and-choose-objects-in-scene/transform";import{transformListenAndDragObjectsIntoScene as l}from"../../../components/questions/types/listen-and-drag-objects-into-scene/transform";import{transformListenAndSpeakAnswer as q}from"../../../components/questions/types/listen-and-speak-answer/transform";import{transformListenAndSpeakImageGroup as D}from"../../../components/questions/types/listen-and-speak-image-group/transform";import{transformListenAndSpeakQuestionList as O}from"../../../components/questions/types/listen-and-speak-question-list/transform";import{transformListenAndSpeakCompareImages as y}from"../../../components/questions/types/listen-and-speak-compare-images/transform";import{transformListenAndSpeakOddOneOut as C}from"../../../components/questions/types/listen-and-speak-odd-one-out/transform";import{transformListenAndSpeakWithStoryImages as G}from"../../../components/questions/types/listen-and-speak-with-story-images/transform";import{transformListenAndSpeakInfoExchange as g}from"../../../components/questions/types/listen-and-speak-info-exchange/transform";import{transformSpeakingDescribeImage as L}from"../../../components/questions/types/speaking-describe-image/transform";import{transformReadDisplayedContent as w}from"../../../components/questions/types/read-displayed-content/transform";import{transformSpontaneousQA as k}from"../../../components/questions/types/spontaneous-qa/transform";import{transformSpeakingConversation as h}from"../../../components/questions/types/speaking-conversation/transform";import{transformSpeakingCueCard as P}from"../../../components/questions/types/speaking-cue-card/transform";import{transformGNSpeakingInterview as B}from"../../../components/questions/types/gn-speaking-interview/transform";import{transformWordFillStructuredForm as W}from"../../../components/questions/types/word-fill-structured-form/transform";const b={LOOK_PICTURE_CHOOSE_CORRECT_ANSWER:o,LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER:t,LOOK_PICTURE_FILL_WORD_HINT:s,READ_AND_COLOR_OBJECTS:e,IMAGE_OBJECT_MATCHING:e,READ_PASSAGE_AND_ANSWER_QUESTIONS:n,ARRANGE_LETTERS_INTO_WORDS:r,WRITE_SHORT_PARAGRAPH:a,WRITE_A_SHORT_LETTER:i,FILL_MISSING_WORDS_IN_GRID:p,LABEL_THE_PICTURE:m,CHOOSE_THE_CORRECT_ANSWER:u,FILL_IN_BLANK:_,WRITE_CORRECT_VERB_FORM:c,CHOOSE_CORRECT_ADJECTIVE:E,ANSWER_THE_QUESTION:f,TRUE_FALSE:N,WORD_ORDERING:A,WORD_FILL_PARAGRAPH:T,MATCH_BY_WRITING_ANSWER:I,WRITE_SENTENCES:S,LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP:R,LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE:d,LISTEN_AND_DRAG_OBJECTS_INTO_SCENE:l,LISTEN_AND_SPEAK_ANSWER:q,LISTEN_AND_SPEAK_IMAGE_GROUP:D,LISTEN_AND_SPEAK_QUESTION_LIST:O,LISTEN_AND_SPEAK_COMPARE_IMAGES:y,LISTEN_AND_SPEAK_ODD_ONE_OUT:C,LISTEN_AND_SPEAK_WITH_STORY_IMAGES:G,LISTEN_AND_SPEAK_INFO_EXCHANGE:g,SPEAKING_DESCRIBE_IMAGE:L,READ_DISPLAYED_CONTENT:w,SPONTANEOUS_QA:k,SPEAKING_CONVERSATION:h,SPEAKING_CUE_CARD:P,GN_SPEAKING_INTERVIEW:B,WORD_FILL_STRUCTURED_FORM:W};export function transformQuestionToApiFormat(o,t={}){const{partId:s,partNo:e,questionNumber:n,addToQuestionBank:r,questionBankCode:a,questionBankTitle:i,sectionId:p}=t,{id:m,type:u,points:_,explanation:c}=o,E=u?b[u]:void 0,f=E?E(o):{apiContent:{},apiCorrectAnswer:{}},{apiContent:N,apiCorrectAnswer:A,totalPoints:T,hintLetters:I,groupNumber:S,passageData:R,imageData:d,basicGroupData:l,questionListGroupData:q,sceneData:D,answerGroupData:O,compareImagesGroupData:y,infoExchangeGroupData:C,conversationGroupData:G,isExample:g,suggestedAnswers:L}=f,w=o.answer,k=o.content,h={id:m,questionType:u||"",content:N,correctAnswer:A||{},points:T??_??1,explanation:f.explanation||c||w?.explanation||k?.explanation||"",questionNumber:n,partId:s,partNo:e,...null!=p?{sectionId:p}:{},questionSkillType:o.skill,addToQuestionBank:r??!1,questionBank:r&&a&&i?{code:a,title:i}:void 0,isExample:g||!1};L&&L.length>0&&(h.suggestedAnswers=L);const P=function(o){const{hintLetters:t,passageData:s,imageData:e,basicGroupData:n,sceneData:r,answerGroupData:a,questionListGroupData:i,compareImagesGroupData:p,infoExchangeGroupData:m,conversationGroupData:u}=o;if(t&&t.length>0)return{hintLetters:t};if(s)return s;if(e)return e;if(n&&(n.title||n.subtitle||n.content||n.imageUrl||n.articles))return n;return r||(a||(i||(p||(m||(u||void 0)))))}({hintLetters:I,passageData:R,imageData:d,basicGroupData:l,sceneData:D,answerGroupData:O,questionListGroupData:q,compareImagesGroupData:y,infoExchangeGroupData:C,conversationGroupData:G});return P&&(h.isGroup=!0,h.questionGroup={payload:P,groupNumber:S||1}),h}export function transformQuestionsToApiFormat(o){const t=[];return o.forEach((o,s)=>{const{question:e,partId:n,partNo:r,sectionId:a,addToQuestionBank:i,questionBankCode:p,questionBankTitle:m}=o,u=e.questionNumber??s+1;t.push(transformQuestionToApiFormat(e,{partId:n,partNo:r,questionNumber:u,addToQuestionBank:i,questionBankCode:p,questionBankTitle:m,sectionId:a}))}),{validQuestions:t,invalidQuestions:[]}}
@@ -1,168 +1 @@
1
- import { clsx } from 'clsx';
2
- import { twMerge } from 'tailwind-merge';
3
- /**
4
- * Merge Tailwind CSS classes with clsx
5
- */
6
- export function cn(...inputs) {
7
- return twMerge(clsx(inputs));
8
- }
9
- /**
10
- * Format date to readable string
11
- */
12
- export function formatDate(date, format = 'DD/MM/YYYY') {
13
- const d = new Date(date);
14
- const day = String(d.getDate()).padStart(2, '0');
15
- const month = String(d.getMonth() + 1).padStart(2, '0');
16
- const year = d.getFullYear();
17
- const hours = String(d.getHours()).padStart(2, '0');
18
- const minutes = String(d.getMinutes()).padStart(2, '0');
19
- return format
20
- .replace('DD', day)
21
- .replace('MM', month)
22
- .replace('YYYY', String(year))
23
- .replace('HH', hours)
24
- .replace('mm', minutes);
25
- }
26
- /**
27
- * Format duration in seconds to readable string
28
- */
29
- export function formatDuration(seconds) {
30
- const hours = Math.floor(seconds / 3600);
31
- const minutes = Math.floor((seconds % 3600) / 60);
32
- const secs = seconds % 60;
33
- if (hours > 0) {
34
- return `${hours}h ${minutes}m ${secs}s`;
35
- }
36
- if (minutes > 0) {
37
- return `${minutes}m ${secs}s`;
38
- }
39
- return `${secs}s`;
40
- }
41
- /**
42
- * Debounce function
43
- */
44
- export function debounce(func, delay) {
45
- let timeoutId;
46
- return (...args) => {
47
- clearTimeout(timeoutId);
48
- timeoutId = setTimeout(() => func(...args), delay);
49
- };
50
- }
51
- /**
52
- * Truncate string
53
- */
54
- export function truncate(str, length) {
55
- if (str.length <= length)
56
- return str;
57
- return `${str.slice(0, length)}...`;
58
- }
59
- /**
60
- * Get initials from name
61
- */
62
- export function getInitials(name) {
63
- return name
64
- .split(' ')
65
- .map((n) => n[0])
66
- .join('')
67
- .toUpperCase()
68
- .slice(0, 2);
69
- }
70
- /**
71
- * Format number with commas
72
- */
73
- export function formatNumber(num) {
74
- return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
75
- }
76
- /**
77
- * Calculate percentage
78
- */
79
- export function calculatePercentage(value, total) {
80
- if (total === 0)
81
- return 0;
82
- return Math.round((value / total) * 100);
83
- }
84
- /**
85
- * Format date/time to Vietnam timezone (UTC+7)
86
- * @param date - ISO date string or Date object
87
- * @param format - Output format (default: 'DD/MM/YYYY HH:mm')
88
- * @returns Formatted date string in UTC+7
89
- */
90
- export function formatDateTimeVN(date, format = 'DD/MM/YYYY HH:mm') {
91
- if (!date)
92
- return '';
93
- try {
94
- const d = new Date(date);
95
- if (isNaN(d.getTime()))
96
- return 'Invalid Date';
97
- // Convert to Vietnam timezone (UTC+7)
98
- const vietnamTime = new Date(d.getTime() + (7 * 60 * 60 * 1000));
99
- const day = String(vietnamTime.getUTCDate()).padStart(2, '0');
100
- const month = String(vietnamTime.getUTCMonth() + 1).padStart(2, '0');
101
- const year = vietnamTime.getUTCFullYear();
102
- const hours = String(vietnamTime.getUTCHours()).padStart(2, '0');
103
- const minutes = String(vietnamTime.getUTCMinutes()).padStart(2, '0');
104
- return format
105
- .replace('DD', day)
106
- .replace('MM', month)
107
- .replace('YYYY', String(year))
108
- .replace('HH', hours)
109
- .replace('mm', minutes);
110
- }
111
- catch {
112
- return 'Invalid Date';
113
- }
114
- }
115
- /**
116
- * Format ISO datetime to time only in Vietnam timezone (UTC+7)
117
- * @param date - ISO date string or Date object
118
- * @returns Time string in HH:mm format (UTC+7)
119
- */
120
- export function formatTimeVN(date) {
121
- return formatDateTimeVN(date, 'HH:mm');
122
- }
123
- /**
124
- * Format date only in Vietnam timezone (UTC+7)
125
- * @param date - ISO date string or Date object
126
- * @returns Date string in DD/MM/YYYY format (UTC+7)
127
- */
128
- export function formatDateVN(date) {
129
- return formatDateTimeVN(date, 'DD/MM/YYYY');
130
- }
131
- /**
132
- * Extract date part from ISO string in Vietnam timezone (for date input)
133
- * @param date - ISO date string or Date object
134
- * @returns Date string in YYYY-MM-DD format (for HTML date input)
135
- */
136
- export function getDateInputValue(date) {
137
- if (!date)
138
- return '';
139
- try {
140
- const d = new Date(date);
141
- if (isNaN(d.getTime()))
142
- return '';
143
- // Convert to Vietnam timezone (UTC+7)
144
- const vietnamTime = new Date(d.getTime() + (7 * 60 * 60 * 1000));
145
- const year = vietnamTime.getUTCFullYear();
146
- const month = String(vietnamTime.getUTCMonth() + 1).padStart(2, '0');
147
- const day = String(vietnamTime.getUTCDate()).padStart(2, '0');
148
- return `${year}-${month}-${day}`;
149
- }
150
- catch {
151
- return '';
152
- }
153
- }
154
- /**
155
- * Extract time part from ISO string in Vietnam timezone (for time input)
156
- * @param date - ISO date string or Date object
157
- * @returns Time string in HH:mm format (for HTML time input)
158
- */
159
- export function getTimeInputValue(date) {
160
- return formatTimeVN(date);
161
- }
162
- /**
163
- * Remove undefined, null, and empty string values from an object.
164
- * Useful for cleaning API payloads before sending to backend.
165
- */
166
- export function cleanPayload(payload) {
167
- return Object.fromEntries(Object.entries(payload).filter(([, v]) => v !== undefined && v !== '' && v !== null));
168
- }
1
+ import{clsx as t}from"clsx";import{twMerge as e}from"tailwind-merge";export function cn(...r){return e(t(r))}export function formatDate(t,e="DD/MM/YYYY"){const r=new Date(t),n=String(r.getDate()).padStart(2,"0"),a=String(r.getMonth()+1).padStart(2,"0"),o=r.getFullYear(),i=String(r.getHours()).padStart(2,"0"),u=String(r.getMinutes()).padStart(2,"0");return e.replace("DD",n).replace("MM",a).replace("YYYY",String(o)).replace("HH",i).replace("mm",u)}export function formatDuration(t){const e=Math.floor(t/3600),r=Math.floor(t%3600/60),n=t%60;return e>0?`${e}h ${r}m ${n}s`:r>0?`${r}m ${n}s`:`${n}s`}export function debounce(t,e){let r;return(...n)=>{clearTimeout(r),r=setTimeout(()=>t(...n),e)}}export function truncate(t,e){return t.length<=e?t:`${t.slice(0,e)}...`}export function getInitials(t){return t.split(" ").map(t=>t[0]).join("").toUpperCase().slice(0,2)}export function formatNumber(t){return t.toString().replace(/\B(?=(\d{3})+(?!\d))/g,",")}export function calculatePercentage(t,e){return 0===e?0:Math.round(t/e*100)}export function formatDateTimeVN(t,e="DD/MM/YYYY HH:mm"){if(!t)return"";try{const r=new Date(t);if(isNaN(r.getTime()))return"Invalid Date";const n=new Date(r.getTime()+252e5),a=String(n.getUTCDate()).padStart(2,"0"),o=String(n.getUTCMonth()+1).padStart(2,"0"),i=n.getUTCFullYear(),u=String(n.getUTCHours()).padStart(2,"0"),c=String(n.getUTCMinutes()).padStart(2,"0");return e.replace("DD",a).replace("MM",o).replace("YYYY",String(i)).replace("HH",u).replace("mm",c)}catch{return"Invalid Date"}}export function formatTimeVN(t){return formatDateTimeVN(t,"HH:mm")}export function formatDateVN(t){return formatDateTimeVN(t,"DD/MM/YYYY")}export function getDateInputValue(t){if(!t)return"";try{const e=new Date(t);if(isNaN(e.getTime()))return"";const r=new Date(e.getTime()+252e5),n=r.getUTCFullYear(),a=String(r.getUTCMonth()+1).padStart(2,"0");return`${n}-${a}-${String(r.getUTCDate()).padStart(2,"0")}`}catch{return""}}export function getTimeInputValue(t){return formatTimeVN(t)}export function cleanPayload(t){return Object.fromEntries(Object.entries(t).filter(([,t])=>void 0!==t&&""!==t&&null!==t))}