@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,111 +1 @@
1
- import { z } from 'zod';
2
- // Validation schema for Choose the Correct Answer form
3
- export const chooseCorrectAnswerFormSchema = z.object({
4
- question: z.string().optional(),
5
- optionType: z.enum(['text', 'image']).default('text'),
6
- options: z
7
- .array(z.string())
8
- .min(2, 'Phải có ít nhất 2 đáp án!'),
9
- correctAnswer: z.union([z.number(), z.array(z.number())]).default(-1),
10
- multipleAnswers: z.boolean().default(false),
11
- imageUrl: z.string().optional(),
12
- explanation: z.string().optional(),
13
- askerName: z.string().optional(),
14
- answererName: z.string().optional(),
15
- isExample: z.boolean().default(false),
16
- points: z
17
- .union([z.string(), z.number()])
18
- .transform((val, ctx) => {
19
- if (val === '' || val === undefined || val === null) {
20
- ctx.addIssue({
21
- code: z.ZodIssueCode.custom,
22
- message: 'Vui lòng nhập điểm số!',
23
- });
24
- return z.NEVER;
25
- }
26
- const num = typeof val === 'string' ? parseInt(val, 10) : val;
27
- if (isNaN(num)) {
28
- ctx.addIssue({
29
- code: z.ZodIssueCode.custom,
30
- message: 'Vui lòng nhập điểm số hợp lệ!',
31
- });
32
- return z.NEVER;
33
- }
34
- return num;
35
- })
36
- .pipe(z.number().min(1, 'Điểm số phải >= 1')),
37
- }).superRefine((data, ctx) => {
38
- const filledOptions = data.options.filter((opt) => opt.trim() !== '');
39
- if (filledOptions.length < 2) {
40
- ctx.addIssue({
41
- code: z.ZodIssueCode.custom,
42
- message: data.optionType === 'image'
43
- ? 'Phải upload ít nhất 2 hình ảnh đáp án!'
44
- : 'Phải có ít nhất 2 đáp án được điền!',
45
- path: ['options'],
46
- });
47
- }
48
- // Validate each option based on type
49
- data.options.forEach((opt, index) => {
50
- if (opt.trim() === '') {
51
- ctx.addIssue({
52
- code: z.ZodIssueCode.custom,
53
- message: data.optionType === 'image'
54
- ? 'Vui lòng upload hình ảnh!'
55
- : 'Vui lòng nhập đáp án!',
56
- path: ['options', index],
57
- });
58
- }
59
- });
60
- if (data.multipleAnswers) {
61
- const answers = Array.isArray(data.correctAnswer)
62
- ? data.correctAnswer
63
- : data.correctAnswer === -1
64
- ? []
65
- : [data.correctAnswer];
66
- if (answers.length === 0) {
67
- ctx.addIssue({
68
- code: z.ZodIssueCode.custom,
69
- message: 'Vui lòng chọn ít nhất 1 đáp án đúng!',
70
- path: ['correctAnswer'],
71
- });
72
- return;
73
- }
74
- const normalizedAnswers = [...new Set(answers)];
75
- if (normalizedAnswers.length !== answers.length) {
76
- ctx.addIssue({
77
- code: z.ZodIssueCode.custom,
78
- message: 'Đáp án đúng không được trùng lặp!',
79
- path: ['correctAnswer'],
80
- });
81
- }
82
- normalizedAnswers.forEach((answer) => {
83
- if (answer < 0 || answer >= data.options.length) {
84
- ctx.addIssue({
85
- code: z.ZodIssueCode.custom,
86
- message: 'Đáp án đúng không hợp lệ!',
87
- path: ['correctAnswer'],
88
- });
89
- }
90
- });
91
- return;
92
- }
93
- const singleAnswer = Array.isArray(data.correctAnswer)
94
- ? (data.correctAnswer[0] ?? -1)
95
- : data.correctAnswer;
96
- if (singleAnswer === -1) {
97
- ctx.addIssue({
98
- code: z.ZodIssueCode.custom,
99
- message: 'Vui lòng chọn đáp án đúng!',
100
- path: ['correctAnswer'],
101
- });
102
- return;
103
- }
104
- if (singleAnswer < 0 || singleAnswer >= data.options.length) {
105
- ctx.addIssue({
106
- code: z.ZodIssueCode.custom,
107
- message: 'Đáp án đúng không hợp lệ!',
108
- path: ['correctAnswer'],
109
- });
110
- }
111
- });
1
+ import{z as e}from"zod";export const chooseCorrectAnswerFormSchema=e.object({question:e.string().optional(),optionType:e.enum(["text","image"]).default("text"),options:e.array(e.string()).min(2,"Phải ít nhất 2 đáp án!"),correctAnswer:e.union([e.number(),e.array(e.number())]).default(-1),multipleAnswers:e.boolean().default(!1),imageUrl:e.string().optional(),explanation:e.string().optional(),askerName:e.string().optional(),answererName:e.string().optional(),isExample:e.boolean().default(!1),points:e.union([e.string(),e.number()]).transform((s,n)=>{if(""===s||null==s)return n.addIssue({code:e.ZodIssueCode.custom,message:"Vui lòng nhập điểm số!"}),e.NEVER;const o="string"==typeof s?parseInt(s,10):s;return isNaN(o)?(n.addIssue({code:e.ZodIssueCode.custom,message:"Vui lòng nhập điểm số hợp lệ!"}),e.NEVER):o}).pipe(e.number().min(1,"Điểm số phải >= 1"))}).superRefine((s,n)=>{if(s.options.filter(e=>""!==e.trim()).length<2&&n.addIssue({code:e.ZodIssueCode.custom,message:"image"===s.optionType?"Phải upload ít nhất 2 hình ảnh đáp án!":"Phải có ít nhất 2 đáp án được điền!",path:["options"]}),s.options.forEach((o,t)=>{""===o.trim()&&n.addIssue({code:e.ZodIssueCode.custom,message:"image"===s.optionType?"Vui lòng upload hình ảnh!":"Vui lòng nhập đáp án!",path:["options",t]})}),s.multipleAnswers){const o=Array.isArray(s.correctAnswer)?s.correctAnswer:-1===s.correctAnswer?[]:[s.correctAnswer];if(0===o.length)return void n.addIssue({code:e.ZodIssueCode.custom,message:"Vui lòng chọn ít nhất 1 đáp án đúng!",path:["correctAnswer"]});const t=[...new Set(o)];return t.length!==o.length&&n.addIssue({code:e.ZodIssueCode.custom,message:"Đáp án đúng không được trùng lặp!",path:["correctAnswer"]}),void t.forEach(o=>{(o<0||o>=s.options.length)&&n.addIssue({code:e.ZodIssueCode.custom,message:"Đáp án đúng không hợp lệ!",path:["correctAnswer"]})})}const o=Array.isArray(s.correctAnswer)?s.correctAnswer[0]??-1:s.correctAnswer;-1!==o?(o<0||o>=s.options.length)&&n.addIssue({code:e.ZodIssueCode.custom,message:"Đáp án đúng không hợp lệ!",path:["correctAnswer"]}):n.addIssue({code:e.ZodIssueCode.custom,message:"Vui lòng chọn đáp án đúng!",path:["correctAnswer"]})});
@@ -1,19 +1 @@
1
- import { z } from 'zod';
2
- // Label position validation schema
3
- const labelPositionSchema = z.object({
4
- id: z.string(),
5
- number: z.number().min(1, 'Số thứ tự phải >= 1'),
6
- correctAnswer: z.string().min(1, 'Vui lòng chọn đáp án đúng!'),
7
- isPreFilled: z.boolean().optional(),
8
- });
9
- // Main form validation schema for Label the Picture
10
- export const labelThePictureFormSchema = z.object({
11
- imageUrl: z.string().min(1, 'Vui lòng upload hình ảnh!'),
12
- wordBank: z
13
- .array(z.string().min(1, 'Vui lòng nhập nội dung từ!'))
14
- .min(1, 'Vui lòng thêm ít nhất một từ vào word bank!')
15
- .refine((words) => words.every((word) => word.trim() !== ''), { message: 'Tất cả các từ trong word bank phải có giá trị!' }),
16
- labels: z
17
- .array(labelPositionSchema)
18
- .min(1, 'Vui lòng thêm ít nhất một vị trí cần điền!'),
19
- });
1
+ import{z as n}from"zod";const t=n.object({id:n.string(),number:n.number().min(1,"Số thứ tự phải >= 1"),correctAnswer:n.string().min(1,"Vui lòng chọn đáp án đúng!"),isPreFilled:n.boolean().optional()});export const labelThePictureFormSchema=n.object({imageUrl:n.string().min(1,"Vui lòng upload hình ảnh!"),wordBank:n.array(n.string().min(1,"Vui lòng nhập nội dung từ!")).min(1,"Vui lòng thêm ít nhất một từ vào word bank!").refine(n=>n.every(n=>""!==n.trim()),{message:"Tất cả các từ trong word bank phải có giá trị!"}),labels:n.array(t).min(1,"Vui lòng thêm ít nhất một vị trí cần điền!")});
@@ -1,46 +1 @@
1
- import { z } from 'zod';
2
- /**
3
- * LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP validation schema.
4
- * Single question format:
5
- * - options: at least 2 options, each with image (required) and label (optional)
6
- * - audioUrl: audio file for the question
7
- * - correctAnswer: index of the correct option
8
- */
9
- export const listenAndChooseFromAnswerGroupOptionSchema = z.object({
10
- id: z.string(),
11
- imageUrl: z.string().min(1, 'Vui lòng upload ảnh cho đáp án!'),
12
- label: z.string().optional(),
13
- });
14
- export const listenAndChooseFromAnswerGroupFormSchema = z.object({
15
- options: z
16
- .array(listenAndChooseFromAnswerGroupOptionSchema)
17
- .min(2, 'Cần tối thiểu 2 đáp án trong nhóm!'),
18
- audioUrl: z.string().min(1, 'Vui lòng upload file audio!'),
19
- correctAnswer: z.string().min(1, 'Vui lòng chọn đáp án đúng!').refine((val) => val !== '-1', {
20
- message: 'Vui lòng chọn đáp án đúng!',
21
- }),
22
- points: z
23
- .union([z.string(), z.number()])
24
- .transform((val, ctx) => {
25
- if (val === '' || val === undefined || val === null) {
26
- ctx.addIssue({
27
- code: z.ZodIssueCode.custom,
28
- message: 'Vui lòng nhập điểm!',
29
- });
30
- return z.NEVER;
31
- }
32
- const num = typeof val === 'string' ? parseInt(val, 10) : val;
33
- if (isNaN(num)) {
34
- ctx.addIssue({
35
- code: z.ZodIssueCode.custom,
36
- message: 'Vui lòng nhập điểm hợp lệ!',
37
- });
38
- return z.NEVER;
39
- }
40
- return num;
41
- })
42
- .pipe(z.number().min(1, 'Điểm phải >= 1'))
43
- .optional(),
44
- explanation: z.string().optional(),
45
- isBackup: z.boolean().optional(),
46
- });
1
+ import{z as n}from"zod";export const listenAndChooseFromAnswerGroupOptionSchema=n.object({id:n.string(),imageUrl:n.string().min(1,"Vui lòng upload ảnh cho đáp án!"),label:n.string().optional()});export const listenAndChooseFromAnswerGroupFormSchema=n.object({options:n.array(listenAndChooseFromAnswerGroupOptionSchema).min(2,"Cần tối thiểu 2 đáp án trong nhóm!"),audioUrl:n.string().min(1,"Vui lòng upload file audio!"),correctAnswer:n.string().min(1,"Vui lòng chọn đáp án đúng!").refine(n=>"-1"!==n,{message:"Vui lòng chọn đáp án đúng!"}),points:n.union([n.string(),n.number()]).transform((o,i)=>{if(""===o||null==o)return i.addIssue({code:n.ZodIssueCode.custom,message:"Vui lòng nhập điểm!"}),n.NEVER;const e="string"==typeof o?parseInt(o,10):o;return isNaN(e)?(i.addIssue({code:n.ZodIssueCode.custom,message:"Vui lòng nhập điểm hợp lệ!"}),n.NEVER):e}).pipe(n.number().min(1,"Điểm phải >= 1")).optional(),explanation:n.string().optional(),isBackup:n.boolean().optional()});
@@ -1,21 +1 @@
1
- import { z } from 'zod';
2
- // Scene object node schema
3
- const sceneObjectNodeSchema = z.object({
4
- id: z.string(),
5
- imageUrl: z.string().min(1, 'Vui lòng upload hình ảnh đối tượng!'),
6
- label: z.string().min(1, 'Vui lòng nhập tên đối tượng!'),
7
- x: z.number().min(0).max(100),
8
- y: z.number().min(0).max(100),
9
- width: z.number().min(1, 'Chiều rộng phải lớn hơn 0!').max(100),
10
- height: z.number().min(1, 'Chiều cao phải lớn hơn 0!').max(100),
11
- });
12
- // Main form validation schema for Listen and Choose Objects in Scene
13
- export const listenAndChooseObjectsInSceneFormSchema = z.object({
14
- audioUrl: z.string().min(1, 'Vui lòng upload file audio!'),
15
- backgroundImageUrl: z.string().min(1, 'Vui lòng upload ảnh nền!'),
16
- objectNodes: z
17
- .array(sceneObjectNodeSchema)
18
- .min(2, 'Vui lòng thêm ít nhất 2 đối tượng!'),
19
- correctObjectId: z.string().min(1, 'Vui lòng chọn đáp án đúng!'),
20
- isBackup: z.boolean().optional(),
21
- });
1
+ import{z as n}from"zod";const i=n.object({id:n.string(),imageUrl:n.string().min(1,"Vui lòng upload hình ảnh đối tượng!"),label:n.string().min(1,"Vui lòng nhập tên đối tượng!"),x:n.number().min(0).max(100),y:n.number().min(0).max(100),width:n.number().min(1,"Chiều rộng phải lớn hơn 0!").max(100),height:n.number().min(1,"Chiều cao phải lớn hơn 0!").max(100)});export const listenAndChooseObjectsInSceneFormSchema=n.object({audioUrl:n.string().min(1,"Vui lòng upload file audio!"),backgroundImageUrl:n.string().min(1,"Vui lòng upload ảnh nền!"),objectNodes:n.array(i).min(2,"Vui lòng thêm ít nhất 2 đối tượng!"),correctObjectId:n.string().min(1,"Vui lòng chọn đáp án đúng!"),isBackup:n.boolean().optional()});
@@ -1,34 +1 @@
1
- import { z } from 'zod';
2
- // Drag object node schema (sidebar objects - no position)
3
- const dragObjectNodeSchema = z.object({
4
- id: z.string(),
5
- imageUrl: z.string().min(1, 'Vui lòng upload hình ảnh đối tượng!'),
6
- label: z.string().min(1, 'Vui lòng nhập tên đối tượng!'),
7
- });
8
- // Drop zone schema (positioned on scene)
9
- const dropZoneSchema = z.object({
10
- id: z.string(),
11
- label: z.string().min(1, 'Vui lòng nhập nhãn vùng thả!'),
12
- x: z.number().min(0).max(100),
13
- y: z.number().min(0).max(100),
14
- width: z.number().min(1, 'Chiều rộng phải lớn hơn 0!').max(100),
15
- height: z.number().min(1, 'Chiều cao phải lớn hơn 0!').max(100),
16
- });
17
- // Main form validation schema for Listen and Drag Objects into Scene
18
- export const listenAndDragObjectsIntoSceneFormSchema = z.object({
19
- audioUrl: z.string().min(1, 'Vui lòng upload file audio!'),
20
- backgroundImageUrl: z.string().min(1, 'Vui lòng upload ảnh nền!'),
21
- objectNodes: z
22
- .array(dragObjectNodeSchema)
23
- .min(2, 'Vui lòng thêm ít nhất 2 đối tượng!'),
24
- dropZones: z
25
- .array(dropZoneSchema)
26
- .min(1, 'Vui lòng thêm ít nhất 1 vùng thả!'),
27
- correctObjectId: z.string().min(1, 'Vui lòng chọn đối tượng đúng!').refine((val) => val !== '-1', {
28
- message: 'Vui lòng chọn đối tượng đúng!',
29
- }),
30
- correctDropZoneId: z.string().min(1, 'Vui lòng chọn vùng thả đúng!').refine((val) => val !== '-1', {
31
- message: 'Vui lòng chọn vùng thả đúng!',
32
- }),
33
- isBackup: z.boolean().optional(),
34
- });
1
+ import{z as n}from"zod";const i=n.object({id:n.string(),imageUrl:n.string().min(1,"Vui lòng upload hình ảnh đối tượng!"),label:n.string().min(1,"Vui lòng nhập tên đối tượng!")}),t=n.object({id:n.string(),label:n.string().min(1,"Vui lòng nhập nhãn vùng thả!"),x:n.number().min(0).max(100),y:n.number().min(0).max(100),width:n.number().min(1,"Chiều rộng phải lớn hơn 0!").max(100),height:n.number().min(1,"Chiều cao phải lớn hơn 0!").max(100)});export const listenAndDragObjectsIntoSceneFormSchema=n.object({audioUrl:n.string().min(1,"Vui lòng upload file audio!"),backgroundImageUrl:n.string().min(1,"Vui lòng upload ảnh nền!"),objectNodes:n.array(i).min(2,"Vui lòng thêm ít nhất 2 đối tượng!"),dropZones:n.array(t).min(1,"Vui lòng thêm ít nhất 1 vùng thả!"),correctObjectId:n.string().min(1,"Vui lòng chọn đối tượng đúng!").refine(n=>"-1"!==n,{message:"Vui lòng chọn đối tượng đúng!"}),correctDropZoneId:n.string().min(1,"Vui lòng chọn vùng thả đúng!").refine(n=>"-1"!==n,{message:"Vui lòng chọn vùng thả đúng!"}),isBackup:n.boolean().optional()});
@@ -1,40 +1 @@
1
- import { z } from 'zod';
2
- export const listenAndSpeakAnswerFormSchema = z.object({
3
- audioUrl: z.string().min(1, 'Vui lòng upload file audio!'),
4
- expectedAnswers: z
5
- .array(z.string().min(1, 'Vui lòng nhập đáp án!'))
6
- .min(1, 'Cần tối thiểu 1 đáp án!')
7
- .refine((options) => options.filter((opt) => opt.trim() !== '').length >= 1, { message: 'Cần tối thiểu 1 đáp án hợp lệ!' }),
8
- explanation: z.string().optional(),
9
- points: z
10
- .union([z.string(), z.number()])
11
- .transform((val, ctx) => {
12
- if (val === '' || val === undefined || val === null) {
13
- ctx.addIssue({
14
- code: z.ZodIssueCode.custom,
15
- message: 'Vui lòng nhập điểm!',
16
- });
17
- return z.NEVER;
18
- }
19
- const num = typeof val === 'string' ? parseInt(val, 10) : val;
20
- if (isNaN(num)) {
21
- ctx.addIssue({
22
- code: z.ZodIssueCode.custom,
23
- message: 'Vui lòng nhập điểm hợp lệ!',
24
- });
25
- return z.NEVER;
26
- }
27
- return num;
28
- })
29
- .pipe(z.number().min(1, 'Điểm số phải >= 1')),
30
- backgroundImageUrl: z.string().optional(),
31
- arrowNode: z
32
- .object({
33
- x: z.number(),
34
- y: z.number(),
35
- width: z.number(),
36
- height: z.number(),
37
- })
38
- .optional(),
39
- isBackup: z.boolean().optional(),
40
- });
1
+ import{z as n}from"zod";export const listenAndSpeakAnswerFormSchema=n.object({audioUrl:n.string().min(1,"Vui lòng upload file audio!"),expectedAnswers:n.array(n.string().min(1,"Vui lòng nhập đáp án!")).min(1,"Cần tối thiểu 1 đáp án!").refine(n=>n.filter(n=>""!==n.trim()).length>=1,{message:"Cần tối thiểu 1 đáp án hợp lệ!"}),explanation:n.string().optional(),points:n.union([n.string(),n.number()]).transform((e,i)=>{if(""===e||null==e)return i.addIssue({code:n.ZodIssueCode.custom,message:"Vui lòng nhập điểm!"}),n.NEVER;const o="string"==typeof e?parseInt(e,10):e;return isNaN(o)?(i.addIssue({code:n.ZodIssueCode.custom,message:"Vui lòng nhập điểm hợp lệ!"}),n.NEVER):o}).pipe(n.number().min(1,"Điểm số phải >= 1")),backgroundImageUrl:n.string().optional(),arrowNode:n.object({x:n.number(),y:n.number(),width:n.number(),height:n.number()}).optional(),isBackup:n.boolean().optional()});
@@ -1,45 +1 @@
1
- import { z } from 'zod';
2
- // Shared config for point validation
3
- const pointsValidation = z
4
- .union([z.string(), z.number()])
5
- .transform((val, ctx) => {
6
- if (val === '' || val === undefined || val === null) {
7
- ctx.addIssue({
8
- code: z.ZodIssueCode.custom,
9
- message: 'Vui lòng nhập điểm!',
10
- });
11
- return z.NEVER;
12
- }
13
- const num = typeof val === 'string' ? parseInt(val, 10) : val;
14
- if (isNaN(num)) {
15
- ctx.addIssue({
16
- code: z.ZodIssueCode.custom,
17
- message: 'Điểm không hợp lệ!',
18
- });
19
- return z.NEVER;
20
- }
21
- return num;
22
- })
23
- .pipe(z.number().min(1, 'Điểm tối thiểu là 1'));
24
- // Shared validation for the group (Only the first question handles this validation if group doesn't exist yet)
25
- export const compareImagesGroupSchema = z.object({
26
- candidateImageUrl: z.string().min(1, "Vui lòng tải lên Candidate's Copy Image!"),
27
- examinerImageUrl: z.string().min(1, "Vui lòng tải lên Examiner's Copy Image!"),
28
- });
29
- // Validation for the actual question form data
30
- export const listenAndSpeakCompareImagesSchema = z.object({
31
- // Group fields (only visible/required if it's the first question)
32
- candidateImageUrl: z.string().optional(),
33
- examinerImageUrl: z.string().optional(),
34
- // Individual fields
35
- audioUrl: z.string({
36
- message: "Vui lòng tải lên File Audio câu hỏi!",
37
- }).min(1, 'Vui lòng tải lên File Audio câu hỏi!'),
38
- expectedAnswers: z
39
- .array(z.string().min(1, 'Vui lòng điền đáp án!'))
40
- .min(1, 'Phải có ít nhất 1 đáp án mong muốn!')
41
- .refine((options) => options.filter((opt) => opt.trim() !== '').length >= 1, { message: 'Phải điền ít nhất 1 đáp án hợp lệ!' }),
42
- explanation: z.string().optional(),
43
- points: pointsValidation,
44
- isBackup: z.boolean().optional(),
45
- });
1
+ import{z as n}from"zod";const i=n.union([n.string(),n.number()]).transform((i,e)=>{if(""===i||null==i)return e.addIssue({code:n.ZodIssueCode.custom,message:"Vui lòng nhập điểm!"}),n.NEVER;const t="string"==typeof i?parseInt(i,10):i;return isNaN(t)?(e.addIssue({code:n.ZodIssueCode.custom,message:"Điểm không hợp lệ!"}),n.NEVER):t}).pipe(n.number().min(1,"Điểm tối thiểu là 1"));export const compareImagesGroupSchema=n.object({candidateImageUrl:n.string().min(1,"Vui lòng tải lên Candidate's Copy Image!"),examinerImageUrl:n.string().min(1,"Vui lòng tải lên Examiner's Copy Image!")});export const listenAndSpeakCompareImagesSchema=n.object({candidateImageUrl:n.string().optional(),examinerImageUrl:n.string().optional(),audioUrl:n.string({message:"Vui lòng tải lên File Audio câu hỏi!"}).min(1,"Vui lòng tải lên File Audio câu hỏi!"),expectedAnswers:n.array(n.string().min(1,"Vui lòng điền đáp án!")).min(1,"Phải có ít nhất 1 đáp án mong muốn!").refine(n=>n.filter(n=>""!==n.trim()).length>=1,{message:"Phải điền ít nhất 1 đáp án hợp lệ!"}),explanation:n.string().optional(),points:i,isBackup:n.boolean().optional()});
@@ -1,19 +1 @@
1
- import { z } from 'zod';
2
- export const groupImageItemSchema = z.object({
3
- id: z.string(),
4
- url: z.string().min(1, 'Vui lòng cung cấp link hình ảnh'),
5
- label: z.string().min(1, 'Vui lòng nhập nhãn cho hình ảnh'),
6
- });
7
- export const listenAndSpeakImageGroupFormSchema = z.object({
8
- audioUrl: z.string({
9
- message: 'Vui lòng tải lên file âm thanh',
10
- }).min(1, 'Vui lòng tải lên file âm thanh'),
11
- expectedAnswers: z.array(z.string().min(1, 'Câu trả lời không được để trống'))
12
- .min(1, 'Cần ít nhất một câu trả lời khả thi'),
13
- explanation: z.string().optional(),
14
- points: z.number().min(0.1, 'Điểm số phải lớn hơn 0'),
15
- activeImageId: z.string().min(1, 'Vui lòng chọn hình ảnh cần hỏi').optional(),
16
- groupImages: z.array(groupImageItemSchema).min(1, 'Vui lòng thêm ít nhất một hình ảnh').optional(),
17
- groupNumber: z.number().optional(),
18
- isBackup: z.boolean().optional(),
19
- });
1
+ import{z as n}from"zod";export const groupImageItemSchema=n.object({id:n.string(),url:n.string().min(1,"Vui lòng cung cấp link hình ảnh"),label:n.string().min(1,"Vui lòng nhập nhãn cho hình ảnh")});export const listenAndSpeakImageGroupFormSchema=n.object({audioUrl:n.string({message:"Vui lòng tải lên file âm thanh"}).min(1,"Vui lòng tải lên file âm thanh"),expectedAnswers:n.array(n.string().min(1,"Câu trả lời không được để trống")).min(1,"Cần ít nhất một câu trả lời khả thi"),explanation:n.string().optional(),points:n.number().min(.1,"Điểm số phải lớn hơn 0"),activeImageId:n.string().min(1,"Vui lòng chọn hình ảnh cần hỏi").optional(),groupImages:n.array(groupImageItemSchema).min(1,"Vui lòng thêm ít nhất một hình ảnh").optional(),groupNumber:n.number().optional(),isBackup:n.boolean().optional()});
@@ -1,39 +1 @@
1
- import { z } from 'zod';
2
- export const infoExchangeFieldSchema = z.object({
3
- key: z.string().min(1, 'Câu hỏi không được để trống'),
4
- answer: z.string().min(1, 'Đáp án không được để trống'),
5
- });
6
- export const listenAndSpeakInfoExchangeSchema = z.object({
7
- // Group data
8
- title: z.string().min(1, 'Vui lòng nhập tiêu đề (VD: Katy\'s house)'),
9
- imageUrl: z.string().optional(),
10
- fields: z.array(infoExchangeFieldSchema).optional(), // DEPRECATED - backward compat
11
- candidateFields: z
12
- .array(infoExchangeFieldSchema)
13
- .min(1, 'Vui lòng thêm ít nhất 1 dòng cho Candidate\'s Copy'),
14
- examinerFields: z
15
- .array(infoExchangeFieldSchema)
16
- .min(1, 'Vui lòng thêm ít nhất 1 dòng cho Examiner\'s Copy'),
17
- // Per-question data
18
- audioUrl: z.string().min(1, 'Vui lòng tải lên file audio câu hỏi'),
19
- expectedAnswers: z
20
- .array(z.string().min(1, 'Đáp án không được để trống'))
21
- .min(1, 'Vui lòng nhập ít nhất 1 đáp án'),
22
- // Common
23
- explanation: z.string().optional(),
24
- points: z
25
- .union([z.string(), z.number()])
26
- .transform((val, ctx) => {
27
- if (val === '' || val === undefined || val === null) {
28
- ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Vui lòng nhập điểm' });
29
- return z.NEVER;
30
- }
31
- const num = typeof val === 'string' ? parseFloat(val) : val;
32
- if (isNaN(num)) {
33
- ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Điểm phải là số hợp lệ' });
34
- return z.NEVER;
35
- }
36
- return num;
37
- })
38
- .pipe(z.number().min(0.5, 'Điểm phải >= 0.5')),
39
- });
1
+ import{z as n}from"zod";export const infoExchangeFieldSchema=n.object({key:n.string().min(1,"Câu hỏi không được để trống"),answer:n.string().min(1,"Đáp án không được để trống")});export const listenAndSpeakInfoExchangeSchema=n.object({title:n.string().min(1,"Vui lòng nhập tiêu đề (VD: Katy's house)"),imageUrl:n.string().optional(),fields:n.array(infoExchangeFieldSchema).optional(),candidateFields:n.array(infoExchangeFieldSchema).min(1,"Vui lòng thêm ít nhất 1 dòng cho Candidate's Copy"),examinerFields:n.array(infoExchangeFieldSchema).min(1,"Vui lòng thêm ít nhất 1 dòng cho Examiner's Copy"),audioUrl:n.string().min(1,"Vui lòng tải lên file audio câu hỏi"),expectedAnswers:n.array(n.string().min(1,"Đáp án không được để trống")).min(1,"Vui lòng nhập ít nhất 1 đáp án"),explanation:n.string().optional(),points:n.union([n.string(),n.number()]).transform((i,e)=>{if(""===i||null==i)return e.addIssue({code:n.ZodIssueCode.custom,message:"Vui lòng nhập điểm"}),n.NEVER;const t="string"==typeof i?parseFloat(i):i;return isNaN(t)?(e.addIssue({code:n.ZodIssueCode.custom,message:"Điểm phải là số hợp lệ"}),n.NEVER):t}).pipe(n.number().min(.5,"Điểm phải >= 0.5"))});
@@ -1,32 +1 @@
1
- import { z } from 'zod';
2
- export const listenAndSpeakOddOneOutSchema = z.object({
3
- audioUrl: z.string().min(1, 'Vui lòng tải lên file audio câu hỏi'),
4
- images: z
5
- .array(z.string().min(1))
6
- .length(4, 'Phải có đúng 4 hình ảnh')
7
- .refine((imgs) => imgs.filter((img) => img.trim() !== '').length === 4, { message: 'Vui lòng tải đủ 4 hình ảnh' }),
8
- oddOneOutIndex: z
9
- .number({ message: 'Vui lòng chọn hình khác loại' })
10
- .min(0, 'Vui lòng chọn hình khác loại')
11
- .max(3, 'Chỉ số hình ảnh không hợp lệ'),
12
- expectedAnswers: z
13
- .array(z.string().min(1, 'Đáp án không được để trống'))
14
- .min(1, 'Vui lòng nhập ít nhất 1 đáp án mong muốn'),
15
- explanation: z.string().optional(),
16
- points: z
17
- .union([z.string(), z.number()])
18
- .transform((val, ctx) => {
19
- if (val === '' || val === undefined || val === null) {
20
- ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Vui lòng nhập điểm' });
21
- return z.NEVER;
22
- }
23
- const num = typeof val === 'string' ? parseFloat(val) : val;
24
- if (isNaN(num)) {
25
- ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Điểm phải là số hợp lệ' });
26
- return z.NEVER;
27
- }
28
- return num;
29
- })
30
- .pipe(z.number().min(0.5, 'Điểm phải >= 0.5')),
31
- isBackup: z.boolean().optional(),
32
- });
1
+ import{z as n}from"zod";export const listenAndSpeakOddOneOutSchema=n.object({audioUrl:n.string().min(1,"Vui lòng tải lên file audio câu hỏi"),images:n.array(n.string().min(1)).length(4,"Phải có đúng 4 hình ảnh").refine(n=>4===n.filter(n=>""!==n.trim()).length,{message:"Vui lòng tải đủ 4 hình ảnh"}),oddOneOutIndex:n.number({message:"Vui lòng chọn hình khác loại"}).min(0,"Vui lòng chọn hình khác loại").max(3,"Chỉ số hình ảnh không hợp lệ"),expectedAnswers:n.array(n.string().min(1,"Đáp án không được để trống")).min(1,"Vui lòng nhập ít nhất 1 đáp án mong muốn"),explanation:n.string().optional(),points:n.union([n.string(),n.number()]).transform((i,e)=>{if(""===i||null==i)return e.addIssue({code:n.ZodIssueCode.custom,message:"Vui lòng nhập điểm"}),n.NEVER;const s="string"==typeof i?parseFloat(i):i;return isNaN(s)?(e.addIssue({code:n.ZodIssueCode.custom,message:"Điểm phải là số hợp lệ"}),n.NEVER):s}).pipe(n.number().min(.5,"Điểm phải >= 0.5")),isBackup:n.boolean().optional()});
@@ -1,19 +1 @@
1
- import { z } from 'zod';
2
- export const listenAndSpeakQuestionListFormSchema = z.object({
3
- audioUrl: z.string({
4
- message: 'Vui lòng tải lên file âm thanh',
5
- }).min(1, 'Vui lòng tải lên file âm thanh'),
6
- activeQuestionId: z.string({
7
- message: 'Vui lòng chọn câu hỏi',
8
- }).min(1, 'Vui lòng chọn câu hỏi'),
9
- expectedAnswers: z.array(z.string().min(1, 'Vui lòng nhập đáp án')).min(1, 'Cần ít nhất 1 đáp án'),
10
- points: z.number().min(1, 'Điểm phải lớn hơn 0').default(1),
11
- explanation: z.string().optional().default(''),
12
- isBackup: z.boolean().optional(),
13
- });
14
- export const listenAndSpeakQuestionGroupSchema = z.object({
15
- questions: z.array(z.object({
16
- id: z.string(),
17
- text: z.string().min(1, 'Vui lòng nhập nội dung câu hỏi'),
18
- })).min(1, 'Cần ít nhất một câu hỏi'),
19
- });
1
+ import{z as n}from"zod";export const listenAndSpeakQuestionListFormSchema=n.object({audioUrl:n.string({message:"Vui lòng tải lên file âm thanh"}).min(1,"Vui lòng tải lên file âm thanh"),activeQuestionId:n.string({message:"Vui lòng chọn câu hỏi"}).min(1,"Vui lòng chọn câu hỏi"),expectedAnswers:n.array(n.string().min(1,"Vui lòng nhập đáp án")).min(1,"Cần ít nhất 1 đáp án"),points:n.number().min(1,"Điểm phải lớn hơn 0").default(1),explanation:n.string().optional().default(""),isBackup:n.boolean().optional()});export const listenAndSpeakQuestionGroupSchema=n.object({questions:n.array(n.object({id:n.string(),text:n.string().min(1,"Vui lòng nhập nội dung câu hỏi")})).min(1,"Cần ít nhất một câu hỏi")});
@@ -1,28 +1 @@
1
- import { z } from 'zod';
2
- export const listenAndSpeakWithStoryImagesSchema = z.object({
3
- audioUrl: z.string().min(1, 'Vui lòng tải lên file audio câu hỏi'),
4
- images: z
5
- .array(z.string().min(1))
6
- .min(1, 'Vui lòng tải lên ít nhất 1 hình ảnh')
7
- .refine((imgs) => imgs.filter((img) => img.trim() !== '').length >= 1, { message: 'Phải có ít nhất 1 hình ảnh hợp lệ' }),
8
- expectedAnswers: z
9
- .array(z.string().min(1, 'Đáp án không được để trống'))
10
- .min(1, 'Vui lòng nhập ít nhất 1 đáp án mong muốn'),
11
- explanation: z.string().optional(),
12
- points: z
13
- .union([z.string(), z.number()])
14
- .transform((val, ctx) => {
15
- if (val === '' || val === undefined || val === null) {
16
- ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Vui lòng nhập điểm' });
17
- return z.NEVER;
18
- }
19
- const num = typeof val === 'string' ? parseFloat(val) : val;
20
- if (isNaN(num)) {
21
- ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Điểm phải là số hợp lệ' });
22
- return z.NEVER;
23
- }
24
- return num;
25
- })
26
- .pipe(z.number().min(0.5, 'Điểm phải >= 0.5')),
27
- isBackup: z.boolean().optional(),
28
- });
1
+ import{z as n}from"zod";export const listenAndSpeakWithStoryImagesSchema=n.object({audioUrl:n.string().min(1,"Vui lòng tải lên file audio câu hỏi"),images:n.array(n.string().min(1)).min(1,"Vui lòng tải lên ít nhất 1 hình ảnh").refine(n=>n.filter(n=>""!==n.trim()).length>=1,{message:"Phải có ít nhất 1 hình ảnh hợp lệ"}),expectedAnswers:n.array(n.string().min(1,"Đáp án không được để trống")).min(1,"Vui lòng nhập ít nhất 1 đáp án mong muốn"),explanation:n.string().optional(),points:n.union([n.string(),n.number()]).transform((i,e)=>{if(""===i||null==i)return e.addIssue({code:n.ZodIssueCode.custom,message:"Vui lòng nhập điểm"}),n.NEVER;const t="string"==typeof i?parseFloat(i):i;return isNaN(t)?(e.addIssue({code:n.ZodIssueCode.custom,message:"Điểm phải là số hợp lệ"}),n.NEVER):t}).pipe(n.number().min(.5,"Điểm phải >= 0.5")),isBackup:n.boolean().optional()});
@@ -1,12 +1 @@
1
- import { z } from 'zod';
2
- // Main form validation schema - NEW flat structure
3
- // Same as LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER but without question field
4
- export const lookPictureChooseCorrectAnswerFormSchema = z.object({
5
- imageUrl: z.string().min(1, 'Vui lòng upload hình ảnh!'),
6
- options: z
7
- .array(z.string().min(1, 'Vui lòng nhập nội dung đáp án!'))
8
- .min(2, 'Phải có ít nhất 2 lựa chọn!'),
9
- correctAnswer: z.number(),
10
- explanation: z.string().optional(),
11
- points: z.number().min(0.5).optional(),
12
- });
1
+ import{z as n}from"zod";export const lookPictureChooseCorrectAnswerFormSchema=n.object({imageUrl:n.string().min(1,"Vui lòng upload hình ảnh!"),options:n.array(n.string().min(1,"Vui lòng nhập nội dung đáp án!")).min(2,"Phải có ít nhất 2 lựa chọn!"),correctAnswer:n.number(),explanation:n.string().optional(),points:n.number().min(.5).optional()});
@@ -1,47 +1 @@
1
- import { z } from 'zod';
2
- /**
3
- * Validation schema for LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER form
4
- *
5
- * Based on API payload structure:
6
- * - content: { imageUrl, question, options: string[] }
7
- * - correct_answer: { answer: number }
8
- */
9
- export const lookPictureFillBlankChooseAnswerFormSchema = z.object({
10
- imageUrl: z.string().min(1, 'Vui lòng upload hình ảnh!'),
11
- question: z
12
- .string()
13
- .min(1, 'Vui lòng nhập nội dung câu hỏi!')
14
- .refine((val) => val.includes('{0}'), {
15
- message: 'Câu hỏi phải chứa {0} để đánh dấu chỗ trống',
16
- })
17
- .refine((val) => (val.match(/\{0\}/g) || []).length <= 1, {
18
- message: 'Chỉ được có một {0} trong câu hỏi',
19
- }),
20
- options: z
21
- .array(z.string().min(1, 'Vui lòng nhập đáp án!'))
22
- .min(2, 'Phải có ít nhất 2 đáp án!')
23
- .refine((options) => options.filter((opt) => opt.trim() !== '').length >= 2, { message: 'Phải có ít nhất 2 đáp án được điền!' }),
24
- correctAnswer: z.number().min(0, 'Vui lòng chọn đáp án đúng!'),
25
- explanation: z.string().optional(),
26
- points: z
27
- .union([z.string(), z.number()])
28
- .transform((val, ctx) => {
29
- if (val === '' || val === undefined || val === null) {
30
- ctx.addIssue({
31
- code: z.ZodIssueCode.custom,
32
- message: 'Vui lòng nhập điểm số!',
33
- });
34
- return z.NEVER;
35
- }
36
- const num = typeof val === 'string' ? parseInt(val, 10) : val;
37
- if (isNaN(num)) {
38
- ctx.addIssue({
39
- code: z.ZodIssueCode.custom,
40
- message: 'Vui lòng nhập điểm số hợp lệ!',
41
- });
42
- return z.NEVER;
43
- }
44
- return num;
45
- })
46
- .pipe(z.number().min(1, 'Điểm số phải >= 1')),
47
- });
1
+ import{z as n}from"zod";export const lookPictureFillBlankChooseAnswerFormSchema=n.object({imageUrl:n.string().min(1,"Vui lòng upload hình ảnh!"),question:n.string().min(1,"Vui lòng nhập nội dung câu hỏi!").refine(n=>n.includes("{0}"),{message:"Câu hỏi phải chứa {0} để đánh dấu chỗ trống"}).refine(n=>(n.match(/\{0\}/g)||[]).length<=1,{message:"Chỉ được có một {0} trong câu hỏi"}),options:n.array(n.string().min(1,"Vui lòng nhập đáp án!")).min(2,"Phải có ít nhất 2 đáp án!").refine(n=>n.filter(n=>""!==n.trim()).length>=2,{message:"Phải có ít nhất 2 đáp án được điền!"}),correctAnswer:n.number().min(0,"Vui lòng chọn đáp án đúng!"),explanation:n.string().optional(),points:n.union([n.string(),n.number()]).transform((i,e)=>{if(""===i||null==i)return e.addIssue({code:n.ZodIssueCode.custom,message:"Vui lòng nhập điểm số!"}),n.NEVER;const s="string"==typeof i?parseInt(i,10):i;return isNaN(s)?(e.addIssue({code:n.ZodIssueCode.custom,message:"Vui lòng nhập điểm số hợp lệ!"}),n.NEVER):s}).pipe(n.number().min(1,"Điểm số phải >= 1"))});
@@ -1,29 +1 @@
1
- import { z } from 'zod';
2
- // Color node schema
3
- const colorNodeSchema = z.object({
4
- id: z.string(),
5
- color: z.string().min(1, 'Vui lòng chọn màu!'),
6
- label: z.string().optional(), // Optional label (e.g. "Tom", "Apple") for IMAGE_OBJECT_MATCHING
7
- });
8
- // Color region node schema
9
- const colorRegionNodeSchema = z.object({
10
- id: z.string(),
11
- x: z.number(),
12
- y: z.number(),
13
- width: z.number().optional(),
14
- height: z.number().optional(),
15
- color: z.string().optional(),
16
- linkedColorNodeId: z.string().optional(),
17
- });
18
- // Main form validation schema for Read and Color Objects
19
- export const readAndColorObjectsFormSchema = z.object({
20
- backgroundImageUrl: z.string().min(1, 'Vui lòng upload ảnh nền!'),
21
- colorNodes: z.array(colorNodeSchema).min(1, 'Vui lòng thêm ít nhất một màu!'),
22
- regionNodes: z
23
- .array(colorRegionNodeSchema)
24
- .min(1, 'Vui lòng thêm ít nhất một vùng tô màu!')
25
- .refine((regions) => regions.every((r) => r.linkedColorNodeId && r.linkedColorNodeId.trim() !== ''), { message: 'Tất cả các vùng phải được liên kết với màu!' }),
26
- instructions: z
27
- .array(z.string().min(1, 'Vui lòng nhập hướng dẫn!'))
28
- .min(1, 'Vui lòng thêm ít nhất một hướng dẫn!'),
29
- });
1
+ import{z as n}from"zod";const o=n.object({id:n.string(),color:n.string().min(1,"Vui lòng chọn màu!"),label:n.string().optional()}),i=n.object({id:n.string(),x:n.number(),y:n.number(),width:n.number().optional(),height:n.number().optional(),color:n.string().optional(),linkedColorNodeId:n.string().optional()});export const readAndColorObjectsFormSchema=n.object({backgroundImageUrl:n.string().min(1,"Vui lòng upload ảnh nền!"),colorNodes:n.array(o).min(1,"Vui lòng thêm ít nhất một màu!"),regionNodes:n.array(i).min(1,"Vui lòng thêm ít nhất một vùng tô màu!").refine(n=>n.every(n=>n.linkedColorNodeId&&""!==n.linkedColorNodeId.trim()),{message:"Tất cả các vùng phải được liên kết với màu!"}),instructions:n.array(n.string().min(1,"Vui lòng nhập hướng dẫn!")).min(1,"Vui lòng thêm ít nhất một hướng dẫn!")});
@@ -1,28 +1 @@
1
- import { z } from 'zod';
2
- export const readDisplayedContentFormSchema = z.object({
3
- referenceText: z
4
- .string()
5
- .min(1, 'Vui lòng nhập đoạn văn bản cần đọc!'),
6
- explanation: z.string().optional(),
7
- points: z
8
- .union([z.string(), z.number()])
9
- .transform((val, ctx) => {
10
- if (val === '' || val === undefined || val === null) {
11
- ctx.addIssue({
12
- code: z.ZodIssueCode.custom,
13
- message: 'Vui lòng nhập điểm!',
14
- });
15
- return z.NEVER;
16
- }
17
- const num = typeof val === 'string' ? parseInt(val, 10) : val;
18
- if (isNaN(num)) {
19
- ctx.addIssue({
20
- code: z.ZodIssueCode.custom,
21
- message: 'Vui lòng nhập điểm hợp lệ!',
22
- });
23
- return z.NEVER;
24
- }
25
- return num;
26
- })
27
- .pipe(z.number().min(1, 'Điểm số phải >= 1')),
28
- });
1
+ import{z as n}from"zod";export const readDisplayedContentFormSchema=n.object({referenceText:n.string().min(1,"Vui lòng nhập đoạn văn bản cần đọc!"),explanation:n.string().optional(),points:n.union([n.string(),n.number()]).transform((e,s)=>{if(""===e||null==e)return s.addIssue({code:n.ZodIssueCode.custom,message:"Vui lòng nhập điểm!"}),n.NEVER;const o="string"==typeof e?parseInt(e,10):e;return isNaN(o)?(s.addIssue({code:n.ZodIssueCode.custom,message:"Vui lòng nhập điểm hợp lệ!"}),n.NEVER):o}).pipe(n.number().min(1,"Điểm số phải >= 1"))});