@tinyweb_dev/oe-exam-sdk 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (514) hide show
  1. package/dist/api/exam-create.js +1 -179
  2. package/dist/api/exam-create.types.js +1 -1
  3. package/dist/api/exam-questions.d.ts +1 -1
  4. package/dist/api/exam-questions.js +1 -98
  5. package/dist/api/exam-questions.types.d.ts +45 -1
  6. package/dist/api/exam-questions.types.js +1 -1
  7. package/dist/api/exam-taking.js +1 -73
  8. package/dist/api/exam-taking.types.js +1 -1
  9. package/dist/api/index.js +1 -6
  10. package/dist/api/result-review.js +1 -50
  11. package/dist/api/result-review.types.js +1 -1
  12. package/dist/components/CueCardEditor.js +1 -58
  13. package/dist/components/common/ResolvedImage.js +1 -15
  14. package/dist/components/exams/CompletionDialog.d.ts +8 -0
  15. package/dist/components/exams/CompletionDialog.js +1 -0
  16. package/dist/components/exams/CreateExamInfoForm.d.ts +4 -1
  17. package/dist/components/exams/CreateExamInfoForm.js +1 -35
  18. package/dist/components/exams/CreateExamPageContainer.d.ts +3 -0
  19. package/dist/components/exams/CreateExamPageContainer.js +1 -103
  20. package/dist/components/exams/ExamCreator.d.ts +9 -3
  21. package/dist/components/exams/ExamCreator.js +1 -89
  22. package/dist/components/exams/ExamPartTabs.d.ts +1 -1
  23. package/dist/components/exams/ExamPartTabs.js +1 -40
  24. package/dist/components/exams/ExamPreviewDialog.d.ts +20 -0
  25. package/dist/components/exams/ExamPreviewDialog.js +1 -0
  26. package/dist/components/exams/ExamQuestionGrid.d.ts +1 -1
  27. package/dist/components/exams/ExamQuestionGrid.js +1 -18
  28. package/dist/components/exams/ExamQuestionsPageContainer.d.ts +3 -0
  29. package/dist/components/exams/ExamQuestionsPageContainer.js +1 -90
  30. package/dist/components/exams/ExamViewDialog.d.ts +24 -0
  31. package/dist/components/exams/ExamViewDialog.js +1 -0
  32. package/dist/components/exams/PartAudioUploader.js +1 -9
  33. package/dist/components/exams/TemplateSelector.js +1 -66
  34. package/dist/components/exams/UnsavedChangesDialog.d.ts +8 -0
  35. package/dist/components/exams/UnsavedChangesDialog.js +1 -0
  36. package/dist/components/exams/api.d.ts +1 -1
  37. package/dist/components/exams/api.js +1 -3
  38. package/dist/components/exams/create-exam.texts.d.ts +58 -0
  39. package/dist/components/exams/create-exam.texts.js +1 -0
  40. package/dist/components/exams/create-exam.validation.js +1 -18
  41. package/dist/components/exams/exam-question-status.d.ts +9 -0
  42. package/dist/components/exams/exam-question-status.js +1 -0
  43. package/dist/components/exams/exam-template.utils.js +1 -18
  44. package/dist/components/exams/index.d.ts +11 -1
  45. package/dist/components/exams/index.js +1 -10
  46. package/dist/components/exams/take/ExamTakingPageContainer.js +1 -153
  47. package/dist/components/exams/take/GenericQuestionRenderer.js +1 -14
  48. package/dist/components/exams/take/exam-taking.utils.js +1 -88
  49. package/dist/components/exams/take/hooks/useSpeakingRecorder.js +1 -24
  50. package/dist/components/exams/take/index.js +1 -2
  51. package/dist/components/exams/take/types.js +1 -1
  52. package/dist/components/index.js +1 -42
  53. package/dist/components/questions/_shared/config/question-types.config.js +1 -333
  54. package/dist/components/questions/_shared/constants/color-palette.js +1 -21
  55. package/dist/components/questions/_shared/hooks/useAnswerGroupQuestionGroup.js +1 -105
  56. package/dist/components/questions/_shared/hooks/useBasicQuestionGroup.js +1 -222
  57. package/dist/components/questions/_shared/hooks/useCompareImagesGroup.js +1 -140
  58. package/dist/components/questions/_shared/hooks/useImageQuestionGroup.js +1 -123
  59. package/dist/components/questions/_shared/hooks/useInfoExchangeGroup.js +1 -50
  60. package/dist/components/questions/_shared/hooks/useQuestionFormState.js +1 -54
  61. package/dist/components/questions/_shared/hooks/useQuestionInitialization.js +1 -123
  62. package/dist/components/questions/_shared/hooks/useQuestionListGroup.js +1 -121
  63. package/dist/components/questions/_shared/hooks/useQuestionOnChange.js +1 -70
  64. package/dist/components/questions/_shared/hooks/useSceneQuestionGroup.js +1 -194
  65. package/dist/components/questions/_shared/index.js +1 -7
  66. package/dist/components/questions/_shared/types/answer-the-question.type.js +1 -1
  67. package/dist/components/questions/_shared/types/arrange-letters-into-words.type.js +1 -1
  68. package/dist/components/questions/_shared/types/choose-correct-adjective.type.js +1 -3
  69. package/dist/components/questions/_shared/types/color-region.config.js +1 -1
  70. package/dist/components/questions/_shared/types/fill-in-blank.type.js +1 -1
  71. package/dist/components/questions/_shared/types/fill-missing-words-in-grid.type.js +1 -1
  72. package/dist/components/questions/_shared/types/gn-speaking-interview.type.js +1 -1
  73. package/dist/components/questions/_shared/types/index.js +1 -12
  74. package/dist/components/questions/_shared/types/label-the-picture.type.js +1 -1
  75. package/dist/components/questions/_shared/types/listen-and-choose-from-answer-group.type.js +1 -1
  76. package/dist/components/questions/_shared/types/listen-and-choose-objects-in-scene.type.js +1 -1
  77. package/dist/components/questions/_shared/types/listen-and-drag-objects-into-scene.type.js +1 -1
  78. package/dist/components/questions/_shared/types/listen-and-speak-answer.type.js +1 -1
  79. package/dist/components/questions/_shared/types/listen-and-speak-compare-images.type.js +1 -1
  80. package/dist/components/questions/_shared/types/listen-and-speak-image-group.type.js +1 -1
  81. package/dist/components/questions/_shared/types/listen-and-speak-info-exchange.type.js +1 -1
  82. package/dist/components/questions/_shared/types/listen-and-speak-odd-one-out.type.js +1 -3
  83. package/dist/components/questions/_shared/types/listen-and-speak-question-list.type.js +1 -1
  84. package/dist/components/questions/_shared/types/listen-and-speak-with-story-images.type.js +1 -3
  85. package/dist/components/questions/_shared/types/listen-and-tick-answer.type.js +1 -1
  86. package/dist/components/questions/_shared/types/listening-drawline.type.js +1 -1
  87. package/dist/components/questions/_shared/types/look-and-choose-answer.type.js +1 -1
  88. package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.js +1 -1
  89. package/dist/components/questions/_shared/types/match-by-writing-answer.type.js +1 -1
  90. package/dist/components/questions/_shared/types/multiple-choice.type.js +1 -1
  91. package/dist/components/questions/_shared/types/question-group.type.js +1 -11
  92. package/dist/components/questions/_shared/types/read-and-color-objects.type.js +1 -1
  93. package/dist/components/questions/_shared/types/read-displayed-content.type.js +1 -1
  94. package/dist/components/questions/_shared/types/read-passage-and-answer-questions.type.js +1 -1
  95. package/dist/components/questions/_shared/types/speaking-describe-image.type.js +1 -1
  96. package/dist/components/questions/_shared/types/spontaneous-qa.type.js +1 -1
  97. package/dist/components/questions/_shared/types/word-fill-paragraph-with-options.type.js +1 -1
  98. package/dist/components/questions/_shared/types/word-fill-paragraph.type.js +1 -1
  99. package/dist/components/questions/_shared/types/word-fill-structured-form.type.js +1 -1
  100. package/dist/components/questions/_shared/types/word-ordering.type.js +1 -1
  101. package/dist/components/questions/_shared/types/write-a-short-letter.type.js +1 -1
  102. package/dist/components/questions/_shared/types/write-correct-verb-form.type.js +1 -3
  103. package/dist/components/questions/_shared/types/write-sentences.type.js +1 -1
  104. package/dist/components/questions/_shared/types/write-short-paragraph.type.js +1 -1
  105. package/dist/components/questions/_shared/utils/answer-builder.js +1 -79
  106. package/dist/components/questions/_shared/utils/createColorRegionRegistration.js +1 -39
  107. package/dist/components/questions/_shared/utils/id-generator.js +1 -3
  108. package/dist/components/questions/_shared/utils/question-validation.js +1 -21
  109. package/dist/components/questions/components/ColorNode.js +1 -85
  110. package/dist/components/questions/components/ColorRegionClient.js +1 -545
  111. package/dist/components/questions/components/ColorRegionCreator.js +1 -420
  112. package/dist/components/questions/components/ColorRegionNode.js +1 -59
  113. package/dist/components/questions/components/CreatorGuide.js +1 -103
  114. package/dist/components/questions/components/NameNode.js +1 -26
  115. package/dist/components/questions/components/QuestionBankOption.js +1 -46
  116. package/dist/components/questions/components/QuestionBasicInfoForm.js +1 -9
  117. package/dist/components/questions/components/QuestionCommonFields.js +1 -33
  118. package/dist/components/questions/components/QuestionSearchDropdown.js +1 -258
  119. package/dist/components/questions/components/QuestionTypeSelector.js +1 -32
  120. package/dist/components/questions/components/QuestionTypeSpecificForms.js +1 -6
  121. package/dist/components/questions/components/RegionNode.js +1 -94
  122. package/dist/components/questions/components/index.js +1 -14
  123. package/dist/components/questions/creator/QuestionCreator.js +1 -90
  124. package/dist/components/questions/creator/QuestionGroupCreator.js +1 -119
  125. package/dist/components/questions/creator/dedicated-component-router.js +1 -79
  126. package/dist/components/questions/creator/index.js +1 -3
  127. package/dist/components/questions/creator/question-type-registry.js +1 -80
  128. package/dist/components/questions/groups/ArticlesGroupCard.js +1 -121
  129. package/dist/components/questions/groups/BasicQuestionGroupCard.js +1 -50
  130. package/dist/components/questions/groups/DocumentGroupCard.js +1 -114
  131. package/dist/components/questions/groups/MatchAnswerGroupCard.js +1 -25
  132. package/dist/components/questions/index.js +1 -10
  133. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +1 -37
  134. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionCreator.js +1 -351
  135. package/dist/components/questions/types/answer-the-question/register.js +1 -67
  136. package/dist/components/questions/types/answer-the-question/transform.js +1 -36
  137. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +1 -141
  138. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsCreator.js +1 -118
  139. package/dist/components/questions/types/arrange-letters-into-words/index.js +1 -2
  140. package/dist/components/questions/types/arrange-letters-into-words/register.js +1 -4
  141. package/dist/components/questions/types/arrange-letters-into-words/transform.js +1 -24
  142. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +1 -64
  143. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js +1 -169
  144. package/dist/components/questions/types/choose-correct-adjective/index.js +1 -2
  145. package/dist/components/questions/types/choose-correct-adjective/register.js +1 -55
  146. package/dist/components/questions/types/choose-correct-adjective/transform.js +1 -16
  147. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +1 -131
  148. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +1 -581
  149. package/dist/components/questions/types/choose-the-correct-answer/index.js +1 -2
  150. package/dist/components/questions/types/choose-the-correct-answer/register.js +1 -101
  151. package/dist/components/questions/types/choose-the-correct-answer/transform.js +1 -43
  152. package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +1 -275
  153. package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +1 -448
  154. package/dist/components/questions/types/fill-in-blank/index.js +1 -2
  155. package/dist/components/questions/types/fill-in-blank/register.js +1 -138
  156. package/dist/components/questions/types/fill-in-blank/transform.js +1 -59
  157. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +1 -117
  158. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridCreator.js +1 -671
  159. package/dist/components/questions/types/fill-missing-words-in-grid/index.js +1 -2
  160. package/dist/components/questions/types/fill-missing-words-in-grid/register.js +1 -37
  161. package/dist/components/questions/types/fill-missing-words-in-grid/transform.js +1 -15
  162. package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.js +1 -262
  163. package/dist/components/questions/types/gn-speaking-interview/register.js +1 -121
  164. package/dist/components/questions/types/gn-speaking-interview/transform.js +1 -48
  165. package/dist/components/questions/types/image-object-matching/ImageObjectMatchingClient.js +1 -16
  166. package/dist/components/questions/types/image-object-matching/ImageObjectMatchingCreator.js +1 -27
  167. package/dist/components/questions/types/image-object-matching/index.js +1 -2
  168. package/dist/components/questions/types/image-object-matching/register.js +1 -3
  169. package/dist/components/questions/types/image-object-matching/transform.js +1 -2
  170. package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +1 -102
  171. package/dist/components/questions/types/label-the-picture/LabelThePictureCreator.js +1 -344
  172. package/dist/components/questions/types/label-the-picture/index.js +1 -2
  173. package/dist/components/questions/types/label-the-picture/register.js +1 -54
  174. package/dist/components/questions/types/label-the-picture/transform.js +1 -28
  175. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +1 -78
  176. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupCreator.js +1 -232
  177. package/dist/components/questions/types/listen-and-choose-from-answer-group/index.js +1 -2
  178. package/dist/components/questions/types/listen-and-choose-from-answer-group/register.js +1 -82
  179. package/dist/components/questions/types/listen-and-choose-from-answer-group/transform.js +1 -27
  180. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneClient.js +1 -70
  181. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneCreator.js +1 -386
  182. package/dist/components/questions/types/listen-and-choose-objects-in-scene/index.js +1 -2
  183. package/dist/components/questions/types/listen-and-choose-objects-in-scene/register.js +1 -100
  184. package/dist/components/questions/types/listen-and-choose-objects-in-scene/transform.js +1 -33
  185. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneClient.js +1 -106
  186. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneCreator.js +1 -457
  187. package/dist/components/questions/types/listen-and-drag-objects-into-scene/index.js +1 -2
  188. package/dist/components/questions/types/listen-and-drag-objects-into-scene/register.js +1 -110
  189. package/dist/components/questions/types/listen-and-drag-objects-into-scene/transform.js +1 -35
  190. package/dist/components/questions/types/listen-and-speak-answer/ArrowIndicator.js +1 -8
  191. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +1 -22
  192. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerCreator.js +1 -291
  193. package/dist/components/questions/types/listen-and-speak-answer/index.js +1 -2
  194. package/dist/components/questions/types/listen-and-speak-answer/register.js +1 -84
  195. package/dist/components/questions/types/listen-and-speak-answer/transform.js +1 -27
  196. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +1 -32
  197. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesCreator.js +1 -295
  198. package/dist/components/questions/types/listen-and-speak-compare-images/register.js +1 -79
  199. package/dist/components/questions/types/listen-and-speak-compare-images/transform.js +1 -27
  200. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +1 -34
  201. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupCreator.js +1 -285
  202. package/dist/components/questions/types/listen-and-speak-image-group/register.js +1 -81
  203. package/dist/components/questions/types/listen-and-speak-image-group/transform.js +1 -26
  204. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +1 -38
  205. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeCreator.js +1 -385
  206. package/dist/components/questions/types/listen-and-speak-info-exchange/register.js +1 -87
  207. package/dist/components/questions/types/listen-and-speak-info-exchange/transform.js +1 -32
  208. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +1 -26
  209. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutCreator.js +1 -247
  210. package/dist/components/questions/types/listen-and-speak-odd-one-out/register.js +1 -59
  211. package/dist/components/questions/types/listen-and-speak-odd-one-out/transform.js +1 -18
  212. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +1 -26
  213. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListCreator.js +1 -256
  214. package/dist/components/questions/types/listen-and-speak-question-list/register.js +1 -81
  215. package/dist/components/questions/types/listen-and-speak-question-list/transform.js +1 -26
  216. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +1 -26
  217. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesCreator.js +1 -230
  218. package/dist/components/questions/types/listen-and-speak-with-story-images/register.js +1 -56
  219. package/dist/components/questions/types/listen-and-speak-with-story-images/transform.js +1 -16
  220. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.js +1 -72
  221. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.js +1 -230
  222. package/dist/components/questions/types/look-picture-choose-correct-answer/index.js +1 -1
  223. package/dist/components/questions/types/look-picture-choose-correct-answer/register.js +1 -66
  224. package/dist/components/questions/types/look-picture-choose-correct-answer/transform.js +1 -42
  225. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.js +1 -96
  226. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.js +1 -238
  227. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.js +1 -2
  228. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.js +1 -76
  229. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.js +1 -19
  230. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.js +1 -134
  231. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.js +1 -617
  232. package/dist/components/questions/types/look-picture-fill-word-hint/index.js +1 -2
  233. package/dist/components/questions/types/look-picture-fill-word-hint/register.js +1 -82
  234. package/dist/components/questions/types/look-picture-fill-word-hint/transform.js +1 -29
  235. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +1 -38
  236. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerCreator.js +1 -359
  237. package/dist/components/questions/types/match-by-writing-answer/index.js +1 -3
  238. package/dist/components/questions/types/match-by-writing-answer/register.js +1 -58
  239. package/dist/components/questions/types/match-by-writing-answer/transform.js +1 -61
  240. package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsClient.js +1 -16
  241. package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsCreator.js +1 -23
  242. package/dist/components/questions/types/read-and-color-objects/index.js +1 -2
  243. package/dist/components/questions/types/read-and-color-objects/register.js +1 -3
  244. package/dist/components/questions/types/read-and-color-objects/transform.js +1 -36
  245. package/dist/components/questions/types/read-displayed-content/ReadDisplayedContentCreator.js +1 -125
  246. package/dist/components/questions/types/read-displayed-content/register.js +1 -64
  247. package/dist/components/questions/types/read-displayed-content/transform.js +1 -12
  248. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +1 -64
  249. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsCreator.js +1 -511
  250. package/dist/components/questions/types/read-passage-and-answer-questions/index.js +1 -2
  251. package/dist/components/questions/types/read-passage-and-answer-questions/register.js +1 -58
  252. package/dist/components/questions/types/read-passage-and-answer-questions/transform.js +1 -28
  253. package/dist/components/questions/types/speaking-conversation/SpeakingConversationCreator.js +1 -373
  254. package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +1 -41
  255. package/dist/components/questions/types/speaking-conversation/register.js +1 -110
  256. package/dist/components/questions/types/speaking-conversation/transform.js +1 -34
  257. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +1 -74
  258. package/dist/components/questions/types/speaking-cue-card/register.js +1 -52
  259. package/dist/components/questions/types/speaking-cue-card/transform.js +1 -12
  260. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +1 -10
  261. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageCreator.js +1 -161
  262. package/dist/components/questions/types/speaking-describe-image/index.js +1 -2
  263. package/dist/components/questions/types/speaking-describe-image/register.js +1 -69
  264. package/dist/components/questions/types/speaking-describe-image/transform.js +1 -16
  265. package/dist/components/questions/types/spontaneous-qa/SpontaneousQACreator.js +1 -234
  266. package/dist/components/questions/types/spontaneous-qa/register.js +1 -93
  267. package/dist/components/questions/types/spontaneous-qa/transform.js +1 -34
  268. package/dist/components/questions/types/true-false/TrueFalseClient.js +1 -75
  269. package/dist/components/questions/types/true-false/TrueFalseCreator.js +1 -244
  270. package/dist/components/questions/types/true-false/index.js +1 -2
  271. package/dist/components/questions/types/true-false/register.js +1 -77
  272. package/dist/components/questions/types/true-false/transform.js +1 -32
  273. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +1 -233
  274. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphCreator.js +1 -631
  275. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphWrapper.js +1 -28
  276. package/dist/components/questions/types/word-fill-paragraph/index.js +1 -2
  277. package/dist/components/questions/types/word-fill-paragraph/register.js +1 -136
  278. package/dist/components/questions/types/word-fill-paragraph/transform.js +1 -56
  279. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -138
  280. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +1 -261
  281. package/dist/components/questions/types/word-fill-structured-form/index.js +1 -2
  282. package/dist/components/questions/types/word-fill-structured-form/register.js +1 -67
  283. package/dist/components/questions/types/word-fill-structured-form/transform.js +1 -40
  284. package/dist/components/questions/types/word-ordering/WordOrderingClient.js +1 -84
  285. package/dist/components/questions/types/word-ordering/WordOrderingCreator.js +1 -192
  286. package/dist/components/questions/types/word-ordering/index.js +1 -2
  287. package/dist/components/questions/types/word-ordering/register.js +1 -46
  288. package/dist/components/questions/types/word-ordering/transform.js +1 -24
  289. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +1 -98
  290. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +1 -320
  291. package/dist/components/questions/types/write-a-short-letter/index.js +1 -2
  292. package/dist/components/questions/types/write-a-short-letter/register.js +1 -68
  293. package/dist/components/questions/types/write-a-short-letter/transform.js +1 -25
  294. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +1 -61
  295. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js +1 -196
  296. package/dist/components/questions/types/write-correct-verb-form/index.js +1 -2
  297. package/dist/components/questions/types/write-correct-verb-form/register.js +1 -62
  298. package/dist/components/questions/types/write-correct-verb-form/transform.js +1 -17
  299. package/dist/components/questions/types/write-sentences/WriteSentencesClient.js +1 -22
  300. package/dist/components/questions/types/write-sentences/WriteSentencesCreator.js +1 -174
  301. package/dist/components/questions/types/write-sentences/index.js +1 -2
  302. package/dist/components/questions/types/write-sentences/register.js +1 -58
  303. package/dist/components/questions/types/write-sentences/transform.js +1 -28
  304. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphClient.js +1 -96
  305. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphCreator.js +1 -161
  306. package/dist/components/questions/types/write-short-paragraph/index.js +1 -2
  307. package/dist/components/questions/types/write-short-paragraph/register.js +1 -4
  308. package/dist/components/questions/types/write-short-paragraph/transform.js +1 -21
  309. package/dist/components/questions/viewer/QuestionGroupViewer.js +1 -36
  310. package/dist/components/questions/viewer/QuestionViewer.js +1 -446
  311. package/dist/components/questions/viewer/index.js +1 -2
  312. package/dist/components/results/ResultReviewPageContainer.js +1 -98
  313. package/dist/components/results/ReviewQuestionRenderer.js +1 -72
  314. package/dist/components/results/index.js +1 -2
  315. package/dist/components/results/result-review.utils.js +1 -6
  316. package/dist/components/results/review-data.js +1 -150
  317. package/dist/components/results/review-renderer.utils.js +1 -97
  318. package/dist/components/results/review-types.js +1 -1
  319. package/dist/components/themes/cambridge-yle/CambridgeYleAudioPlayer.js +1 -138
  320. package/dist/components/themes/cambridge-yle/CambridgeYleBottomNav.js +1 -12
  321. package/dist/components/themes/cambridge-yle/CambridgeYleExamLayout.js +1 -18
  322. package/dist/components/themes/cambridge-yle/CambridgeYleExampleText.js +1 -11
  323. package/dist/components/themes/cambridge-yle/CambridgeYleHeader.js +1 -11
  324. package/dist/components/themes/cambridge-yle/CambridgeYleInstructionBanner.js +1 -9
  325. package/dist/components/themes/cambridge-yle/CambridgeYleNavButton.js +1 -13
  326. package/dist/components/themes/cambridge-yle/CambridgeYlePartBanner.js +1 -8
  327. package/dist/components/themes/cambridge-yle/CambridgeYleProgressBar.js +1 -6
  328. package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCard.js +1 -5
  329. package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCardFullWidth.js +1 -9
  330. package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.js +1 -41
  331. package/dist/components/themes/cambridge-yle/CambridgeYleTimer.js +1 -25
  332. package/dist/components/themes/cambridge-yle/index.js +1 -13
  333. package/dist/components/themes/english-certification/EcAnswerTheQuestion.js +1 -24
  334. package/dist/components/themes/english-certification/EcMatchByWritingAnswer.js +1 -88
  335. package/dist/components/themes/english-certification/EcWordFillParagraph.js +1 -55
  336. package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -156
  337. package/dist/components/themes/english-certification/EcWritingTask.js +1 -34
  338. package/dist/components/themes/english-certification/EnglishCertificationAudioPlayer.js +1 -114
  339. package/dist/components/themes/english-certification/EnglishCertificationBrand.js +1 -11
  340. package/dist/components/themes/english-certification/EnglishCertificationExamLayout.js +1 -21
  341. package/dist/components/themes/english-certification/EnglishCertificationFlagButton.js +1 -15
  342. package/dist/components/themes/english-certification/EnglishCertificationFooterBar.js +1 -19
  343. package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.js +1 -148
  344. package/dist/components/themes/english-certification/EnglishCertificationHeader.js +1 -31
  345. package/dist/components/themes/english-certification/EnglishCertificationNavigationPanel.js +1 -71
  346. package/dist/components/themes/english-certification/EnglishCertificationOptionSelector.js +1 -33
  347. package/dist/components/themes/english-certification/EnglishCertificationPassagePanel.js +1 -16
  348. package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.js +1 -22
  349. package/dist/components/themes/english-certification/EnglishCertificationQuestionItem.js +1 -37
  350. package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -72
  351. package/dist/components/themes/english-certification/EnglishCertificationReadingSection.js +1 -90
  352. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestion.js +1 -18
  353. package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js +1 -29
  354. package/dist/components/themes/english-certification/english-certification-theme.js +1 -58
  355. package/dist/components/themes/english-certification/grouped-question-utils.js +1 -218
  356. package/dist/components/themes/english-certification/index.js +1 -21
  357. package/dist/components/themes/index.js +1 -6
  358. package/dist/components/themes/summer-sky/SummerSkyAudioPlayer.js +1 -170
  359. package/dist/components/themes/summer-sky/SummerSkyLayout.js +1 -221
  360. package/dist/components/themes/summer-sky/SummerSkySubmitModal.js +1 -18
  361. package/dist/components/themes/summer-sky/SummerSkyWaitingRoom.js +1 -194
  362. package/dist/components/themes/types.js +1 -1
  363. package/dist/components/ui/alert-dialog.js +1 -26
  364. package/dist/components/ui/alert.js +1 -22
  365. package/dist/components/ui/avatar.js +1 -12
  366. package/dist/components/ui/badge.js +1 -38
  367. package/dist/components/ui/button.js +1 -35
  368. package/dist/components/ui/calendar.js +1 -76
  369. package/dist/components/ui/card.js +1 -16
  370. package/dist/components/ui/carousel.js +1 -91
  371. package/dist/components/ui/checkbox.js +1 -9
  372. package/dist/components/ui/collapsible.js +1 -13
  373. package/dist/components/ui/command.js +1 -34
  374. package/dist/components/ui/confirm-dialog.js +1 -49
  375. package/dist/components/ui/dialog.js +1 -23
  376. package/dist/components/ui/drawer.js +1 -35
  377. package/dist/components/ui/dropdown-menu.js +1 -33
  378. package/dist/components/ui/file-upload.js +1 -155
  379. package/dist/components/ui/form.js +1 -62
  380. package/dist/components/ui/hover-card.js +1 -10
  381. package/dist/components/ui/image-preview.js +1 -29
  382. package/dist/components/ui/input.js +1 -8
  383. package/dist/components/ui/label.js +1 -9
  384. package/dist/components/ui/language-switcher.js +1 -15
  385. package/dist/components/ui/multi-select.js +1 -90
  386. package/dist/components/ui/points-input.js +1 -33
  387. package/dist/components/ui/popover.js +1 -26
  388. package/dist/components/ui/progress.js +1 -16
  389. package/dist/components/ui/radio-group.js +1 -12
  390. package/dist/components/ui/scroll-area.js +1 -11
  391. package/dist/components/ui/select.js +1 -38
  392. package/dist/components/ui/separator.js +1 -8
  393. package/dist/components/ui/sheet.js +1 -40
  394. package/dist/components/ui/single-select.js +1 -76
  395. package/dist/components/ui/skeleton.js +1 -6
  396. package/dist/components/ui/switch.js +1 -8
  397. package/dist/components/ui/table.js +1 -20
  398. package/dist/components/ui/tabs.js +1 -17
  399. package/dist/components/ui/textarea.js +1 -8
  400. package/dist/components/ui/tooltip.js +1 -11
  401. package/dist/index.d.ts +3 -3
  402. package/dist/index.js +1 -19
  403. package/dist/mcp/config.js +1 -32
  404. package/dist/mcp/http-client.js +1 -48
  405. package/dist/mcp/index.js +1 -29
  406. package/dist/mcp/tools/_helpers.js +1 -25
  407. package/dist/mcp/tools/exams.js +1 -439
  408. package/dist/mcp/tools/index.js +1 -6
  409. package/dist/mcp/tools/results.js +1 -19
  410. package/dist/shared/constants/ApiConstant.js +1 -276
  411. package/dist/shared/constants/QueryKeyConstant.js +1 -112
  412. package/dist/shared/constants/exam-level.enum.js +1 -41
  413. package/dist/shared/constants/landings/placement-test.constants.js +1 -431
  414. package/dist/shared/constants/question-skills.js +1 -267
  415. package/dist/shared/constants/routes.js +1 -81
  416. package/dist/shared/index.d.ts +3 -0
  417. package/dist/shared/index.js +1 -7
  418. package/dist/shared/lib/hooks/index.js +1 -10
  419. package/dist/shared/lib/hooks/useAlertDialog.js +1 -57
  420. package/dist/shared/lib/hooks/useAudioPlayCounter.js +1 -30
  421. package/dist/shared/lib/hooks/useAudioPreview.js +1 -81
  422. package/dist/shared/lib/hooks/useAudioUpload.js +1 -24
  423. package/dist/shared/lib/hooks/useConfirmDialog.js +1 -89
  424. package/dist/shared/lib/hooks/useDebouncedCallback.js +1 -32
  425. package/dist/shared/lib/hooks/useDelayedAutoPlay.js +1 -12
  426. package/dist/shared/lib/hooks/useFileUpload.js +1 -24
  427. package/dist/shared/lib/hooks/useImageUrl.js +1 -5
  428. package/dist/shared/lib/hooks/usePresignedFileUrl.js +1 -10
  429. package/dist/shared/lib/hooks/useReactHookForm.js +1 -31
  430. package/dist/shared/lib/hooks/useToast.js +1 -62
  431. package/dist/shared/lib/i18n/index.js +1 -54
  432. package/dist/shared/lib/i18n/messages/en/admin.js +1 -2104
  433. package/dist/shared/lib/i18n/messages/en/auth.js +1 -86
  434. package/dist/shared/lib/i18n/messages/en/common.js +1 -140
  435. package/dist/shared/lib/i18n/messages/en/file-upload.js +1 -18
  436. package/dist/shared/lib/i18n/messages/en/student.js +1 -133
  437. package/dist/shared/lib/i18n/messages/en/terms.js +1 -37
  438. package/dist/shared/lib/i18n/messages/en.js +1 -15
  439. package/dist/shared/lib/i18n/messages/vi/admin.js +1 -2104
  440. package/dist/shared/lib/i18n/messages/vi/auth.js +1 -86
  441. package/dist/shared/lib/i18n/messages/vi/common.js +1 -140
  442. package/dist/shared/lib/i18n/messages/vi/file-upload.js +1 -18
  443. package/dist/shared/lib/i18n/messages/vi/student.js +1 -133
  444. package/dist/shared/lib/i18n/messages/vi/terms.js +1 -37
  445. package/dist/shared/lib/i18n/messages/vi.js +1 -15
  446. package/dist/shared/lib/i18n/types.js +1 -1
  447. package/dist/shared/lib/stores/examQuestionStore.js +1 -212
  448. package/dist/shared/lib/stores/localeStore.js +1 -10
  449. package/dist/shared/lib/utils/public-page.js +1 -44
  450. package/dist/shared/lib/utils/question-reverse-transform.d.ts +6 -0
  451. package/dist/shared/lib/utils/question-reverse-transform.js +1 -0
  452. package/dist/shared/lib/utils/question-transform-types.js +1 -1
  453. package/dist/shared/lib/utils/question-transform-validation.d.ts +6 -0
  454. package/dist/shared/lib/utils/question-transform-validation.js +1 -0
  455. package/dist/shared/lib/utils/question-transform.d.ts +6 -2
  456. package/dist/shared/lib/utils/question-transform.js +1 -174
  457. package/dist/shared/lib/utils.js +1 -168
  458. package/dist/shared/lib/validation/choose-correct-answer.validation.js +1 -111
  459. package/dist/shared/lib/validation/label-the-picture.validation.js +1 -19
  460. package/dist/shared/lib/validation/listen-and-choose-from-answer-group.validation.js +1 -46
  461. package/dist/shared/lib/validation/listen-and-choose-objects-in-scene.validation.js +1 -21
  462. package/dist/shared/lib/validation/listen-and-drag-objects-into-scene.validation.js +1 -34
  463. package/dist/shared/lib/validation/listen-and-speak-answer.validation.js +1 -40
  464. package/dist/shared/lib/validation/listen-and-speak-compare-images.validation.js +1 -45
  465. package/dist/shared/lib/validation/listen-and-speak-image-group.validation.js +1 -19
  466. package/dist/shared/lib/validation/listen-and-speak-info-exchange.validation.js +1 -39
  467. package/dist/shared/lib/validation/listen-and-speak-odd-one-out.validation.js +1 -32
  468. package/dist/shared/lib/validation/listen-and-speak-question-list.validation.js +1 -19
  469. package/dist/shared/lib/validation/listen-and-speak-with-story-images.validation.js +1 -28
  470. package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.js +1 -12
  471. package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.js +1 -47
  472. package/dist/shared/lib/validation/read-and-color-objects.validation.js +1 -29
  473. package/dist/shared/lib/validation/read-displayed-content.validation.js +1 -28
  474. package/dist/shared/lib/validation/speaking-conversation.validation.js +1 -75
  475. package/dist/shared/lib/validation/speaking-describe-image.validation.js +1 -31
  476. package/dist/shared/lib/validation/spontaneous-qa.validation.js +1 -48
  477. package/dist/shared/lib/validation/word-fill-paragraph-default.validation.js +1 -38
  478. package/dist/shared/lib/validation/word-fill-paragraph-with-options.validation.js +1 -39
  479. package/dist/shared/lib/validation/word-fill-paragraph.validation.js +1 -43
  480. package/dist/shared/lib/validation/word-ordering.validation.js +1 -33
  481. package/dist/shared/types/branch.types.js +1 -6
  482. package/dist/shared/types/common.types.js +1 -50
  483. package/dist/shared/types/entities/exam-schedule.types.js +1 -5
  484. package/dist/shared/types/entities/exam.types.js +1 -1
  485. package/dist/shared/types/entities/question.types.js +1 -4
  486. package/dist/shared/types/entities/result.types.js +1 -4
  487. package/dist/shared/types/entities/user.types.js +1 -4
  488. package/dist/shared/types/exam-taking.types.js +1 -2
  489. package/dist/shared/types/history.types.js +1 -34
  490. package/dist/shared/types/index.js +1 -1
  491. package/dist/shared/types/questions/choose-correct-adjective.js +1 -4
  492. package/dist/shared/types/questions/choose-the-correct-answer.js +1 -9
  493. package/dist/shared/types/questions/fill-missing-words-in-grid.js +1 -11
  494. package/dist/shared/types/questions/index.js +1 -40
  495. package/dist/shared/types/questions/listen-and-speak-answer.js +1 -1
  496. package/dist/shared/types/questions/listen-and-speak-compare-images.js +1 -1
  497. package/dist/shared/types/questions/listen-and-speak-image-group.js +1 -1
  498. package/dist/shared/types/questions/listen-and-speak-info-exchange.js +1 -3
  499. package/dist/shared/types/questions/listen-and-speak-odd-one-out.js +1 -3
  500. package/dist/shared/types/questions/listen-and-speak-question-list.js +1 -1
  501. package/dist/shared/types/questions/listen-and-speak-with-story-images.js +1 -3
  502. package/dist/shared/types/questions/look-picture-choose-correct-answer.js +1 -5
  503. package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.js +1 -9
  504. package/dist/shared/types/questions/look-picture-fill-word-hint.js +1 -7
  505. package/dist/shared/types/questions/read-displayed-content.js +1 -1
  506. package/dist/shared/types/questions/speaking-conversation.js +1 -7
  507. package/dist/shared/types/questions/speaking-describe-image.js +1 -1
  508. package/dist/shared/types/questions/spontaneous-qa.js +1 -1
  509. package/dist/shared/types/questions/write-correct-verb-form.js +1 -12
  510. package/dist/shared/types/role.types.js +1 -1
  511. package/dist/shared/types/structure-management.js +1 -28
  512. package/dist/shared/types/student.types.js +1 -54
  513. package/dist/shared/types/teacher-dashboard-rooms.js +1 -2
  514. package/package.json +12 -3
@@ -1,58 +1 @@
1
- import { WriteSentencesCreator } from './WriteSentencesCreator';
2
- export const writeSentencesRegistration = {
3
- component: WriteSentencesCreator,
4
- transformInitialData: (initialData) => {
5
- const answer = initialData?.answer || {};
6
- const explanation = initialData?.explanation || answer?.explanation || '';
7
- const apiPoints = initialData?.total_points
8
- ? parseFloat(initialData.total_points)
9
- : (initialData?.points || 1);
10
- const questionGroup = initialData?.questionGroup || {};
11
- const groupPayload = questionGroup?.payload || {};
12
- const groupTitle = groupPayload?.title || answer?.title || '';
13
- const groupContent = groupPayload?.content || answer?.groupContent || '';
14
- const groupImageUrl = groupPayload?.imageUrl || answer?.imageUrl || '';
15
- const groupNumber = questionGroup?.groupNumber || answer?.groupNumber || 1;
16
- const content = initialData?.content || {};
17
- const instruction = answer?.instruction || content?.instruction || '';
18
- const sentenceCount = answer?.sentenceCount || content?.sentenceCount || undefined;
19
- return {
20
- points: answer?.points || apiPoints,
21
- explanation,
22
- instruction,
23
- sentenceCount,
24
- title: groupTitle,
25
- groupContent,
26
- imageUrl: groupImageUrl,
27
- groupNumber,
28
- groups: answer?.groups || initialData?.groups,
29
- };
30
- },
31
- getExtraProps: (ctx) => ({
32
- groups: ctx.groups,
33
- questionIndexInPart: ctx.questionIndexInPart,
34
- partId: ctx.partId,
35
- validationRef: ctx.validationRef,
36
- onUnsavedChangesChange: ctx.onUnsavedChangesChange,
37
- }),
38
- wrapOnSave: (data, ctx) => ({
39
- type: ctx.questionType,
40
- content: ctx.state.content,
41
- points: data?.points ?? ctx.state.points ?? 1,
42
- level: ctx.state.level,
43
- difficulty: ctx.state.difficulty,
44
- skill: ctx.state.skill,
45
- answer: data,
46
- explanation: data?.explanation || '',
47
- }),
48
- wrapOnChange: (data, ctx) => ({
49
- type: ctx.questionType,
50
- content: ctx.state.content,
51
- points: data?.points ?? ctx.state.points ?? 1,
52
- level: ctx.state.level,
53
- difficulty: ctx.state.difficulty,
54
- skill: ctx.state.skill,
55
- answer: data,
56
- explanation: data?.explanation || '',
57
- }),
58
- };
1
+ import{WriteSentencesCreator as t}from"./WriteSentencesCreator";export const writeSentencesRegistration={component:t,transformInitialData:t=>{const n=t?.answer||{},e=t?.explanation||n?.explanation||"",o=t?.total_points?parseFloat(t.total_points):t?.points||1,a=t?.questionGroup||{},i=a?.payload||{},s=i?.title||n?.title||"",r=i?.content||n?.groupContent||"",p=i?.imageUrl||n?.imageUrl||"",l=a?.groupNumber||n?.groupNumber||1,u=t?.content||{},c=n?.instruction||u?.instruction||"",g=n?.sentenceCount||u?.sentenceCount||void 0;return{points:n?.points||o,explanation:e,instruction:c,sentenceCount:g,title:s,groupContent:r,imageUrl:p,groupNumber:l,groups:n?.groups||t?.groups}},getExtraProps:t=>({groups:t.groups,questionIndexInPart:t.questionIndexInPart,partId:t.partId,validationRef:t.validationRef,onUnsavedChangesChange:t.onUnsavedChangesChange}),wrapOnSave:(t,n)=>({type:n.questionType,content:n.state.content,points:t?.points??n.state.points??1,level:n.state.level,difficulty:n.state.difficulty,skill:n.state.skill,answer:t,explanation:t?.explanation||""}),wrapOnChange:(t,n)=>({type:n.questionType,content:n.state.content,points:t?.points??n.state.points??1,level:n.state.level,difficulty:n.state.difficulty,skill:n.state.skill,answer:t,explanation:t?.explanation||""})};
@@ -1,28 +1 @@
1
- export const transformWriteSentences = (question) => {
2
- const answerData = question.answer;
3
- const hasGroupData = !!(answerData?.title || answerData?.subtitle || answerData?.groupContent || answerData?.imageUrl);
4
- const basicGroupData = hasGroupData
5
- ? {
6
- title: answerData.title || '',
7
- subtitle: answerData.subtitle || '',
8
- content: answerData.groupContent || '',
9
- imageUrl: answerData.imageUrl || '',
10
- }
11
- : undefined;
12
- const groupNumber = answerData?.groupNumber || 1;
13
- const apiContent = {};
14
- if (answerData?.instruction) {
15
- apiContent.instruction = answerData.instruction;
16
- }
17
- if (answerData?.sentenceCount) {
18
- apiContent.sentenceCount = answerData.sentenceCount;
19
- }
20
- return {
21
- apiContent,
22
- apiCorrectAnswer: {},
23
- totalPoints: answerData?.points || question.points || 1,
24
- explanation: answerData?.explanation || question.explanation || '',
25
- basicGroupData,
26
- groupNumber,
27
- };
28
- };
1
+ export const transformWriteSentences=t=>{const n=t.answer,e=!!(n?.title||n?.subtitle||n?.groupContent||n?.imageUrl)?{title:n.title||"",subtitle:n.subtitle||"",content:n.groupContent||"",imageUrl:n.imageUrl||""}:void 0,o=n?.groupNumber||1,i={};return n?.instruction&&(i.instruction=n.instruction),n?.sentenceCount&&(i.sentenceCount=n.sentenceCount),{apiContent:i,apiCorrectAnswer:{},totalPoints:n?.points||t.points||1,explanation:n?.explanation||t.explanation||"",basicGroupData:e,groupNumber:o}};
@@ -1,96 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useState, useEffect, useMemo } from 'react';
4
- import { Card, CardContent, CardHeader, CardTitle } from '../../../../components/ui/card';
5
- import { Textarea } from '../../../../components/ui/textarea';
6
- import { Label } from '../../../../components/ui/label';
7
- import { Image, Music, FileText, AlertCircle } from 'lucide-react';
8
- import { usePresignedFileUrl } from '../../../../shared/lib/hooks';
9
- export function WriteShortParagraphClient({ questionData, onSubmit, isReviewMode = false, userAnswer, }) {
10
- const { contexts, minWords, maxWords, instruction } = questionData;
11
- // Initialize answer state
12
- const [answer, setAnswer] = useState(userAnswer || '');
13
- // Sync userAnswer when it changes (e.g., when loading from server in review mode)
14
- useEffect(() => {
15
- if (userAnswer !== undefined) {
16
- setAnswer(userAnswer);
17
- }
18
- }, [userAnswer]);
19
- // Count words
20
- const wordCount = useMemo(() => {
21
- if (!answer.trim())
22
- return 0;
23
- return answer
24
- .trim()
25
- .split(/\s+/)
26
- .filter((word) => word.length > 0).length;
27
- }, [answer]);
28
- // Check if word count is valid
29
- const isValidWordCount = useMemo(() => {
30
- if (wordCount < minWords)
31
- return false;
32
- if (maxWords && wordCount > maxWords)
33
- return false;
34
- return true;
35
- }, [wordCount, minWords, maxWords]);
36
- // Handle answer change
37
- const handleAnswerChange = (value) => {
38
- if (isReviewMode)
39
- return;
40
- setAnswer(value);
41
- onSubmit?.(value);
42
- };
43
- // Get icon for context type
44
- const getContextIcon = (type) => {
45
- switch (type) {
46
- case 'image':
47
- return _jsx(Image, { className: "h-5 w-5" });
48
- case 'audio':
49
- return _jsx(Music, { className: "h-5 w-5" });
50
- case 'text':
51
- return _jsx(FileText, { className: "h-5 w-5" });
52
- }
53
- };
54
- // Get label for context type
55
- const getContextLabel = (type) => {
56
- switch (type) {
57
- case 'image':
58
- return 'Ảnh';
59
- case 'audio':
60
- return 'Audio';
61
- case 'text':
62
- return 'Text';
63
- }
64
- };
65
- return (_jsxs("div", { className: "space-y-6", children: [instruction && (_jsx(Card, { children: _jsx(CardHeader, { children: _jsx(CardTitle, { className: "text-lg", children: instruction }) }) })), contexts.length > 0 && (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: "Contexts" }) }), _jsx(CardContent, { children: _jsx("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3", children: contexts.map((ctx, index) => (_jsx(ContextDisplay, { context: ctx, index: index }, ctx.id))) }) })] })), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx(CardTitle, { children: "Vi\u1EBFt b\u00E0i" }), _jsx("div", { className: "flex items-center gap-2", children: _jsxs("span", { className: `text-sm font-semibold ${isValidWordCount ? 'text-green-600' : 'text-red-600'}`, children: [wordCount, " / ", minWords, maxWords ? ` - ${maxWords}` : '+', " t\u1EEB"] }) })] }) }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { children: [_jsx(Label, { htmlFor: "writing-answer", children: "N\u1ED9i dung b\u00E0i vi\u1EBFt" }), _jsx(Textarea, { id: "writing-answer", value: answer, onChange: (e) => handleAnswerChange(e.target.value), placeholder: "Nh\u1EADp n\u1ED9i dung b\u00E0i vi\u1EBFt c\u1EE7a b\u1EA1n...", className: "mt-2 min-h-[200px]", rows: 10, disabled: isReviewMode })] }), !isReviewMode && (_jsx("div", { className: "flex items-start gap-2 rounded-lg border p-3", children: isValidWordCount ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "mt-0.5 h-5 w-5 rounded-full bg-green-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("p", { className: "text-sm font-medium text-green-700", children: "\u0110\u00E3 \u0111\u1EE7 s\u1ED1 t\u1EEB y\u00EAu c\u1EA7u" }), _jsxs("p", { className: "text-xs text-green-600", children: ["B\u1EA1n \u0111\u00E3 vi\u1EBFt ", wordCount, " t\u1EEB. Y\u00EAu c\u1EA7u: ", minWords, maxWords ? ` - ${maxWords}` : '+', " t\u1EEB."] })] })] })) : (_jsxs(_Fragment, { children: [_jsx(AlertCircle, { className: "h-5 w-5 text-amber-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("p", { className: "text-sm font-medium text-amber-700", children: "Ch\u01B0a \u0111\u1EE7 s\u1ED1 t\u1EEB y\u00EAu c\u1EA7u" }), _jsxs("p", { className: "text-xs text-amber-600", children: ["B\u1EA1n \u0111\u00E3 vi\u1EBFt ", wordCount, " t\u1EEB. C\u1EA7n \u00EDt nh\u1EA5t ", minWords, " t\u1EEB.", maxWords && wordCount > maxWords && _jsxs("span", { children: [" T\u1ED1i \u0111a ", maxWords, " t\u1EEB."] })] })] })] })) }))] })] })] }));
66
- }
67
- function ContextDisplay({ context, index }) {
68
- const { previewUrl } = usePresignedFileUrl(context.type !== 'text' ? context.url || '' : '');
69
- const getIcon = () => {
70
- switch (context.type) {
71
- case 'image':
72
- return _jsx(Image, { className: "h-5 w-5" });
73
- case 'audio':
74
- return _jsx(Music, { className: "h-5 w-5" });
75
- case 'text':
76
- return _jsx(FileText, { className: "h-5 w-5" });
77
- }
78
- };
79
- const getLabel = () => {
80
- switch (context.type) {
81
- case 'image':
82
- return 'Ảnh';
83
- case 'audio':
84
- return 'Audio';
85
- case 'text':
86
- return 'Text';
87
- }
88
- };
89
- return (_jsxs("div", { className: "rounded-lg border bg-white p-4 shadow-sm", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [getIcon(), _jsxs("span", { className: "text-sm font-semibold text-gray-700", children: [getLabel(), " ", index + 1] })] }), context.type === 'image' && (_jsx("div", { className: "relative h-48 w-full overflow-hidden rounded border bg-gray-50", children: previewUrl ? (
90
- /* eslint-disable-next-line @next/next/no-img-element */
91
- _jsx("img", { src: previewUrl, alt: `Context ${index + 1}`, className: "h-full w-full object-contain", onError: () => {
92
- console.error('Failed to load image:', context.url);
93
- } })) : (_jsx("div", { className: "flex h-full items-center justify-center text-gray-400", children: _jsx(Image, { className: "h-12 w-12" }) })) })), context.type === 'audio' && (_jsx("div", { className: "space-y-2", children: _jsx("div", { className: "rounded border bg-gray-50 p-3", children: _jsx("audio", { controls: true, className: "w-full", src: previewUrl || context.url || '', onError: () => {
94
- console.error('Failed to load audio:', context.url);
95
- }, children: "Your browser does not support the audio element." }) }) })), context.type === 'text' && (_jsx("div", { className: "rounded border bg-gray-50 p-3", children: _jsx("p", { className: "text-sm whitespace-pre-wrap text-gray-700", children: context.text }) }))] }));
96
- }
1
+ "use client";import{jsx as e,jsxs as r,Fragment as t}from"react/jsx-runtime";import{useState as i,useEffect as s,useMemo as a}from"react";import{Card as l,CardContent as n,CardHeader as c,CardTitle as d}from"../../../../components/ui/card";import{Textarea as o}from"../../../../components/ui/textarea";import{Label as m}from"../../../../components/ui/label";import{Image as h,Music as u,FileText as p,AlertCircle as x}from"lucide-react";import{usePresignedFileUrl as g}from"../../../../shared/lib/hooks";export function WriteShortParagraphClient({questionData:h,onSubmit:u,isReviewMode:p=!1,userAnswer:g}){const{contexts:f,minWords:v,maxWords:b,instruction:w}=h,[y,j]=i(g||"");s(()=>{void 0!==g&&j(g)},[g]);const C=a(()=>y.trim()?y.trim().split(/\s+/).filter(e=>e.length>0).length:0,[y]),F=a(()=>!(C<v)&&!(b&&C>b),[C,v,b]);return r("div",{className:"space-y-6",children:[w&&e(l,{children:e(c,{children:e(d,{className:"text-lg",children:w})})}),f.length>0&&r(l,{children:[e(c,{children:e(d,{children:"Contexts"})}),e(n,{children:e("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3",children:f.map((r,t)=>e(N,{context:r,index:t},r.id))})})]}),r(l,{children:[e(c,{children:r("div",{className:"flex items-center justify-between",children:[e(d,{children:"Viết bài"}),e("div",{className:"flex items-center gap-2",children:r("span",{className:"text-sm font-semibold "+(F?"text-green-600":"text-red-600"),children:[C," / ",v,b?` - ${b}`:"+"," từ"]})})]})}),r(n,{className:"space-y-4",children:[r("div",{children:[e(m,{htmlFor:"writing-answer",children:"Nội dung bài viết"}),e(o,{id:"writing-answer",value:y,onChange:e=>{return r=e.target.value,void(p||(j(r),u?.(r)));var r},placeholder:"Nhập nội dung bài viết của bạn...",className:"mt-2 min-h-[200px]",rows:10,disabled:p})]}),!p&&e("div",{className:"flex items-start gap-2 rounded-lg border p-3",children:r(t,F?{children:[e("div",{className:"mt-0.5 h-5 w-5 rounded-full bg-green-500"}),r("div",{className:"flex-1",children:[e("p",{className:"text-sm font-medium text-green-700",children:"Đã đủ số từ yêu cầu"}),r("p",{className:"text-xs text-green-600",children:["Bạn đã viết ",C," từ. Yêu cầu: ",v,b?` - ${b}`:"+"," từ."]})]})]}:{children:[e(x,{className:"h-5 w-5 text-amber-500"}),r("div",{className:"flex-1",children:[e("p",{className:"text-sm font-medium text-amber-700",children:"Chưa đủ số từ yêu cầu"}),r("p",{className:"text-xs text-amber-600",children:["Bạn đã viết ",C," từ. Cần ít nhất ",v," từ.",b&&C>b&&r("span",{children:[" Tối đa ",b," từ."]})]})]})]})})]})]})]})}function N({context:t,index:i}){const{previewUrl:s}=g("text"!==t.type&&t.url||"");return r("div",{className:"rounded-lg border bg-white p-4 shadow-sm",children:[r("div",{className:"mb-2 flex items-center gap-2",children:[(()=>{switch(t.type){case"image":return e(h,{className:"h-5 w-5"});case"audio":return e(u,{className:"h-5 w-5"});case"text":return e(p,{className:"h-5 w-5"})}})(),r("span",{className:"text-sm font-semibold text-gray-700",children:[(()=>{switch(t.type){case"image":return"Ảnh";case"audio":return"Audio";case"text":return"Text"}})()," ",i+1]})]}),"image"===t.type&&e("div",{className:"relative h-48 w-full overflow-hidden rounded border bg-gray-50",children:s?e("img",{src:s,alt:`Context ${i+1}`,className:"h-full w-full object-contain",onError:()=>{console.error("Failed to load image:",t.url)}}):e("div",{className:"flex h-full items-center justify-center text-gray-400",children:e(h,{className:"h-12 w-12"})})}),"audio"===t.type&&e("div",{className:"space-y-2",children:e("div",{className:"rounded border bg-gray-50 p-3",children:e("audio",{controls:!0,className:"w-full",src:s||t.url||"",onError:()=>{console.error("Failed to load audio:",t.url)},children:"Your browser does not support the audio element."})})}),"text"===t.type&&e("div",{className:"rounded border bg-gray-50 p-3",children:e("p",{className:"text-sm whitespace-pre-wrap text-gray-700",children:t.text})})]})}
@@ -1,161 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState, useRef, useEffect } from 'react';
4
- import { Button } from '../../../../components/ui/button';
5
- import { Label } from '../../../../components/ui/label';
6
- import { Input } from '../../../../components/ui/input';
7
- import { Textarea } from '../../../../components/ui/textarea';
8
- import { Card, CardContent, CardHeader, CardTitle } from '../../../../components/ui/card';
9
- import { Pencil, Eye, X, Image, Music, FileText } from 'lucide-react';
10
- import { FileUpload } from '../../../../components/ui/file-upload';
11
- import { WriteShortParagraphClient } from './WriteShortParagraphClient';
12
- import { usePresignedFileUrl } from '../../../../shared/lib/hooks';
13
- function WriteShortParagraphCreatorContent({ initialData, onSave, // eslint-disable-line @typescript-eslint/no-unused-vars
14
- onCancel, // eslint-disable-line @typescript-eslint/no-unused-vars
15
- onChange, }) {
16
- // State
17
- const [contexts, setContexts] = useState(initialData?.contexts || []);
18
- const [minWords, setMinWords] = useState(initialData?.minWords || 20);
19
- const [maxWords, setMaxWords] = useState(initialData?.maxWords || undefined);
20
- const [instruction, setInstruction] = useState(initialData?.instruction || '');
21
- // Track previous initialData to detect changes
22
- const previousInitialDataRef = useRef(initialData);
23
- const isInitializingRef = useRef(false);
24
- const hasInitializedRef = useRef(false);
25
- // Sync state from initialData when it changes
26
- useEffect(() => {
27
- const initialDataChanged = JSON.stringify(previousInitialDataRef.current) !== JSON.stringify(initialData);
28
- if (initialDataChanged) {
29
- isInitializingRef.current = true;
30
- previousInitialDataRef.current = initialData;
31
- if (initialData) {
32
- if (initialData.contexts !== undefined)
33
- setContexts(initialData.contexts);
34
- if (initialData.minWords !== undefined)
35
- setMinWords(initialData.minWords);
36
- if (initialData.maxWords !== undefined)
37
- setMaxWords(initialData.maxWords);
38
- if (initialData.instruction !== undefined)
39
- setInstruction(initialData.instruction);
40
- hasInitializedRef.current = true;
41
- }
42
- else {
43
- // Only reset if not the first mount
44
- if (hasInitializedRef.current) {
45
- setContexts([]);
46
- setMinWords(20);
47
- setMaxWords(undefined);
48
- setInstruction('');
49
- }
50
- }
51
- setTimeout(() => {
52
- isInitializingRef.current = false;
53
- }, 100);
54
- }
55
- }, [initialData]);
56
- // Track previous data to avoid unnecessary onChange calls
57
- const previousDataRef = useRef(undefined);
58
- const onChangeRef = useRef(onChange);
59
- // Keep onChange ref up to date
60
- useEffect(() => {
61
- onChangeRef.current = onChange;
62
- }, [onChange]);
63
- useEffect(() => {
64
- if (isInitializingRef.current)
65
- return;
66
- const currentData = {
67
- contexts,
68
- minWords,
69
- maxWords,
70
- instruction,
71
- };
72
- // Only call onChange if data actually changed
73
- const dataChanged = JSON.stringify(previousDataRef.current) !== JSON.stringify(currentData);
74
- if (dataChanged) {
75
- previousDataRef.current = currentData;
76
- // Only call onChange if there's meaningful data (at least 1 context with valid data)
77
- const hasValidContext = contexts.some((ctx) => {
78
- if (ctx.type === 'text') {
79
- return ctx.text && ctx.text.trim().length > 0;
80
- }
81
- return ctx.url && ctx.url.trim().length > 0;
82
- });
83
- if (hasValidContext) {
84
- onChangeRef.current?.(currentData);
85
- }
86
- }
87
- }, [contexts, minWords, maxWords, instruction]);
88
- // UI State
89
- const [isClientMode, setIsClientMode] = useState(false);
90
- // Add new context
91
- const addContext = (type) => {
92
- const newContext = {
93
- id: `context-${Date.now()}-${Math.random()}`,
94
- type,
95
- url: type !== 'text' ? '' : undefined,
96
- text: type === 'text' ? '' : undefined,
97
- };
98
- setContexts([...contexts, newContext]);
99
- };
100
- // Remove context
101
- const removeContext = (id) => {
102
- setContexts(contexts.filter((ctx) => ctx.id !== id));
103
- };
104
- // Update context
105
- const updateContext = (id, field, value) => {
106
- setContexts(contexts.map((ctx) => (ctx.id === id ? { ...ctx, [field]: value } : ctx)));
107
- };
108
- // If in client mode, render the Client component
109
- if (isClientMode) {
110
- const questionData = {
111
- contexts,
112
- minWords,
113
- maxWords,
114
- instruction,
115
- };
116
- return (_jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-blue-100/50", children: [_jsx("div", { className: "h-1.5 bg-gradient-to-r from-blue-500 via-indigo-500 to-purple-500" }), _jsx(CardHeader, { children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-xl font-bold tracking-tight text-gray-900", children: "Write Short Paragraph (Preview)" }), _jsx("p", { className: "mt-1 text-sm text-gray-500", children: "Ch\u1EBF \u0111\u1ED9 xem tr\u01B0\u1EDBc" })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setIsClientMode(false), children: [_jsx(Pencil, { className: "mr-2 h-4 w-4" }), "Quay l\u1EA1i Edit Mode"] })] }) })] }), _jsx(WriteShortParagraphClient, { questionData: questionData, onSubmit: () => { } })] }));
117
- }
118
- return (_jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-blue-100/50", children: [_jsx("div", { className: "h-1.5 bg-gradient-to-r from-blue-500 via-indigo-500 to-purple-500" }), _jsx(CardHeader, { children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-xl font-bold tracking-tight text-gray-900", children: "Write Short Paragraph" }), _jsx("p", { className: "mt-1 text-sm text-gray-500", children: "T\u1EA1o b\u00E0i t\u1EADp vi\u1EBFt \u0111o\u1EA1n v\u0103n v\u1EDBi nhi\u1EC1u content (\u1EA3nh, audio, text)" })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setIsClientMode(true), disabled: contexts.length === 0 || minWords < 1, children: [_jsx(Eye, { className: "mr-2 h-4 w-4" }), "Client Mode"] })] }) }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "instruction", className: "text-sm font-semibold text-gray-700", children: "H\u01B0\u1EDBng d\u1EABn" }), _jsx(Textarea, { id: "instruction", value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: "V\u00ED d\u1EE5: Look at the three pictures. Write about this story.", className: "mt-1", rows: 2 })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "minWords", className: "text-sm font-semibold text-gray-700", children: "S\u1ED1 t\u1EEB t\u1ED1i thi\u1EC3u *" }), _jsx(Input, { id: "minWords", type: "number", min: "1", value: minWords, onChange: (e) => setMinWords(parseInt(e.target.value) || 1), placeholder: "20", className: "mt-1" })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "maxWords", className: "text-sm font-semibold text-gray-700", children: "S\u1ED1 t\u1EEB t\u1ED1i \u0111a (t\u00F9y ch\u1ECDn)" }), _jsx(Input, { id: "maxWords", type: "number", min: minWords, value: maxWords || '', onChange: (e) => setMaxWords(e.target.value ? parseInt(e.target.value) : undefined), placeholder: "Kh\u00F4ng gi\u1EDBi h\u1EA1n", className: "mt-1" })] })] })] })] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-xl shadow-blue-100/40 ring-1 ring-gray-100", children: [_jsx(CardHeader, { className: "bg-gradient-to-br from-indigo-50/50 via-white to-blue-50/30 pb-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-blue-500 to-indigo-600 shadow-md", children: _jsx(FileText, { className: "h-5 w-5 text-white" }) }), _jsxs("div", { children: [_jsx(CardTitle, { className: "text-lg font-bold text-gray-900", children: "Contexts" }), _jsx("p", { className: "mt-1 text-sm text-gray-500", children: "Th\u00EAm c\u00E1c context (\u1EA3nh, audio, ho\u1EB7c text) \u0111\u1EC3 h\u1ECDc sinh xem khi vi\u1EBFt" })] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: () => addContext('image'), className: "flex items-center gap-2 border-indigo-200 bg-indigo-50 text-indigo-700 hover:bg-indigo-100 hover:text-indigo-800", children: [_jsx(Image, { className: "h-4 w-4" }), "Th\u00EAm \u1EA3nh"] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => addContext('audio'), className: "flex items-center gap-2 border-purple-200 bg-purple-50 text-purple-700 hover:bg-purple-100 hover:text-purple-800", children: [_jsx(Music, { className: "h-4 w-4" }), "Th\u00EAm audio"] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => addContext('text'), className: "flex items-center gap-2 border-blue-200 bg-blue-50 text-blue-700 hover:bg-blue-100 hover:text-blue-800", children: [_jsx(FileText, { className: "h-4 w-4" }), "Th\u00EAm text"] })] })] }) }), _jsx(CardContent, { className: "space-y-4 pt-6", children: contexts.length > 0 ? (contexts.map((ctx, index) => (_jsx(ContextItem, { context: ctx, index: index, onUpdate: updateContext, onRemove: removeContext }, ctx.id)))) : (_jsxs("div", { className: "flex flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50 p-12", children: [_jsx("div", { className: "mb-4 rounded-full bg-gray-200 p-4", children: _jsx(Image, { className: "h-8 w-8 text-gray-400" }) }), _jsx("p", { className: "mb-2 text-sm font-medium text-gray-700", children: "Ch\u01B0a c\u00F3 context n\u00E0o" }), _jsx("p", { className: "mb-4 text-xs text-gray-500", children: "Nh\u1EA5n c\u00E1c n\u00FAt b\u00EAn tr\u00EAn \u0111\u1EC3 th\u00EAm context" })] })) })] })] }));
119
- }
120
- function ContextItem({ context, index, onUpdate, onRemove }) {
121
- const { previewUrl } = usePresignedFileUrl(context.type !== 'text' ? context.url || '' : '');
122
- const getIcon = () => {
123
- switch (context.type) {
124
- case 'image':
125
- return _jsx(Image, { className: "h-5 w-5" });
126
- case 'audio':
127
- return _jsx(Music, { className: "h-5 w-5" });
128
- case 'text':
129
- return _jsx(FileText, { className: "h-5 w-5" });
130
- }
131
- };
132
- const getLabel = () => {
133
- switch (context.type) {
134
- case 'image':
135
- return 'Ảnh';
136
- case 'audio':
137
- return 'Audio';
138
- case 'text':
139
- return 'Text';
140
- }
141
- };
142
- return (_jsx("div", { className: "rounded-lg border bg-white p-4 shadow-sm transition-shadow hover:shadow-md", children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: "flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full bg-blue-500 text-white shadow-md", children: _jsx("span", { className: "text-sm font-bold", children: index + 1 }) }), _jsxs("div", { className: "flex-1 space-y-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [getIcon(), _jsxs(Label, { className: "text-sm font-semibold text-gray-700", children: ["Context ", index + 1, " - ", getLabel()] })] }), context.type === 'text' ? (_jsxs("div", { children: [_jsx(Label, { className: "text-sm font-semibold text-gray-700", children: "N\u1ED9i dung text *" }), _jsx(Textarea, { value: context.text || '', onChange: (e) => onUpdate(context.id, 'text', e.target.value), placeholder: "Nh\u1EADp n\u1ED9i dung text...", className: "mt-1", rows: 3 })] })) : (_jsx("div", { children: _jsx(FileUpload, { id: `context-${context.id}`, label: context.type === 'image' ? 'URL ảnh *' : 'URL audio *', accept: context.type === 'image' ? 'image/*' : 'audio/*', value: context.url || '', onChange: (url) => onUpdate(context.id, 'url', url), maxSize: context.type === 'image' ? 5 : 10, placeholder: "Paste URL ho\u1EB7c upload file", autoUpload: true, prefix: "questions" }) })), context.type === 'image' && previewUrl && (_jsx("div", { className: "relative h-48 w-full overflow-hidden rounded border", children: _jsx("img", { src: previewUrl, alt: `Context ${index + 1} preview`, className: "h-full w-full object-contain", onError: () => {
143
- console.error('Failed to load image:', context.url);
144
- } }) })), context.type === 'audio' && context.url && (_jsx("div", { className: "rounded border bg-gray-50 p-3", children: _jsx("audio", { controls: true, className: "w-full", src: previewUrl || context.url, children: "Your browser does not support the audio element." }) }))] }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => onRemove(context.id), className: "flex-shrink-0 text-gray-400 hover:text-red-500", children: _jsx(X, { className: "h-5 w-5" }) })] }) }));
145
- }
146
- export function WriteShortParagraphCreator({ initialData, onSave, onCancel, onChange, }) {
147
- const handleSave = () => {
148
- // Validation
149
- if (!initialData?.contexts || initialData.contexts.length === 0) {
150
- return;
151
- }
152
- if (!initialData.minWords || initialData.minWords < 1) {
153
- return;
154
- }
155
- onSave?.(initialData);
156
- };
157
- return (_jsxs("div", { className: "space-y-6", children: [_jsx(WriteShortParagraphCreatorContent, { initialData: initialData, onSave: handleSave, onCancel: onCancel, onChange: onChange }), _jsxs("div", { className: "flex justify-end gap-3", children: [_jsx(Button, { variant: "outline", onClick: onCancel, children: "H\u1EE7y" }), _jsx(Button, { onClick: handleSave, className: "bg-blue-500 hover:bg-blue-600", disabled: !initialData?.contexts ||
158
- initialData.contexts.length === 0 ||
159
- !initialData.minWords ||
160
- initialData.minWords < 1, children: "L\u01B0u c\u00E2u h\u1ECFi" })] })] }));
161
- }
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as i,useRef as r,useEffect as a}from"react";import{Button as n}from"../../../../components/ui/button";import{Label as s}from"../../../../components/ui/label";import{Input as o}from"../../../../components/ui/input";import{Textarea as l}from"../../../../components/ui/textarea";import{Card as c,CardContent as d,CardHeader as m,CardTitle as h}from"../../../../components/ui/card";import{Pencil as u,Eye as g,X as x,Image as p,Music as v,FileText as b}from"lucide-react";import{FileUpload as f}from"../../../../components/ui/file-upload";import{WriteShortParagraphClient as N}from"./WriteShortParagraphClient";import{usePresignedFileUrl as y}from"../../../../shared/lib/hooks";function w({initialData:x,onSave:f,onCancel:y,onChange:w}){const[W,k]=i(x?.contexts||[]),[S,j]=i(x?.minWords||20),[z,T]=i(x?.maxWords||void 0),[U,P]=i(x?.instruction||""),D=r(x),L=r(!1),R=r(!1);a(()=>{JSON.stringify(D.current)!==JSON.stringify(x)&&(L.current=!0,D.current=x,x?(void 0!==x.contexts&&k(x.contexts),void 0!==x.minWords&&j(x.minWords),void 0!==x.maxWords&&T(x.maxWords),void 0!==x.instruction&&P(x.instruction),R.current=!0):R.current&&(k([]),j(20),T(void 0),P("")),setTimeout(()=>{L.current=!1},100))},[x]);const F=r(void 0),J=r(w);a(()=>{J.current=w},[w]),a(()=>{if(L.current)return;const e={contexts:W,minWords:S,maxWords:z,instruction:U};if(JSON.stringify(F.current)!==JSON.stringify(e)){F.current=e;W.some(e=>"text"===e.type?e.text&&e.text.trim().length>0:e.url&&e.url.trim().length>0)&&J.current?.(e)}},[W,S,z,U]);const[O,$]=i(!1),M=e=>{const t={id:`context-${Date.now()}-${Math.random()}`,type:e,url:"text"!==e?"":void 0,text:"text"===e?"":void 0};k([...W,t])},q=e=>{k(W.filter(t=>t.id!==e))},E=(e,t,i)=>{k(W.map(r=>r.id===e?{...r,[t]:i}:r))};if(O){const i={contexts:W,minWords:S,maxWords:z,instruction:U};return t("div",{className:"space-y-6",children:[t(c,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-blue-100/50",children:[e("div",{className:"h-1.5 bg-gradient-to-r from-blue-500 via-indigo-500 to-purple-500"}),e(m,{children:t("div",{className:"flex items-center justify-between",children:[t("div",{children:[e(h,{className:"text-xl font-bold tracking-tight text-gray-900",children:"Write Short Paragraph (Preview)"}),e("p",{className:"mt-1 text-sm text-gray-500",children:"Chế độ xem trước"})]}),t(n,{variant:"outline",size:"sm",onClick:()=>$(!1),children:[e(u,{className:"mr-2 h-4 w-4"}),"Quay lại Edit Mode"]})]})})]}),e(N,{questionData:i,onSubmit:()=>{}})]})}return t("div",{className:"space-y-6",children:[t(c,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-blue-100/50",children:[e("div",{className:"h-1.5 bg-gradient-to-r from-blue-500 via-indigo-500 to-purple-500"}),e(m,{children:t("div",{className:"flex items-center justify-between",children:[t("div",{children:[e(h,{className:"text-xl font-bold tracking-tight text-gray-900",children:"Write Short Paragraph"}),e("p",{className:"mt-1 text-sm text-gray-500",children:"Tạo bài tập viết đoạn văn với nhiều content (ảnh, audio, text)"})]}),t(n,{variant:"outline",size:"sm",onClick:()=>$(!0),disabled:0===W.length||S<1,children:[e(g,{className:"mr-2 h-4 w-4"}),"Client Mode"]})]})}),t(d,{className:"space-y-4",children:[t("div",{className:"space-y-1.5",children:[e(s,{htmlFor:"instruction",className:"text-sm font-semibold text-gray-700",children:"Hướng dẫn"}),e(l,{id:"instruction",value:U,onChange:e=>P(e.target.value),placeholder:"Ví dụ: Look at the three pictures. Write about this story.",className:"mt-1",rows:2})]}),t("div",{className:"grid grid-cols-2 gap-4",children:[t("div",{className:"space-y-1.5",children:[e(s,{htmlFor:"minWords",className:"text-sm font-semibold text-gray-700",children:"Số từ tối thiểu *"}),e(o,{id:"minWords",type:"number",min:"1",value:S,onChange:e=>j(parseInt(e.target.value)||1),placeholder:"20",className:"mt-1"})]}),t("div",{className:"space-y-1.5",children:[e(s,{htmlFor:"maxWords",className:"text-sm font-semibold text-gray-700",children:"Số từ tối đa (tùy chọn)"}),e(o,{id:"maxWords",type:"number",min:S,value:z||"",onChange:e=>T(e.target.value?parseInt(e.target.value):void 0),placeholder:"Không giới hạn",className:"mt-1"})]})]})]})]}),t(c,{className:"overflow-hidden border-0 bg-white shadow-xl shadow-blue-100/40 ring-1 ring-gray-100",children:[e(m,{className:"bg-gradient-to-br from-indigo-50/50 via-white to-blue-50/30 pb-4",children:t("div",{className:"flex items-center justify-between",children:[t("div",{className:"flex items-center gap-3",children:[e("div",{className:"flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-blue-500 to-indigo-600 shadow-md",children:e(b,{className:"h-5 w-5 text-white"})}),t("div",{children:[e(h,{className:"text-lg font-bold text-gray-900",children:"Contexts"}),e("p",{className:"mt-1 text-sm text-gray-500",children:"Thêm các context (ảnh, audio, hoặc text) để học sinh xem khi viết"})]})]}),t("div",{className:"flex gap-2",children:[t(n,{variant:"outline",size:"sm",onClick:()=>M("image"),className:"flex items-center gap-2 border-indigo-200 bg-indigo-50 text-indigo-700 hover:bg-indigo-100 hover:text-indigo-800",children:[e(p,{className:"h-4 w-4"}),"Thêm ảnh"]}),t(n,{variant:"outline",size:"sm",onClick:()=>M("audio"),className:"flex items-center gap-2 border-purple-200 bg-purple-50 text-purple-700 hover:bg-purple-100 hover:text-purple-800",children:[e(v,{className:"h-4 w-4"}),"Thêm audio"]}),t(n,{variant:"outline",size:"sm",onClick:()=>M("text"),className:"flex items-center gap-2 border-blue-200 bg-blue-50 text-blue-700 hover:bg-blue-100 hover:text-blue-800",children:[e(b,{className:"h-4 w-4"}),"Thêm text"]})]})]})}),e(d,{className:"space-y-4 pt-6",children:W.length>0?W.map((t,i)=>e(C,{context:t,index:i,onUpdate:E,onRemove:q},t.id)):t("div",{className:"flex flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50 p-12",children:[e("div",{className:"mb-4 rounded-full bg-gray-200 p-4",children:e(p,{className:"h-8 w-8 text-gray-400"})}),e("p",{className:"mb-2 text-sm font-medium text-gray-700",children:"Chưa có context nào"}),e("p",{className:"mb-4 text-xs text-gray-500",children:"Nhấn các nút bên trên để thêm context"})]})})]})]})}function C({context:i,index:r,onUpdate:a,onRemove:o}){const{previewUrl:c}=y("text"!==i.type&&i.url||"");return e("div",{className:"rounded-lg border bg-white p-4 shadow-sm transition-shadow hover:shadow-md",children:t("div",{className:"flex items-start gap-4",children:[e("div",{className:"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full bg-blue-500 text-white shadow-md",children:e("span",{className:"text-sm font-bold",children:r+1})}),t("div",{className:"flex-1 space-y-3",children:[t("div",{className:"flex items-center gap-2",children:[(()=>{switch(i.type){case"image":return e(p,{className:"h-5 w-5"});case"audio":return e(v,{className:"h-5 w-5"});case"text":return e(b,{className:"h-5 w-5"})}})(),t(s,{className:"text-sm font-semibold text-gray-700",children:["Context ",r+1," - ",(()=>{switch(i.type){case"image":return"Ảnh";case"audio":return"Audio";case"text":return"Text"}})()]})]}),"text"===i.type?t("div",{children:[e(s,{className:"text-sm font-semibold text-gray-700",children:"Nội dung text *"}),e(l,{value:i.text||"",onChange:e=>a(i.id,"text",e.target.value),placeholder:"Nhập nội dung text...",className:"mt-1",rows:3})]}):e("div",{children:e(f,{id:`context-${i.id}`,label:"image"===i.type?"URL ảnh *":"URL audio *",accept:"image"===i.type?"image/*":"audio/*",value:i.url||"",onChange:e=>a(i.id,"url",e),maxSize:"image"===i.type?5:10,placeholder:"Paste URL hoặc upload file",autoUpload:!0,prefix:"questions"})}),"image"===i.type&&c&&e("div",{className:"relative h-48 w-full overflow-hidden rounded border",children:e("img",{src:c,alt:`Context ${r+1} preview`,className:"h-full w-full object-contain",onError:()=>{console.error("Failed to load image:",i.url)}})}),"audio"===i.type&&i.url&&e("div",{className:"rounded border bg-gray-50 p-3",children:e("audio",{controls:!0,className:"w-full",src:c||i.url,children:"Your browser does not support the audio element."})})]}),e(n,{type:"button",variant:"ghost",size:"icon",onClick:()=>o(i.id),className:"flex-shrink-0 text-gray-400 hover:text-red-500",children:e(x,{className:"h-5 w-5"})})]})})}export function WriteShortParagraphCreator({initialData:i,onSave:r,onCancel:a,onChange:s}){const o=()=>{i?.contexts&&0!==i.contexts.length&&(!i.minWords||i.minWords<1||r?.(i))};return t("div",{className:"space-y-6",children:[e(w,{initialData:i,onSave:o,onCancel:a,onChange:s}),t("div",{className:"flex justify-end gap-3",children:[e(n,{variant:"outline",onClick:a,children:"Hủy"}),e(n,{onClick:o,className:"bg-blue-500 hover:bg-blue-600",disabled:!i?.contexts||0===i.contexts.length||!i.minWords||i.minWords<1,children:"Lưu câu hỏi"})]})]})}
@@ -1,2 +1 @@
1
- export * from './WriteShortParagraphCreator';
2
- export * from './WriteShortParagraphClient';
1
+ export*from"./WriteShortParagraphCreator";export*from"./WriteShortParagraphClient";
@@ -1,4 +1 @@
1
- import { WriteShortParagraphCreator } from './WriteShortParagraphCreator';
2
- export const writeShortParagraphRegistration = {
3
- component: WriteShortParagraphCreator,
4
- };
1
+ import{WriteShortParagraphCreator as r}from"./WriteShortParagraphCreator";export const writeShortParagraphRegistration={component:r};
@@ -1,21 +1 @@
1
- export const transformWriteShortParagraph = (question) => {
2
- const answerData = question.answer;
3
- const contexts = (answerData?.contexts || []).map((ctx) => {
4
- if (ctx.type === 'text') {
5
- return { type: ctx.type, text: ctx.text || '' };
6
- }
7
- return { type: ctx.type, url: ctx.url || '' };
8
- });
9
- return {
10
- apiContent: {
11
- contexts,
12
- minWords: answerData?.minWords || 0,
13
- maxWords: answerData?.maxWords,
14
- instruction: answerData?.instruction,
15
- },
16
- apiCorrectAnswer: {
17
- minWords: answerData?.minWords || 0,
18
- maxWords: answerData?.maxWords || 100,
19
- },
20
- };
21
- };
1
+ export const transformWriteShortParagraph=t=>{const r=t.answer;return{apiContent:{contexts:(r?.contexts||[]).map(t=>"text"===t.type?{type:t.type,text:t.text||""}:{type:t.type,url:t.url||""}),minWords:r?.minWords||0,maxWords:r?.maxWords,instruction:r?.instruction},apiCorrectAnswer:{minWords:r?.minWords||0,maxWords:r?.maxWords||100}}};
@@ -1,36 +1 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import Image from 'next/image';
4
- import { Badge } from '../../../components/ui/badge';
5
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../../../components/ui/card';
6
- import { FileText, Music, Video, Image as ImageIcon, Volume2, Play } from 'lucide-react';
7
- export function QuestionGroupViewer({ group, showQuestions = true, compact = false, }) {
8
- const getGroupTypeIcon = () => {
9
- switch (group.type) {
10
- case 'READING_PASSAGE':
11
- return _jsx(FileText, { className: "h-5 w-5 text-blue-600" });
12
- case 'LISTENING_AUDIO':
13
- return _jsx(Music, { className: "h-5 w-5 text-purple-600" });
14
- case 'LISTENING_VIDEO':
15
- return _jsx(Video, { className: "h-5 w-5 text-red-600" });
16
- case 'IMAGE_BASED':
17
- return _jsx(ImageIcon, { className: "h-5 w-5 text-green-600" });
18
- default:
19
- return _jsx(FileText, { className: "h-5 w-5 text-gray-600" });
20
- }
21
- };
22
- const getGroupTypeLabel = () => {
23
- const labels = {
24
- READING_PASSAGE: 'Đọc hiểu - Đoạn văn',
25
- LISTENING_AUDIO: 'Nghe - Audio/Hội thoại',
26
- LISTENING_VIDEO: 'Nghe - Video',
27
- IMAGE_BASED: 'Dựa vào hình ảnh',
28
- MIXED: 'Kết hợp nhiều loại',
29
- };
30
- return labels[group.type] || group.type;
31
- };
32
- if (compact) {
33
- return (_jsxs("div", { className: "rounded-lg border border-gray-200 p-4 hover:bg-gray-50", children: [_jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex items-start gap-3", children: [getGroupTypeIcon(), _jsxs("div", { children: [_jsx("h3", { className: "font-semibold", children: group.name }), _jsx("p", { className: "text-sm text-gray-500", children: getGroupTypeLabel() })] })] }), _jsxs("div", { className: "flex flex-col items-end gap-1", children: [_jsxs(Badge, { className: "bg-blue-100 text-blue-700", children: [group.questionCount, " c\u00E2u h\u1ECFi"] }), _jsxs(Badge, { className: "bg-green-100 text-green-700", children: [group.totalPoints, " \u0111i\u1EC3m"] })] })] }), group.description && _jsx("p", { className: "mt-2 text-sm text-gray-600", children: group.description }), _jsxs("div", { className: "mt-3 flex flex-wrap gap-2", children: [_jsx(Badge, { variant: "outline", children: group.level }), _jsx(Badge, { variant: "outline", children: group.skill }), group.category && _jsx(Badge, { variant: "secondary", children: group.category }), group.tags?.map((tag) => (_jsx(Badge, { variant: "secondary", className: "bg-gray-100", children: tag }, tag)))] })] }));
34
- }
35
- return (_jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex items-start gap-3", children: [getGroupTypeIcon(), _jsxs("div", { children: [_jsx(CardTitle, { children: group.name }), _jsx(CardDescription, { className: "mt-1", children: getGroupTypeLabel() })] })] }), _jsxs("div", { className: "flex flex-col items-end gap-2", children: [_jsxs(Badge, { className: "bg-blue-100 text-blue-700", children: [group.questionCount, " c\u00E2u h\u1ECFi"] }), _jsxs(Badge, { className: "bg-green-100 text-green-700", children: ["T\u1ED5ng ", group.totalPoints, " \u0111i\u1EC3m"] })] })] }) }), _jsxs(CardContent, { className: "space-y-4", children: [group.description && _jsx("p", { className: "text-gray-700", children: group.description }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Badge, { variant: "outline", children: group.level }), _jsx(Badge, { variant: "outline", children: group.skill }), group.category && _jsx(Badge, { variant: "secondary", children: group.category }), group.tags?.map((tag) => (_jsx(Badge, { variant: "secondary", className: "bg-gray-100", children: tag }, tag)))] }), group.allowShuffle && (_jsx("div", { className: "rounded-lg border border-yellow-200 bg-yellow-50 p-3", children: _jsx("p", { className: "text-sm text-yellow-800", children: "\u2139\uFE0F C\u00E2u h\u1ECFi trong nh\u00F3m n\u00E0y c\u00F3 th\u1EC3 \u0111\u01B0\u1EE3c x\u00E1o tr\u1ED9n th\u1EE9 t\u1EF1" }) }))] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "N\u1ED9i dung chung" }), _jsx(CardDescription, { children: "Context m\u00E0 t\u1EA5t c\u1EA3 c\u00E2u h\u1ECFi trong nh\u00F3m s\u1EBD s\u1EED d\u1EE5ng" })] }), _jsxs(CardContent, { className: "space-y-4", children: [group.context.instructions && (_jsxs("div", { className: "rounded-lg border border-blue-200 bg-blue-50 p-4", children: [_jsx("p", { className: "font-medium text-blue-900", children: "H\u01B0\u1EDBng d\u1EABn:" }), _jsx("p", { className: "mt-1 text-blue-800", children: group.context.instructions })] })), group.context.passage && (_jsxs("div", { className: "rounded-lg border p-4", children: [group.context.passageTitle && (_jsx("h4", { className: "mb-2 text-lg font-semibold", children: group.context.passageTitle })), _jsx("div", { className: "prose max-w-none", children: _jsx("p", { className: "whitespace-pre-wrap text-gray-700", children: group.context.passage }) })] })), group.context.audioUrl && (_jsxs("div", { className: "rounded-lg border p-4", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(Volume2, { className: "h-5 w-5 text-purple-600" }), _jsx("h4", { className: "font-semibold", children: "Audio" })] }), _jsx("audio", { controls: true, className: "w-full", src: group.context.audioUrl, children: "Your browser does not support the audio element." }), group.context.audioScript && (_jsxs("div", { className: "mt-3", children: [_jsx("p", { className: "text-sm font-medium text-gray-600", children: "Transcript:" }), _jsx("p", { className: "mt-1 text-sm whitespace-pre-wrap text-gray-700", children: group.context.audioScript })] }))] })), group.context.videoUrl && (_jsxs("div", { className: "rounded-lg border p-4", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(Play, { className: "h-5 w-5 text-red-600" }), _jsx("h4", { className: "font-semibold", children: "Video" })] }), _jsx("video", { controls: true, className: "w-full rounded", src: group.context.videoUrl, children: "Your browser does not support the video element." }), group.context.videoScript && (_jsxs("div", { className: "mt-3", children: [_jsx("p", { className: "text-sm font-medium text-gray-600", children: "Transcript:" }), _jsx("p", { className: "mt-1 text-sm whitespace-pre-wrap text-gray-700", children: group.context.videoScript })] }))] })), group.context.imageUrl && (_jsxs("div", { className: "rounded-lg border p-4", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(ImageIcon, { className: "h-5 w-5 text-green-600" }), _jsx("h4", { className: "font-semibold", children: "H\u00ECnh \u1EA3nh" })] }), _jsx("div", { className: "relative h-auto w-full", children: _jsx(Image, { src: group.context.imageUrl, alt: group.context.imageCaption || 'Group image', width: 800, height: 600, className: "max-w-full rounded", style: { width: '100%', height: 'auto' } }) }), group.context.imageCaption && (_jsx("p", { className: "mt-2 text-sm text-gray-600", children: group.context.imageCaption }))] }))] })] }), showQuestions && group.questions && group.questions.length > 0 && (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs(CardTitle, { children: ["C\u00E2u h\u1ECFi trong nh\u00F3m (", group.questions.length, ")"] }), _jsx(CardDescription, { children: "C\u00E1c c\u00E2u h\u1ECFi s\u1EBD s\u1EED d\u1EE5ng context chung b\u00EAn tr\u00EAn" })] }), _jsx(CardContent, { children: _jsx("div", { className: "space-y-3", children: group.questions.map((question, index) => (_jsx("div", { className: "rounded-lg border bg-white p-4", children: _jsx("div", { className: "flex items-start justify-between", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("span", { className: "flex h-8 w-8 items-center justify-center rounded-full bg-blue-100 text-sm font-semibold text-blue-700", children: index + 1 }), _jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "mb-2 flex flex-wrap gap-2", children: [_jsx(Badge, { variant: "outline", children: question.type }), _jsx(Badge, { variant: "outline", children: question.difficulty }), _jsxs(Badge, { className: "bg-green-100 text-green-700", children: [question.points, " \u0111i\u1EC3m"] })] }), _jsx("p", { className: "text-gray-800", children: question.content }), question.explanation && (_jsxs("p", { className: "mt-2 text-sm text-gray-500", children: ["\uD83D\uDCA1 ", question.explanation] }))] })] }) }) }, question.id))) }) })] }))] }));
36
- }
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import a from"next/image";import{Badge as l}from"../../../components/ui/badge";import{Card as s,CardContent as i,CardDescription as r,CardHeader as n,CardTitle as c}from"../../../components/ui/card";import{FileText as d,Music as o,Video as m,Image as h,Volume2 as p,Play as u}from"lucide-react";export function QuestionGroupViewer({group:g,showQuestions:x=!0,compact:N=!1}){const b=()=>{switch(g.type){case"READING_PASSAGE":return e(d,{className:"h-5 w-5 text-blue-600"});case"LISTENING_AUDIO":return e(o,{className:"h-5 w-5 text-purple-600"});case"LISTENING_VIDEO":return e(m,{className:"h-5 w-5 text-red-600"});case"IMAGE_BASED":return e(h,{className:"h-5 w-5 text-green-600"});default:return e(d,{className:"h-5 w-5 text-gray-600"})}},v=()=>({READING_PASSAGE:"Đọc hiểu - Đoạn văn",LISTENING_AUDIO:"Nghe - Audio/Hội thoại",LISTENING_VIDEO:"Nghe - Video",IMAGE_BASED:"Dựa vào hình ảnh",MIXED:"Kết hợp nhiều loại"}[g.type]||g.type);return t("div",N?{className:"rounded-lg border border-gray-200 p-4 hover:bg-gray-50",children:[t("div",{className:"flex items-start justify-between",children:[t("div",{className:"flex items-start gap-3",children:[b(),t("div",{children:[e("h3",{className:"font-semibold",children:g.name}),e("p",{className:"text-sm text-gray-500",children:v()})]})]}),t("div",{className:"flex flex-col items-end gap-1",children:[t(l,{className:"bg-blue-100 text-blue-700",children:[g.questionCount," câu hỏi"]}),t(l,{className:"bg-green-100 text-green-700",children:[g.totalPoints," điểm"]})]})]}),g.description&&e("p",{className:"mt-2 text-sm text-gray-600",children:g.description}),t("div",{className:"mt-3 flex flex-wrap gap-2",children:[e(l,{variant:"outline",children:g.level}),e(l,{variant:"outline",children:g.skill}),g.category&&e(l,{variant:"secondary",children:g.category}),g.tags?.map(t=>e(l,{variant:"secondary",className:"bg-gray-100",children:t},t))]})]}:{className:"space-y-6",children:[t(s,{children:[e(n,{children:t("div",{className:"flex items-start justify-between",children:[t("div",{className:"flex items-start gap-3",children:[b(),t("div",{children:[e(c,{children:g.name}),e(r,{className:"mt-1",children:v()})]})]}),t("div",{className:"flex flex-col items-end gap-2",children:[t(l,{className:"bg-blue-100 text-blue-700",children:[g.questionCount," câu hỏi"]}),t(l,{className:"bg-green-100 text-green-700",children:["Tổng ",g.totalPoints," điểm"]})]})]})}),t(i,{className:"space-y-4",children:[g.description&&e("p",{className:"text-gray-700",children:g.description}),t("div",{className:"flex flex-wrap gap-2",children:[e(l,{variant:"outline",children:g.level}),e(l,{variant:"outline",children:g.skill}),g.category&&e(l,{variant:"secondary",children:g.category}),g.tags?.map(t=>e(l,{variant:"secondary",className:"bg-gray-100",children:t},t))]}),g.allowShuffle&&e("div",{className:"rounded-lg border border-yellow-200 bg-yellow-50 p-3",children:e("p",{className:"text-sm text-yellow-800",children:"ℹ️ Câu hỏi trong nhóm này có thể được xáo trộn thứ tự"})})]})]}),t(s,{children:[t(n,{children:[e(c,{children:"Nội dung chung"}),e(r,{children:"Context mà tất cả câu hỏi trong nhóm sẽ sử dụng"})]}),t(i,{className:"space-y-4",children:[g.context.instructions&&t("div",{className:"rounded-lg border border-blue-200 bg-blue-50 p-4",children:[e("p",{className:"font-medium text-blue-900",children:"Hướng dẫn:"}),e("p",{className:"mt-1 text-blue-800",children:g.context.instructions})]}),g.context.passage&&t("div",{className:"rounded-lg border p-4",children:[g.context.passageTitle&&e("h4",{className:"mb-2 text-lg font-semibold",children:g.context.passageTitle}),e("div",{className:"prose max-w-none",children:e("p",{className:"whitespace-pre-wrap text-gray-700",children:g.context.passage})})]}),g.context.audioUrl&&t("div",{className:"rounded-lg border p-4",children:[t("div",{className:"mb-2 flex items-center gap-2",children:[e(p,{className:"h-5 w-5 text-purple-600"}),e("h4",{className:"font-semibold",children:"Audio"})]}),e("audio",{controls:!0,className:"w-full",src:g.context.audioUrl,children:"Your browser does not support the audio element."}),g.context.audioScript&&t("div",{className:"mt-3",children:[e("p",{className:"text-sm font-medium text-gray-600",children:"Transcript:"}),e("p",{className:"mt-1 text-sm whitespace-pre-wrap text-gray-700",children:g.context.audioScript})]})]}),g.context.videoUrl&&t("div",{className:"rounded-lg border p-4",children:[t("div",{className:"mb-2 flex items-center gap-2",children:[e(u,{className:"h-5 w-5 text-red-600"}),e("h4",{className:"font-semibold",children:"Video"})]}),e("video",{controls:!0,className:"w-full rounded",src:g.context.videoUrl,children:"Your browser does not support the video element."}),g.context.videoScript&&t("div",{className:"mt-3",children:[e("p",{className:"text-sm font-medium text-gray-600",children:"Transcript:"}),e("p",{className:"mt-1 text-sm whitespace-pre-wrap text-gray-700",children:g.context.videoScript})]})]}),g.context.imageUrl&&t("div",{className:"rounded-lg border p-4",children:[t("div",{className:"mb-2 flex items-center gap-2",children:[e(h,{className:"h-5 w-5 text-green-600"}),e("h4",{className:"font-semibold",children:"Hình ảnh"})]}),e("div",{className:"relative h-auto w-full",children:e(a,{src:g.context.imageUrl,alt:g.context.imageCaption||"Group image",width:800,height:600,className:"max-w-full rounded",style:{width:"100%",height:"auto"}})}),g.context.imageCaption&&e("p",{className:"mt-2 text-sm text-gray-600",children:g.context.imageCaption})]})]})]}),x&&g.questions&&g.questions.length>0&&t(s,{children:[t(n,{children:[t(c,{children:["Câu hỏi trong nhóm (",g.questions.length,")"]}),e(r,{children:"Các câu hỏi sẽ sử dụng context chung bên trên"})]}),e(i,{children:e("div",{className:"space-y-3",children:g.questions.map((a,s)=>e("div",{className:"rounded-lg border bg-white p-4",children:e("div",{className:"flex items-start justify-between",children:t("div",{className:"flex items-start gap-3",children:[e("span",{className:"flex h-8 w-8 items-center justify-center rounded-full bg-blue-100 text-sm font-semibold text-blue-700",children:s+1}),t("div",{className:"flex-1",children:[t("div",{className:"mb-2 flex flex-wrap gap-2",children:[e(l,{variant:"outline",children:a.type}),e(l,{variant:"outline",children:a.difficulty}),t(l,{className:"bg-green-100 text-green-700",children:[a.points," điểm"]})]}),e("p",{className:"text-gray-800",children:a.content}),a.explanation&&t("p",{className:"mt-2 text-sm text-gray-500",children:["💡 ",a.explanation]})]})]})})},a.id))})})]})]})}