@tinyweb_dev/oe-exam-sdk 1.0.6 → 1.0.7

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 (225) hide show
  1. package/dist/components/exams/ExamCreator.js +1 -16
  2. package/dist/components/exams/take/ExamTakingPageContainer.js +0 -12
  3. package/dist/components/exams/take/components/QuestionRenderer.js +2 -15
  4. package/dist/components/exams/take/components/question-renderers/index.d.ts +0 -3
  5. package/dist/components/exams/take/components/question-renderers/index.js +0 -3
  6. package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionRenderer.js +0 -4
  7. package/dist/components/exams/take/types/speaking.types.d.ts +0 -31
  8. package/dist/components/exams/take/types.d.ts +0 -65
  9. package/dist/components/exams/take/utils/answer-transformers.js +6 -60
  10. package/dist/components/exams/take/utils/question-transformers.d.ts +2 -15
  11. package/dist/components/exams/take/utils/question-transformers.js +0 -143
  12. package/dist/components/questions/_shared/components/compact/CompactCreatorHeader.d.ts +23 -0
  13. package/dist/components/questions/_shared/components/compact/CompactCreatorHeader.js +9 -0
  14. package/dist/components/questions/_shared/components/compact/CompactExampleToggle.d.ts +6 -0
  15. package/dist/components/questions/_shared/components/compact/CompactExampleToggle.js +8 -0
  16. package/dist/components/questions/_shared/components/compact/CompactExplanationToggle.d.ts +7 -0
  17. package/dist/components/questions/_shared/components/compact/CompactExplanationToggle.js +14 -0
  18. package/dist/components/questions/_shared/components/compact/CompactFieldCard.d.ts +9 -0
  19. package/dist/components/questions/_shared/components/compact/CompactFieldCard.js +7 -0
  20. package/dist/components/questions/_shared/components/compact/CompactPreviewBanner.d.ts +7 -0
  21. package/dist/components/questions/_shared/components/compact/CompactPreviewBanner.js +7 -0
  22. package/dist/components/questions/_shared/components/compact/CompactPreviewButton.d.ts +6 -0
  23. package/dist/components/questions/_shared/components/compact/CompactPreviewButton.js +7 -0
  24. package/dist/components/questions/_shared/components/compact/index.d.ts +6 -0
  25. package/dist/components/questions/_shared/components/compact/index.js +6 -0
  26. package/dist/components/questions/_shared/config/question-types.config.js +0 -24
  27. package/dist/components/questions/_shared/hooks/useQuestionInitialization.js +0 -9
  28. package/dist/components/questions/_shared/types/index.d.ts +0 -1
  29. package/dist/components/questions/_shared/types/index.js +0 -1
  30. package/dist/components/questions/_shared/types/look-and-choose-answer.type.d.ts +0 -13
  31. package/dist/components/questions/_shared/utils/answer-builder.js +0 -11
  32. package/dist/components/questions/components/ColorRegionCreator.js +66 -63
  33. package/dist/components/questions/components/QuestionSearchDropdown.js +0 -8
  34. package/dist/components/questions/components/QuestionTypeSelector.js +0 -2
  35. package/dist/components/questions/components/index.d.ts +1 -0
  36. package/dist/components/questions/components/index.js +1 -0
  37. package/dist/components/questions/creator/question-type-registry.js +0 -8
  38. package/dist/components/questions/groups/ArticlesGroupCard.js +2 -2
  39. package/dist/components/questions/groups/BasicQuestionGroupCard.js +1 -1
  40. package/dist/components/questions/groups/DocumentGroupCard.js +1 -1
  41. package/dist/components/questions/groups/ImageLabelGroupCard.js +1 -1
  42. package/dist/components/questions/groups/MatchAnswerGroupCard.js +2 -2
  43. package/dist/components/questions/question-bank/QuestionEditorRenderer.d.ts +0 -3
  44. package/dist/components/questions/question-bank/QuestionEditorRenderer.js +1 -10
  45. package/dist/components/questions/question-bank/editor-adapters/choice-adapters.d.ts +0 -2
  46. package/dist/components/questions/question-bank/editor-adapters/choice-adapters.js +0 -41
  47. package/dist/components/questions/question-bank/editor-adapters/index.d.ts +2 -2
  48. package/dist/components/questions/question-bank/editor-adapters/index.js +2 -2
  49. package/dist/components/questions/question-bank/editor-adapters/media-adapters.d.ts +0 -1
  50. package/dist/components/questions/question-bank/editor-adapters/media-adapters.js +0 -28
  51. package/dist/components/questions/question-bank/question-bank-picker.utils.js +0 -7
  52. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +16 -16
  53. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionCreator.js +36 -30
  54. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupClient.js +1 -1
  55. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupCreator.js +7 -6
  56. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +2 -2
  57. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsCreator.js +11 -7
  58. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +1 -1
  59. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js +11 -5
  60. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +5 -5
  61. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +34 -28
  62. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseAnswerGroupImageUpload.js +2 -2
  63. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupClient.js +1 -1
  64. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupCreator.js +44 -28
  65. package/dist/components/questions/types/choose-then-answer-group/ChooseThenAnswerGroupClient.js +7 -7
  66. package/dist/components/questions/types/choose-then-answer-group/ChooseThenAnswerGroupCreator.js +8 -5
  67. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupClient.js +2 -2
  68. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupCreator.js +20 -16
  69. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleClient.js +1 -1
  70. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleCreator.js +66 -29
  71. package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +5 -5
  72. package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +45 -37
  73. package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupCreator.js +24 -20
  74. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +2 -2
  75. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridCreator.js +68 -65
  76. package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixClient.js +1 -1
  77. package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixCreator.js +45 -5
  78. package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +2 -2
  79. package/dist/components/questions/types/label-the-picture/LabelThePictureCreator.js +18 -14
  80. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +2 -2
  81. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupCreator.js +30 -30
  82. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneClient.js +2 -2
  83. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneCreator.js +24 -31
  84. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneClient.js +2 -2
  85. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneCreator.js +29 -32
  86. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +1 -1
  87. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerCreator.js +27 -29
  88. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +1 -1
  89. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesCreator.js +11 -15
  90. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +1 -1
  91. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupCreator.js +22 -24
  92. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +1 -1
  93. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeCreator.js +17 -24
  94. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +1 -1
  95. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutCreator.js +31 -31
  96. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +1 -1
  97. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListCreator.js +11 -15
  98. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +1 -1
  99. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesCreator.js +14 -15
  100. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +2 -2
  101. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerCreator.js +27 -25
  102. package/dist/components/questions/types/match-columns-to-make-sentences/MatchColumnsToMakeSentencesClient.js +12 -12
  103. package/dist/components/questions/types/match-columns-to-make-sentences/MatchColumnsToMakeSentencesCreator.js +8 -5
  104. package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureClient.js +8 -8
  105. package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureCreator.js +25 -20
  106. package/dist/components/questions/types/match-word-to-picture-group/MatchWordToPictureGroupClient.js +1 -1
  107. package/dist/components/questions/types/match-word-to-picture-group/MatchWordToPictureGroupCreator.js +13 -10
  108. package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesGroupCreator.js +8 -5
  109. package/dist/components/questions/types/read-displayed-content/ReadDisplayedContentCreator.js +7 -11
  110. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +1 -1
  111. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsCreator.js +15 -12
  112. package/dist/components/questions/types/sort-words-into-categories/SortWordsIntoCategoriesClient.js +1 -1
  113. package/dist/components/questions/types/sort-words-into-categories/SortWordsIntoCategoriesCreator.js +5 -5
  114. package/dist/components/questions/types/speaking-conversation/SpeakingConversationCreator.js +35 -39
  115. package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +2 -2
  116. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardClient.js +1 -1
  117. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +7 -8
  118. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +1 -1
  119. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageCreator.js +30 -23
  120. package/dist/components/questions/types/spontaneous-qa/SpontaneousQAClient.js +1 -1
  121. package/dist/components/questions/types/spontaneous-qa/SpontaneousQACreator.js +26 -19
  122. package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupClient.js +1 -1
  123. package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupCreator.js +13 -11
  124. package/dist/components/questions/types/true-false/TrueFalseClient.js +2 -2
  125. package/dist/components/questions/types/true-false/TrueFalseCreator.js +35 -29
  126. package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupClient.js +1 -1
  127. package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupCreator.js +11 -7
  128. package/dist/components/questions/types/true-false-group/TrueFalseGroupClient.js +1 -1
  129. package/dist/components/questions/types/true-false-group/TrueFalseGroupCreator.js +11 -7
  130. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +2 -2
  131. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphCreator.js +21 -56
  132. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -1
  133. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +30 -24
  134. package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupClient.js +3 -3
  135. package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupCreator.js +12 -14
  136. package/dist/components/questions/types/word-ordering/WordOrderingClient.js +1 -1
  137. package/dist/components/questions/types/word-ordering/WordOrderingCreator.js +27 -18
  138. package/dist/components/questions/types/word-ordering-group/WordOrderingGroupClient.js +7 -7
  139. package/dist/components/questions/types/word-ordering-group/WordOrderingGroupCreator.js +16 -13
  140. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +2 -2
  141. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +34 -28
  142. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +2 -2
  143. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js +22 -22
  144. package/dist/components/questions/types/write-sentences/WriteSentencesCreator.js +21 -18
  145. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphClient.js +1 -1
  146. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphCreator.js +7 -4
  147. package/dist/components/questions/viewer/QuestionViewer.js +0 -98
  148. package/dist/components/results/renderers/review-question-body-movers.js +2 -26
  149. package/dist/components/results/review-data.js +0 -4
  150. package/dist/components/ui/points-input.d.ts +1 -0
  151. package/dist/components/ui/points-input.js +12 -2
  152. package/dist/shared/constants/question-skills.js +0 -11
  153. package/dist/shared/lib/i18n/messages/en/admin.d.ts +0 -3
  154. package/dist/shared/lib/i18n/messages/en/admin.js +0 -3
  155. package/dist/shared/lib/i18n/messages/en.d.ts +0 -3
  156. package/dist/shared/lib/i18n/messages/vi/admin.d.ts +0 -3
  157. package/dist/shared/lib/i18n/messages/vi/admin.js +0 -3
  158. package/dist/shared/lib/i18n/messages/vi.d.ts +0 -3
  159. package/dist/shared/lib/utils/question-reverse-transform.js +0 -19
  160. package/dist/shared/lib/utils/question-transform-types.d.ts +1 -23
  161. package/dist/shared/lib/utils/question-transform-validation.js +0 -40
  162. package/dist/shared/lib/utils/question-transform.js +0 -9
  163. package/dist/shared/types/common.types.d.ts +1 -1
  164. package/dist/shared/types/entities/question.types.d.ts +1 -11
  165. package/dist/shared/types/questions/index.d.ts +0 -3
  166. package/dist/shared/types/questions/index.js +0 -6
  167. package/package.json +1 -1
  168. package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.d.ts +0 -2
  169. package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.js +0 -131
  170. package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.d.ts +0 -2
  171. package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.js +0 -76
  172. package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.d.ts +0 -2
  173. package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.js +0 -68
  174. package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.d.ts +0 -16
  175. package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.js +0 -212
  176. package/dist/components/questions/_shared/types/gn-speaking-interview.type.d.ts +0 -32
  177. package/dist/components/questions/_shared/types/gn-speaking-interview.type.js +0 -1
  178. package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.d.ts +0 -47
  179. package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.js +0 -1
  180. package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.d.ts +0 -2
  181. package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.js +0 -262
  182. package/dist/components/questions/types/gn-speaking-interview/register.d.ts +0 -2
  183. package/dist/components/questions/types/gn-speaking-interview/register.js +0 -121
  184. package/dist/components/questions/types/gn-speaking-interview/transform.d.ts +0 -2
  185. package/dist/components/questions/types/gn-speaking-interview/transform.js +0 -48
  186. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.d.ts +0 -20
  187. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.js +0 -72
  188. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.d.ts +0 -15
  189. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.js +0 -230
  190. package/dist/components/questions/types/look-picture-choose-correct-answer/index.d.ts +0 -1
  191. package/dist/components/questions/types/look-picture-choose-correct-answer/index.js +0 -1
  192. package/dist/components/questions/types/look-picture-choose-correct-answer/register.d.ts +0 -2
  193. package/dist/components/questions/types/look-picture-choose-correct-answer/register.js +0 -66
  194. package/dist/components/questions/types/look-picture-choose-correct-answer/transform.d.ts +0 -2
  195. package/dist/components/questions/types/look-picture-choose-correct-answer/transform.js +0 -42
  196. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.d.ts +0 -6
  197. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.js +0 -96
  198. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.d.ts +0 -15
  199. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.js +0 -238
  200. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.d.ts +0 -2
  201. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.js +0 -2
  202. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.d.ts +0 -2
  203. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.js +0 -76
  204. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.d.ts +0 -2
  205. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.js +0 -19
  206. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.d.ts +0 -7
  207. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.js +0 -134
  208. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.d.ts +0 -3
  209. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.js +0 -617
  210. package/dist/components/questions/types/look-picture-fill-word-hint/index.d.ts +0 -2
  211. package/dist/components/questions/types/look-picture-fill-word-hint/index.js +0 -2
  212. package/dist/components/questions/types/look-picture-fill-word-hint/register.d.ts +0 -2
  213. package/dist/components/questions/types/look-picture-fill-word-hint/register.js +0 -82
  214. package/dist/components/questions/types/look-picture-fill-word-hint/transform.d.ts +0 -2
  215. package/dist/components/questions/types/look-picture-fill-word-hint/transform.js +0 -29
  216. package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.d.ts +0 -9
  217. package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.js +0 -12
  218. package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.d.ts +0 -17
  219. package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.js +0 -47
  220. package/dist/shared/types/questions/look-picture-choose-correct-answer.d.ts +0 -38
  221. package/dist/shared/types/questions/look-picture-choose-correct-answer.js +0 -5
  222. package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.d.ts +0 -63
  223. package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.js +0 -9
  224. package/dist/shared/types/questions/look-picture-fill-word-hint.d.ts +0 -57
  225. package/dist/shared/types/questions/look-picture-fill-word-hint.js +0 -7
@@ -38,7 +38,7 @@ export function ReadPassageAndAnswerQuestionsClient({ questionData, userAnswer,
38
38
  const isCorrect = isReviewMode && selectedAnswer === singleQuestion.correctAnswer;
39
39
  const isWrong = isReviewMode && selectedAnswer >= 0 && selectedAnswer !== singleQuestion.correctAnswer;
40
40
  const hasAnswered = selectedAnswer >= 0;
41
- return (_jsxs("div", { className: "space-y-5", children: [instructions && (_jsx("div", { className: "overflow-hidden rounded-xl border border-blue-200 bg-gradient-to-r from-blue-50 to-indigo-50 shadow-sm", children: _jsxs("div", { className: "flex items-center gap-3 px-5 py-4", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-blue-500 to-indigo-600 text-white shadow-sm", children: _jsx(FileText, { className: "h-4 w-4" }) }), _jsx("p", { className: "text-sm font-medium text-blue-900", children: instructions })] }) })), _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-3 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-5 py-3", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-emerald-500 to-teal-600 text-white shadow-sm", children: _jsx(BookOpen, { className: "h-4 w-4" }) }), _jsx("span", { className: "text-sm font-medium text-gray-700", children: "\u0110o\u1EA1n v\u0103n \u0111\u1ECDc hi\u1EC3u" })] }), _jsxs("div", { className: "p-5 space-y-4", children: [passageTitle && (_jsx("h3", { className: "text-center text-lg font-bold text-gray-900 border-b border-gray-100 pb-3", children: passageTitle })), _jsx("div", { className: "rounded-lg bg-gradient-to-br from-slate-50 to-gray-50 p-5 border border-gray-100", children: _jsx("p", { className: "whitespace-pre-wrap text-base leading-relaxed text-gray-700", children: passage }) })] })] }), _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm transition-all hover:shadow-md", children: [_jsxs("div", { className: cn('flex items-center justify-between border-b px-5 py-3', isReviewMode && isCorrect && 'border-green-200 bg-gradient-to-r from-green-50 to-emerald-50', isReviewMode && isWrong && 'border-red-200 bg-gradient-to-r from-red-50 to-rose-50', !isReviewMode && 'border-gray-100 bg-gradient-to-r from-gray-50 to-white'), children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: cn('flex h-8 w-8 items-center justify-center rounded-lg text-sm font-bold text-white shadow-sm', isReviewMode && isCorrect && 'bg-gradient-to-br from-green-500 to-emerald-600', isReviewMode && isWrong && 'bg-gradient-to-br from-red-500 to-rose-600', !isReviewMode && 'bg-gradient-to-br from-indigo-500 to-purple-600'), children: _jsx(ClipboardList, { className: "h-4 w-4" }) }), _jsx("span", { className: "text-sm font-medium text-gray-800", children: singleQuestion.question })] }), isReviewMode && hasAnswered && (_jsxs("div", { className: cn('flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold', isCorrect ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'), children: [isCorrect ? _jsx(Check, { className: "h-3.5 w-3.5" }) : _jsx(X, { className: "h-3.5 w-3.5" }), isCorrect ? 'Đúng' : 'Sai'] }))] }), _jsxs("div", { className: "p-5 space-y-2.5", children: [singleQuestion.options.map((option, optIndex) => {
41
+ return (_jsxs("div", { className: "space-y-3", children: [instructions && (_jsx("div", { className: "overflow-hidden rounded-xl border border-blue-200 bg-gradient-to-r from-blue-50 to-indigo-50 shadow-sm", children: _jsxs("div", { className: "flex items-center gap-3 px-3 py-2", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-blue-500 to-indigo-600 text-white shadow-sm", children: _jsx(FileText, { className: "h-4 w-4" }) }), _jsx("p", { className: "text-sm font-medium text-blue-900", children: instructions })] }) })), _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-3 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-3 py-2", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-emerald-500 to-teal-600 text-white shadow-sm", children: _jsx(BookOpen, { className: "h-4 w-4" }) }), _jsx("span", { className: "text-sm font-medium text-gray-700", children: "\u0110o\u1EA1n v\u0103n \u0111\u1ECDc hi\u1EC3u" })] }), _jsxs("div", { className: "p-3 space-y-3", children: [passageTitle && (_jsx("h3", { className: "text-center text-lg font-bold text-gray-900 border-b border-gray-100 pb-3", children: passageTitle })), _jsx("div", { className: "rounded-lg bg-gradient-to-br from-slate-50 to-gray-50 p-5 border border-gray-100", children: _jsx("p", { className: "whitespace-pre-wrap text-base leading-relaxed text-gray-700", children: passage }) })] })] }), _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm transition-all hover:shadow-md", children: [_jsxs("div", { className: cn('flex items-center justify-between border-b px-3 py-2', isReviewMode && isCorrect && 'border-green-200 bg-gradient-to-r from-green-50 to-emerald-50', isReviewMode && isWrong && 'border-red-200 bg-gradient-to-r from-red-50 to-rose-50', !isReviewMode && 'border-gray-100 bg-gradient-to-r from-gray-50 to-white'), children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: cn('flex h-8 w-8 items-center justify-center rounded-lg text-sm font-bold text-white shadow-sm', isReviewMode && isCorrect && 'bg-gradient-to-br from-green-500 to-emerald-600', isReviewMode && isWrong && 'bg-gradient-to-br from-red-500 to-rose-600', !isReviewMode && 'bg-gradient-to-br from-indigo-500 to-purple-600'), children: _jsx(ClipboardList, { className: "h-4 w-4" }) }), _jsx("span", { className: "text-sm font-medium text-gray-800", children: singleQuestion.question })] }), isReviewMode && hasAnswered && (_jsxs("div", { className: cn('flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold', isCorrect ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'), children: [isCorrect ? _jsx(Check, { className: "h-3.5 w-3.5" }) : _jsx(X, { className: "h-3.5 w-3.5" }), isCorrect ? 'Đúng' : 'Sai'] }))] }), _jsxs("div", { className: "p-3 space-y-3", children: [singleQuestion.options.map((option, optIndex) => {
42
42
  const isSelected = selectedAnswer === optIndex;
43
43
  const isCorrectOption = optIndex === singleQuestion.correctAnswer;
44
44
  const letter = String.fromCharCode(65 + optIndex);
@@ -5,10 +5,10 @@ import { Button } from '../../../../components/ui/button';
5
5
  import { Label } from '../../../../components/ui/label';
6
6
  import { Input } from '../../../../components/ui/input';
7
7
  import { Textarea } from '../../../../components/ui/textarea';
8
- import { PointsInput } from '../../../../components/ui/points-input';
9
8
  import { Card, CardContent, CardHeader, CardTitle } from '../../../../components/ui/card';
10
9
  import { RadioGroup } from '../../../../components/ui/radio-group';
11
- import { Pencil, Eye, Plus, Trash2, BookOpen, Lightbulb, MessageSquare, CheckCircle2 } from 'lucide-react';
10
+ import { Plus, Trash2, BookOpen, Lightbulb, MessageSquare, CheckCircle2 } from 'lucide-react';
11
+ import { CompactCreatorHeader, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, } from '../../_shared/components/compact';
12
12
  import { ReadPassageAndAnswerQuestionsClient } from './ReadPassageAndAnswerQuestionsClient';
13
13
  import { useDebouncedCallback } from '../../../../shared/lib/hooks';
14
14
  import { useExamQuestionStore } from '../../../../shared/lib/stores/examQuestionStore';
@@ -486,16 +486,19 @@ function ReadPassageAndAnswerQuestionsContent({ initialData, onSave, onSaveToQue
486
486
  singleQuestion: currentQuestion,
487
487
  groups,
488
488
  };
489
- return (_jsxs("div", { className: "space-y-6", children: [_jsx(Card, { children: _jsx(CardHeader, { children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx(CardTitle, { children: "\u0110\u1ECDc \u0111o\u1EA1n v\u0103n v\u00E0 tr\u1EA3 l\u1EDDi c\u00E2u h\u1ECFi (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(ReadPassageAndAnswerQuestionsClient, { questionData: questionData, autoFillCorrectAnswers: true, isReviewMode: true, onSubmit: () => { }, explanation: explanation })] }));
489
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(CompactPreviewBanner, { onBack: () => setIsClientMode(false) }), _jsx(ReadPassageAndAnswerQuestionsClient, { questionData: questionData, autoFillCorrectAnswers: true, isReviewMode: true, onSubmit: () => { }, explanation: explanation })] }));
490
490
  }
491
- 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-purple-500 via-violet-500 to-indigo-500" }), _jsx(CardHeader, { className: "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-purple-500 to-violet-600 shadow-md", children: _jsx(BookOpen, { className: "h-5 w-5 text-white" }) }), _jsxs("div", { children: [_jsx(CardTitle, { className: "text-xl font-bold text-gray-900", children: "\u0110\u1ECDc \u0111o\u1EA1n v\u0103n v\u00E0 tr\u1EA3 l\u1EDDi c\u00E2u h\u1ECFi" }), _jsxs("div", { className: "mt-1.5 inline-flex items-center gap-1.5 rounded-full bg-purple-100 px-3 py-1 text-sm font-medium text-purple-700", children: [_jsx("span", { children: "\uD83D\uDCDA" }), _jsxs("span", { children: ["Nh\u00F3m ", currentGroupNumber] })] })] })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: handlePreview, className: "gap-2 border-violet-200 text-violet-600 hover:bg-violet-50 hover:text-violet-700", children: [_jsx(Eye, { className: "h-4 w-4" }), "Xem tr\u01B0\u1EDBc"] })] }) }), _jsxs(CardContent, { className: "space-y-6", children: [_jsxs("div", { className: `rounded-xl border-2 p-5 transition-all ${validationErrors.passage ? 'border-red-300 bg-gradient-to-r from-red-50 to-rose-50' : 'border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50'}`, children: [_jsxs("div", { className: "mb-4 flex items-center gap-3", children: [_jsx("div", { className: `flex h-8 w-8 items-center justify-center rounded-lg ${validationErrors.passage ? 'bg-red-100' : 'bg-amber-100'}`, children: _jsx(BookOpen, { className: `h-4 w-4 ${validationErrors.passage ? 'text-red-600' : 'text-amber-600'}` }) }), _jsxs(Label, { className: `text-base font-semibold ${validationErrors.passage ? 'text-red-800' : 'text-amber-800'}`, children: ["\u0110o\u1EA1n v\u0103n \u0111\u1ECDc hi\u1EC3u ", _jsxs("span", { className: "font-normal text-amber-600", children: ["(d\u00F9ng chung cho nh\u00F3m ", currentGroupNumber, ")"] })] })] }), _jsxs("div", { className: "mb-4", children: [_jsx(Label, { htmlFor: "passageTitle", className: "text-sm font-medium text-gray-700", children: "Ti\u00EAu \u0111\u1EC1" }), _jsx(Input, { id: "passageTitle", value: passageTitle, onChange: (e) => setPassageTitle(e.target.value), placeholder: "V\u00ED d\u1EE5: Our Family Holiday in Nha Trang", className: "mt-1.5 border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200" })] }), _jsxs("div", { className: "mb-4", children: [_jsxs(Label, { htmlFor: "passage", className: "text-sm font-medium text-gray-700", children: ["N\u1ED9i dung \u0111o\u1EA1n v\u0103n ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Textarea, { id: "passage", value: passage, onChange: (e) => {
492
- setPassage(e.target.value);
493
- if (validationErrors.passage) {
494
- setValidationErrors(prev => ({ ...prev, passage: undefined }));
495
- }
496
- }, placeholder: "Nh\u1EADp n\u1ED9i dung \u0111o\u1EA1n v\u0103n \u0111\u1ECDc hi\u1EC3u...", className: `mt-1.5 min-h-[150px] border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200 ${validationErrors.passage ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}`, rows: 6 }), validationErrors.passage && (_jsx("p", { className: "mt-1.5 text-sm text-red-600", children: validationErrors.passage }))] }), _jsxs("div", { children: [_jsx(Label, { htmlFor: "instructions", className: "text-sm font-medium text-gray-700", children: "H\u01B0\u1EDBng d\u1EABn" }), _jsx(Input, { id: "instructions", value: instructions, onChange: (e) => setInstructions(e.target.value), placeholder: "V\u00ED d\u1EE5: Read the short passage and answer the question below.", className: "mt-1.5 border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200" })] })] }), externalErrors && externalErrors.length > 0 && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-red-200 bg-gradient-to-r from-red-50 to-rose-50 p-4", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-red-100", children: _jsx("span", { className: "text-lg", children: "\u274C" }) }), _jsxs("div", { className: "text-sm", children: [_jsx("p", { className: "font-semibold text-red-800", children: "L\u1ED7i:" }), _jsx("ul", { className: "mt-1 list-inside list-disc text-red-700", children: externalErrors.map((error, index) => (_jsx("li", { children: error }, index))) })] })] }))] })] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-indigo-100/50", children: [_jsx("div", { className: "h-1 bg-gradient-to-r from-indigo-400 to-purple-400" }), _jsx(CardHeader, { className: "bg-gradient-to-r from-indigo-50 to-purple-50 pb-4", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-indigo-100", children: _jsx(MessageSquare, { className: "h-4 w-4 text-indigo-600" }) }), _jsx(CardTitle, { className: "text-lg font-semibold text-gray-800", children: "N\u1ED9i dung c\u00E2u h\u1ECFi" }), _jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-purple-100 px-2.5 py-1 text-xs font-medium text-purple-700", children: ["\uD83D\uDCDA Nh\u00F3m ", currentGroupNumber] })] }) }), _jsxs(CardContent, { className: "space-y-6 pt-6", children: [_jsx("div", { className: "rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4", children: _jsx(PointsInput, { id: "points", value: currentQuestion.points || 1, onChange: (e) => {
497
- updateCurrentQuestion('points', Number(e.target.value) || 1);
498
- } }) }), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { htmlFor: "question", className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(MessageSquare, { className: "h-4 w-4 text-indigo-500" }), "C\u00E2u h\u1ECFi ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { id: "question", value: currentQuestion.question || '', onChange: (e) => updateCurrentQuestion('question', e.target.value), placeholder: "Nh\u1EADp c\u00E2u h\u1ECFi...", className: `border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 ${validationErrors.question ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` }), validationErrors.question && (_jsx("p", { className: "text-sm text-red-600", children: validationErrors.question }))] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-6 w-6 items-center justify-center rounded-md bg-indigo-100", children: _jsx(Lightbulb, { className: "h-3.5 w-3.5 text-indigo-600" }) }), _jsxs(Label, { className: "text-base font-semibold text-gray-800", children: ["C\u00E1c l\u1EF1a ch\u1ECDn ", _jsxs("span", { className: "text-sm font-normal text-gray-500", children: ["(", currentQuestion.options.length, " \u0111\u00E1p \u00E1n)"] })] })] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: addOption, disabled: currentQuestion.options.length >= 10, className: "gap-2 border-green-200 text-green-600 hover:bg-green-50 hover:text-green-700", children: [_jsx(Plus, { className: "h-4 w-4" }), "Th\u00EAm \u0111\u00E1p \u00E1n"] })] }), _jsx(RadioGroup, { value: currentQuestion.correctAnswer >= 0 ? currentQuestion.correctAnswer.toString() : '', onValueChange: (value) => updateCurrentQuestion('correctAnswer', parseInt(value)), children: _jsx("div", { className: "space-y-3", children: currentQuestion.options.map((option, optIndex) => {
491
+ return (_jsxs("div", { className: "space-y-3", children: [_jsxs(CompactFieldCard, { header: _jsx(CompactCreatorHeader, { icon: _jsx(BookOpen, { className: "h-3.5 w-3.5" }), title: "\u0110\u1ECDc \u0111o\u1EA1n v\u0103n v\u00E0 tr\u1EA3 l\u1EDDi c\u00E2u h\u1ECFi", points: {
492
+ value: currentQuestion.points || 1,
493
+ onValueChange: (value) => updateCurrentQuestion('points', value),
494
+ }, extraActions: _jsxs("span", { className: "inline-flex items-center rounded-full bg-purple-100 px-2 py-0.5 text-xs font-medium text-purple-700", children: ["Nh\u00F3m ", currentGroupNumber] }), preview: {
495
+ onClick: handlePreview,
496
+ } }), children: [_jsxs("div", { className: `rounded-xl border-2 p-5 transition-all ${validationErrors.passage ? 'border-red-300 bg-gradient-to-r from-red-50 to-rose-50' : 'border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50'}`, children: [_jsxs("div", { className: "mb-4 flex items-center gap-3", children: [_jsx("div", { className: `flex h-8 w-8 items-center justify-center rounded-lg ${validationErrors.passage ? 'bg-red-100' : 'bg-amber-100'}`, children: _jsx(BookOpen, { className: `h-4 w-4 ${validationErrors.passage ? 'text-red-600' : 'text-amber-600'}` }) }), _jsxs(Label, { className: `text-base font-semibold ${validationErrors.passage ? 'text-red-800' : 'text-amber-800'}`, children: ["\u0110o\u1EA1n v\u0103n \u0111\u1ECDc hi\u1EC3u ", _jsxs("span", { className: "font-normal text-amber-600", children: ["(d\u00F9ng chung cho nh\u00F3m ", currentGroupNumber, ")"] })] })] }), _jsxs("div", { className: "mb-4", children: [_jsx(Label, { htmlFor: "passageTitle", className: "text-sm font-medium text-gray-700", children: "Ti\u00EAu \u0111\u1EC1" }), _jsx(Input, { id: "passageTitle", value: passageTitle, onChange: (e) => setPassageTitle(e.target.value), placeholder: "V\u00ED d\u1EE5: Our Family Holiday in Nha Trang", className: "mt-1.5 border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200" })] }), _jsxs("div", { className: "mb-4", children: [_jsxs(Label, { htmlFor: "passage", className: "text-sm font-medium text-gray-700", children: ["N\u1ED9i dung \u0111o\u1EA1n v\u0103n ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Textarea, { id: "passage", value: passage, onChange: (e) => {
497
+ setPassage(e.target.value);
498
+ if (validationErrors.passage) {
499
+ setValidationErrors(prev => ({ ...prev, passage: undefined }));
500
+ }
501
+ }, placeholder: "Nh\u1EADp n\u1ED9i dung \u0111o\u1EA1n v\u0103n \u0111\u1ECDc hi\u1EC3u...", className: `mt-1.5 min-h-[150px] border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200 ${validationErrors.passage ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}`, rows: 6 }), validationErrors.passage && (_jsx("p", { className: "mt-1.5 text-sm text-red-600", children: validationErrors.passage }))] }), _jsxs("div", { children: [_jsx(Label, { htmlFor: "instructions", className: "text-sm font-medium text-gray-700", children: "H\u01B0\u1EDBng d\u1EABn" }), _jsx(Input, { id: "instructions", value: instructions, onChange: (e) => setInstructions(e.target.value), placeholder: "V\u00ED d\u1EE5: Read the short passage and answer the question below.", className: "mt-1.5 border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200" })] })] }), externalErrors && externalErrors.length > 0 && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-red-200 bg-gradient-to-r from-red-50 to-rose-50 p-4", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-red-100", children: _jsx("span", { className: "text-lg", children: "\u274C" }) }), _jsxs("div", { className: "text-sm", children: [_jsx("p", { className: "font-semibold text-red-800", children: "L\u1ED7i:" }), _jsx("ul", { className: "mt-1 list-inside list-disc text-red-700", children: externalErrors.map((error, index) => (_jsx("li", { children: error }, index))) })] })] }))] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-sm", children: [_jsx(CardHeader, { className: "px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-indigo-100", children: _jsx(MessageSquare, { className: "h-4 w-4 text-indigo-600" }) }), _jsx(CardTitle, { className: "text-lg font-semibold text-gray-800", children: "N\u1ED9i dung c\u00E2u h\u1ECFi" }), _jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-purple-100 px-2.5 py-1 text-xs font-medium text-purple-700", children: ["\uD83D\uDCDA Nh\u00F3m ", currentGroupNumber] })] }) }), _jsxs(CardContent, { className: "space-y-2.5 px-3 pb-3", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { htmlFor: "question", className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(MessageSquare, { className: "h-4 w-4 text-indigo-500" }), "C\u00E2u h\u1ECFi ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { id: "question", value: currentQuestion.question || '', onChange: (e) => updateCurrentQuestion('question', e.target.value), placeholder: "Nh\u1EADp c\u00E2u h\u1ECFi...", className: `border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 ${validationErrors.question ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` }), validationErrors.question && (_jsx("p", { className: "text-sm text-red-600", children: validationErrors.question }))] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-6 w-6 items-center justify-center rounded-md bg-indigo-100", children: _jsx(Lightbulb, { className: "h-3.5 w-3.5 text-indigo-600" }) }), _jsxs(Label, { className: "text-base font-semibold text-gray-800", children: ["C\u00E1c l\u1EF1a ch\u1ECDn ", _jsxs("span", { className: "text-sm font-normal text-gray-500", children: ["(", currentQuestion.options.length, " \u0111\u00E1p \u00E1n)"] })] })] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: addOption, disabled: currentQuestion.options.length >= 10, className: "gap-2 border-green-200 text-green-600 hover:bg-green-50 hover:text-green-700", children: [_jsx(Plus, { className: "h-4 w-4" }), "Th\u00EAm \u0111\u00E1p \u00E1n"] })] }), _jsx(RadioGroup, { value: currentQuestion.correctAnswer >= 0 ? currentQuestion.correctAnswer.toString() : '', onValueChange: (value) => updateCurrentQuestion('correctAnswer', parseInt(value)), children: _jsx("div", { className: "space-y-3", children: currentQuestion.options.map((option, optIndex) => {
499
502
  const optionError = validationErrors.options?.[optIndex];
500
503
  const isCorrect = currentQuestion.correctAnswer === optIndex;
501
504
  const optionLetter = String.fromCharCode(65 + optIndex);
@@ -504,7 +507,7 @@ function ReadPassageAndAnswerQuestionsContent({ initialData, onSave, onSaveToQue
504
507
  : 'border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm'}`, children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: `flex h-10 w-10 flex-shrink-0 cursor-pointer items-center justify-center rounded-xl font-bold transition-all ${isCorrect
505
508
  ? 'bg-gradient-to-br from-green-500 to-emerald-600 text-white shadow-md'
506
509
  : 'bg-gray-100 text-gray-600 hover:bg-indigo-100 hover:text-indigo-600'}`, onClick: () => updateCurrentQuestion('correctAnswer', optIndex), children: optionLetter }), _jsxs("div", { className: "flex-1 space-y-2", children: [_jsx(Input, { id: `option-input-${optIndex}`, value: option, onChange: (e) => updateOption(optIndex, e.target.value), placeholder: `Nhập đáp án ${optionLetter}...`, className: `border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 ${optionError ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` }), optionError && (_jsx("p", { className: "text-sm text-red-600", children: optionError })), isCorrect && (_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-full bg-green-100 px-3 py-1 text-xs font-semibold text-green-700", children: [_jsx(CheckCircle2, { className: "h-3.5 w-3.5" }), "\u0110\u00E1p \u00E1n \u0111\u00FAng"] }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [!isCorrect && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => updateCurrentQuestion('correctAnswer', optIndex), className: "text-gray-400 hover:text-green-600", title: "Ch\u1ECDn l\u00E0m \u0111\u00E1p \u00E1n \u0111\u00FAng", children: _jsx(CheckCircle2, { className: "h-4 w-4" }) })), currentQuestion.options.length > 2 && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => deleteOption(optIndex), className: "text-red-500 hover:bg-red-50 hover:text-red-600", children: _jsx(Trash2, { className: "h-4 w-4" }) }))] })] }) }, optIndex));
507
- }) }) }), currentQuestion.correctAnswer < 0 && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-4", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-amber-100", children: _jsx("span", { className: "text-lg", children: "\u26A0\uFE0F" }) }), _jsxs("div", { className: "text-sm text-amber-800", children: [_jsx("p", { className: "font-semibold", children: "Ch\u01B0a ch\u1ECDn \u0111\u00E1p \u00E1n \u0111\u00FAng" }), _jsx("p", { className: "mt-0.5 text-amber-700", children: "Click v\u00E0o \u00F4 ch\u1EEF c\u00E1i ho\u1EB7c icon \u2713 \u0111\u1EC3 ch\u1ECDn \u0111\u00E1p \u00E1n \u0111\u00FAng" })] })] })), validationErrors.correctAnswer && (_jsx("div", { className: "rounded-xl border border-red-200 bg-red-50 p-4", children: _jsx("p", { className: "text-sm text-red-600", children: validationErrors.correctAnswer }) }))] })] })] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-amber-100/50", children: [_jsx("div", { className: "h-1 bg-gradient-to-r from-amber-400 to-orange-400" }), _jsx(CardHeader, { className: "pb-4", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-9 w-9 items-center justify-center rounded-lg bg-gradient-to-br from-amber-500 to-orange-500 shadow-sm", children: _jsx(BookOpen, { className: "h-4 w-4 text-white" }) }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-lg font-semibold text-gray-800", children: "Gi\u1EA3i th\u00EDch" }), _jsx("span", { className: "inline-flex items-center rounded-full border border-amber-200 bg-amber-50 px-2.5 py-0.5 text-xs font-medium text-amber-600", children: "Kh\u00F4ng b\u1EAFt bu\u1ED9c" })] }), _jsx("p", { className: "text-sm text-gray-500 mt-0.5", children: "Gi\u1EA3i th\u00EDch cho \u0111\u00E1p \u00E1n \u0111\u00FAng \u2014 hi\u1EC3n th\u1ECB sau khi h\u1ECDc sinh ho\u00E0n th\u00E0nh c\u00E2u h\u1ECFi" })] })] }) }), _jsx(CardContent, { children: _jsx(Textarea, { id: "explanation", value: explanation, onChange: (e) => setExplanation(e.target.value), placeholder: "VD: C\u00E2u tr\u1EA3 l\u1EDDi \u0111\u00FAng l\u00E0... v\u00EC...", rows: 3, className: "min-h-[80px] border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200 resize-none" }) })] })] }));
510
+ }) }) }), currentQuestion.correctAnswer < 0 && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-4", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-amber-100", children: _jsx("span", { className: "text-lg", children: "\u26A0\uFE0F" }) }), _jsxs("div", { className: "text-sm text-amber-800", children: [_jsx("p", { className: "font-semibold", children: "Ch\u01B0a ch\u1ECDn \u0111\u00E1p \u00E1n \u0111\u00FAng" }), _jsx("p", { className: "mt-0.5 text-amber-700", children: "Click v\u00E0o \u00F4 ch\u1EEF c\u00E1i ho\u1EB7c icon \u2713 \u0111\u1EC3 ch\u1ECDn \u0111\u00E1p \u00E1n \u0111\u00FAng" })] })] })), validationErrors.correctAnswer && (_jsx("div", { className: "rounded-xl border border-red-200 bg-red-50 p-4", children: _jsx("p", { className: "text-sm text-red-600", children: validationErrors.correctAnswer }) }))] })] })] }), _jsx(CompactExplanationToggle, { value: explanation, onValueChange: setExplanation })] }));
508
511
  }
509
512
  export function ReadPassageAndAnswerQuestionsCreator(props) {
510
513
  return _jsx(ReadPassageAndAnswerQuestionsContent, { ...props });
@@ -20,5 +20,5 @@ export function SortWordsIntoCategoriesClient({ questionData, isReviewMode = fal
20
20
  return item;
21
21
  });
22
22
  const canEdit = Boolean(onPlacementsChange) && !isReviewMode;
23
- return (_jsxs("div", { className: "space-y-4", children: [(questionData.title || questionData.instruction) && (_jsxs("div", { className: "rounded-xl border border-slate-200 bg-slate-50 px-4 py-3", children: [questionData.title && (_jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-slate-500", children: questionData.title })), questionData.instruction && (_jsx("p", { className: "text-sm font-medium text-slate-800", children: questionData.instruction }))] })), _jsx(SortWordsIntoCategoriesBoard, { categories: questionData.categories, words: questionData.words, placements: placements, correctPlacements: isReviewMode ? correctPlacements : undefined, onChange: canEdit ? onPlacementsChange : undefined, disabled: !canEdit, isReviewMode: isReviewMode }), isReviewMode && questionData.explanation && (_jsxs("div", { className: "flex items-start gap-2 rounded-xl border border-amber-100 bg-amber-50 px-4 py-3 text-sm text-amber-800", children: [_jsx(Lightbulb, { className: "mt-0.5 h-4 w-4 flex-shrink-0" }), questionData.explanation] }))] }));
23
+ return (_jsxs("div", { className: "space-y-4", children: [(questionData.title || questionData.instruction) && (_jsxs("div", { className: "rounded-xl border border-slate-200 bg-slate-50 px-3 py-2", children: [questionData.title && (_jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-slate-500", children: questionData.title })), questionData.instruction && (_jsx("p", { className: "text-sm font-medium text-slate-800", children: questionData.instruction }))] })), _jsx(SortWordsIntoCategoriesBoard, { categories: questionData.categories, words: questionData.words, placements: placements, correctPlacements: isReviewMode ? correctPlacements : undefined, onChange: canEdit ? onPlacementsChange : undefined, disabled: !canEdit, isReviewMode: isReviewMode }), isReviewMode && questionData.explanation && (_jsxs("div", { className: "flex items-start gap-2 rounded-xl border border-amber-100 bg-amber-50 px-4 py-3 text-sm text-amber-800", children: [_jsx(Lightbulb, { className: "mt-0.5 h-4 w-4 flex-shrink-0" }), questionData.explanation] }))] }));
24
24
  }
@@ -5,11 +5,11 @@ import { Button } from '../../../../components/ui/button';
5
5
  import { Label } from '../../../../components/ui/label';
6
6
  import { Input } from '../../../../components/ui/input';
7
7
  import { PointsInput } from '../../../../components/ui/points-input';
8
- import { Textarea } from '../../../../components/ui/textarea';
9
8
  import { Card, CardContent, CardHeader, CardTitle } from '../../../../components/ui/card';
10
9
  import { Switch } from '../../../../components/ui/switch';
11
10
  import { useDebouncedCallback } from '../../../../shared/lib/hooks';
12
- import { Eye, Pencil, Plus, Star, Trash2 } from 'lucide-react';
11
+ import { Plus, Star, Trash2, Layers } from 'lucide-react';
12
+ import { CompactCreatorHeader, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, } from '../../_shared/components/compact';
13
13
  import { SortWordsIntoCategoriesClient } from './SortWordsIntoCategoriesClient';
14
14
  import { createEmptyCategory, createEmptyWord, sumGradablePoints, } from './map-sort-words-into-categories-data';
15
15
  import { SORT_WORDS_INTO_CATEGORIES_DEFAULT_INSTRUCTION } from '../../_shared/types/sort-words-into-categories.type';
@@ -165,7 +165,7 @@ export function SortWordsIntoCategoriesCreator({ initialData, onChange, external
165
165
  setWords((prev) => prev.filter((_, i) => i !== index));
166
166
  };
167
167
  const displayErrors = [...errors, ...(externalErrors || [])];
168
- return (_jsxs("div", { className: "space-y-4", children: [_jsx("div", { className: "flex justify-end", children: _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setIsClientMode((v) => !v), children: [isClientMode ? _jsx(Pencil, { className: "mr-2 h-4 w-4" }) : _jsx(Eye, { className: "mr-2 h-4 w-4" }), isClientMode ? 'Sửa' : 'Xem trước'] }) }), isClientMode ? (_jsx(SortWordsIntoCategoriesClient, { questionData: buildPayload(), isReviewMode: true })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs("div", { children: [_jsx(Label, { htmlFor: "swc-title", children: "Ti\u00EAu \u0111\u1EC1 (optional)" }), _jsx(Input, { id: "swc-title", value: title, onChange: (event) => setTitle(event.target.value), placeholder: "VOCABULARY" })] }), _jsxs("div", { children: [_jsx(Label, { htmlFor: "swc-instruction", children: "H\u01B0\u1EDBng d\u1EABn" }), _jsx(Input, { id: "swc-instruction", value: instruction, onChange: (event) => setInstruction(event.target.value), placeholder: SORT_WORDS_INTO_CATEGORIES_DEFAULT_INSTRUCTION })] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between space-y-0", children: [_jsx(CardTitle, { className: "text-base", children: "Nh\u00F3m (categories)" }), _jsxs(Button, { type: "button", size: "sm", variant: "outline", onClick: addCategory, children: [_jsx(Plus, { className: "mr-1 h-4 w-4" }), " Th\u00EAm nh\u00F3m"] })] }), _jsx(CardContent, { className: "space-y-3", children: categories.map((category, index) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { value: category.name, onChange: (event) => updateCategory(index, { name: event.target.value }), placeholder: `Nhóm ${index + 1}` }), categories.length > 2 && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => removeCategory(index), children: _jsx(Trash2, { className: "h-4 w-4 text-red-500" }) }))] }, category.id))) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between space-y-0", children: [_jsx(CardTitle, { className: "text-base", children: "T\u1EEB / c\u1EE5m t\u1EEB" }), _jsxs(Button, { type: "button", size: "sm", variant: "outline", onClick: addWord, children: [_jsx(Plus, { className: "mr-1 h-4 w-4" }), " Th\u00EAm t\u1EEB"] })] }), _jsx(CardContent, { className: "space-y-3", children: words.map((word, index) => (_jsxs("div", { className: "grid gap-2 rounded-lg border p-3 md:grid-cols-[1fr_180px_auto]", children: [_jsx(Input, { value: word.text, onChange: (event) => updateWord(index, { text: event.target.value }), placeholder: `Từ #${index + 1} (VD: press a button)` }), _jsx("select", { className: "h-10 rounded-md border border-input bg-background px-3 text-sm", value: word.categoryId, onChange: (event) => updateWord(index, { categoryId: event.target.value }), children: categories.map((category) => (_jsx("option", { value: category.id, children: category.name || category.id }, category.id))) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Switch, { id: `swc-example-${index}`, checked: word.isExample === true, onCheckedChange: (checked) => updateWord(index, { isExample: checked }) }), _jsxs(Label, { htmlFor: `swc-example-${index}`, className: "flex cursor-pointer items-center gap-1 text-xs", children: [_jsx(Star, { className: "h-3 w-3 text-amber-500" }), "Example"] })] }), !word.isExample && (_jsx(PointsInput, { value: word.points, allowZero: true, onChange: (event) => updateWord(index, {
169
- points: Number.parseInt(event.target.value, 10) || 1,
170
- }) })), words.length > 1 && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => removeWord(index), children: _jsx(Trash2, { className: "h-4 w-4 text-red-500" }) }))] })] }, word.id))) })] }), _jsxs("div", { children: [_jsx(Label, { htmlFor: "swc-explanation", children: "Gi\u1EA3i th\u00EDch" }), _jsx(Textarea, { id: "swc-explanation", value: explanation, onChange: (event) => setExplanation(event.target.value) })] })] })), displayErrors.length > 0 && (_jsx("ul", { className: "list-disc space-y-1 rounded-md border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700", children: displayErrors.map((error) => (_jsx("li", { children: error }, error))) }))] }));
168
+ return (_jsxs("div", { className: "space-y-3", children: [isClientMode ? (_jsxs("div", { className: "space-y-4", children: [_jsx(CompactPreviewBanner, { onBack: () => setIsClientMode(false) }), _jsx(SortWordsIntoCategoriesClient, { questionData: buildPayload(), isReviewMode: true })] })) : (_jsxs(_Fragment, { children: [_jsxs(CompactFieldCard, { header: _jsx(CompactCreatorHeader, { icon: _jsx(Layers, { className: "h-3.5 w-3.5" }), title: "S\u1EAFp x\u1EBFp t\u1EEB v\u00E0o nh\u00F3m", preview: { onClick: () => setIsClientMode(true) } }), children: [_jsxs("div", { className: "grid gap-2.5 md:grid-cols-2", children: [_jsxs("div", { children: [_jsx(Label, { htmlFor: "swc-title", children: "Ti\u00EAu \u0111\u1EC1 (optional)" }), _jsx(Input, { id: "swc-title", value: title, onChange: (event) => setTitle(event.target.value), placeholder: "VOCABULARY" })] }), _jsxs("div", { children: [_jsx(Label, { htmlFor: "swc-instruction", children: "H\u01B0\u1EDBng d\u1EABn" }), _jsx(Input, { id: "swc-instruction", value: instruction, onChange: (event) => setInstruction(event.target.value), placeholder: SORT_WORDS_INTO_CATEGORIES_DEFAULT_INSTRUCTION })] })] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-sm", children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 px-3 py-2", children: [_jsx(CardTitle, { className: "text-sm font-semibold text-gray-800", children: "Nh\u00F3m (categories)" }), _jsxs(Button, { type: "button", size: "sm", variant: "outline", onClick: addCategory, className: "h-8", children: [_jsx(Plus, { className: "mr-1 h-3.5 w-3.5" }), " Th\u00EAm nh\u00F3m"] })] }), _jsx(CardContent, { className: "space-y-2.5 px-3 pb-3", children: categories.map((category, index) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { value: category.name, onChange: (event) => updateCategory(index, { name: event.target.value }), placeholder: `Nhóm ${index + 1}` }), categories.length > 2 && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => removeCategory(index), children: _jsx(Trash2, { className: "h-4 w-4 text-red-500" }) }))] }, category.id))) })] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-sm", children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between space-y-0 px-3 py-2", children: [_jsx(CardTitle, { className: "text-sm font-semibold text-gray-800", children: "T\u1EEB / c\u1EE5m t\u1EEB" }), _jsxs(Button, { type: "button", size: "sm", variant: "outline", onClick: addWord, className: "h-8", children: [_jsx(Plus, { className: "mr-1 h-3.5 w-3.5" }), " Th\u00EAm t\u1EEB"] })] }), _jsx(CardContent, { className: "space-y-2.5 px-3 pb-3", children: words.map((word, index) => (_jsxs("div", { className: "grid gap-2 rounded-lg border p-3 md:grid-cols-[1fr_180px_auto]", children: [_jsx(Input, { value: word.text, onChange: (event) => updateWord(index, { text: event.target.value }), placeholder: `Từ #${index + 1} (VD: press a button)` }), _jsx("select", { className: "h-10 rounded-md border border-input bg-background px-3 text-sm", value: word.categoryId, onChange: (event) => updateWord(index, { categoryId: event.target.value }), children: categories.map((category) => (_jsx("option", { value: category.id, children: category.name || category.id }, category.id))) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Switch, { id: `swc-example-${index}`, checked: word.isExample === true, onCheckedChange: (checked) => updateWord(index, { isExample: checked }) }), _jsxs(Label, { htmlFor: `swc-example-${index}`, className: "flex cursor-pointer items-center gap-1 text-xs", children: [_jsx(Star, { className: "h-3 w-3 text-amber-500" }), "Example"] })] }), !word.isExample && (_jsx(PointsInput, { value: word.points, allowZero: true, onChange: (event) => updateWord(index, {
169
+ points: Number.parseInt(event.target.value, 10) || 1,
170
+ }) })), words.length > 1 && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => removeWord(index), children: _jsx(Trash2, { className: "h-4 w-4 text-red-500" }) }))] })] }, word.id))) })] })] }), _jsx(CompactExplanationToggle, { value: explanation, onValueChange: setExplanation, defaultVisible: Boolean(initialData?.explanation) })] })), displayErrors.length > 0 && (_jsx("ul", { className: "list-disc space-y-1 rounded-md border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700", children: displayErrors.map((error) => (_jsx("li", { children: error }, error))) }))] }));
171
171
  }
@@ -1,20 +1,20 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useRef, useEffect, useMemo } from 'react';
3
+ import { useRef, useEffect, useMemo, useState } from 'react';
4
4
  import { Button } from '../../../../components/ui/button';
5
5
  import { Label } from '../../../../components/ui/label';
6
6
  import { Input } from '../../../../components/ui/input';
7
7
  import { Textarea } from '../../../../components/ui/textarea';
8
8
  import { Switch } from '../../../../components/ui/switch';
9
9
  import { PointsInput } from '../../../../components/ui/points-input';
10
- import { Card, CardContent, CardHeader, CardTitle } from '../../../../components/ui/card';
11
10
  import { Badge } from '../../../../components/ui/badge';
12
11
  import { FileUpload } from '../../../../components/ui/file-upload';
13
- import { CreatorGuide } from '../../components/CreatorGuide';
12
+ import { CompactCreatorHeader, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, } from '../../_shared/components/compact';
13
+ import { SpeakingConversationPreviewClient } from './SpeakingConversationPreviewClient';
14
14
  import { useReactHookForm } from '../../../../shared/lib/hooks/useReactHookForm';
15
15
  import { useDebouncedCallback } from '../../../../shared/lib/hooks/useDebouncedCallback';
16
16
  import { speakingConversationFormSchema, } from '../../../../shared/lib/validation/speaking-conversation.validation';
17
- import { Users, Mic, Volume2, MessageSquareText, BookOpen, Info, Plus, Trash2, Image, User, UserCheck, } from 'lucide-react';
17
+ import { Users, Mic, Volume2, MessageSquareText, Info, Plus, Trash2, Image, User, UserCheck, } from 'lucide-react';
18
18
  import { useExamQuestionStore } from '../../../../shared/lib/stores/examQuestionStore';
19
19
  import { generateObjectId } from '../../_shared/utils/id-generator';
20
20
  // ─── Helpers ─────────────────────────────────────────────────────────────────
@@ -103,6 +103,7 @@ export function SpeakingConversationCreator({ initialData, onSave, onChange, ext
103
103
  zodSchema: speakingConversationFormSchema,
104
104
  mode: 'onBlur',
105
105
  });
106
+ const [isClientMode, setIsClientMode] = useState(false);
106
107
  const previousInitialDataRef = useRef(initialData);
107
108
  const isInitializingRef = useRef(false);
108
109
  const onChangeRef = useRef(onChange);
@@ -335,39 +336,34 @@ export function SpeakingConversationCreator({ initialData, onSave, onChange, ext
335
336
  form.setValue('images', updated, { shouldValidate: true });
336
337
  };
337
338
  // ─── Render ───────────────────────────────────────────────────────────────
338
- return (_jsxs("div", { className: "space-y-6", children: [_jsx(CreatorGuide, { colorScheme: "teal", steps: [
339
- {
340
- text: 'Cấu hình Group Data (tên Partner, avatar) — chỉ câu đầu tiên trong nhóm được chỉnh sửa',
341
- },
342
- {
343
- text: 'Chọn Responder: Partner (câu mẫu) hoặc Student (học sinh trả lời)',
344
- highlight: true,
345
- },
346
- {
347
- text: 'Upload audio Interlocutor (câu hỏi) và audio Partner (câu trả lời mẫu khi responder = Partner)',
348
- },
349
- { text: 'Nhập đáp án mong muốn (dùng khi responder = Student để giáo viên tham chiếu)' },
350
- { text: 'Thêm giải thích nếu cần' },
351
- ], tips: [
352
- 'Responder = Partner: tự động set is_example=true, points=0. Học sinh chỉ nghe, không ghi âm.',
353
- 'Responder = Student: học sinh ghi âm trả lời. Cần nhập điểm >= 1.',
354
- ] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-teal-100/50", children: [_jsx("div", { className: "h-1 bg-gradient-to-r from-teal-400 to-cyan-400" }), _jsx(CardHeader, { className: "pb-4", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-9 w-9 items-center justify-center rounded-lg bg-gradient-to-br from-teal-500 to-cyan-600 shadow-sm", children: _jsx(Users, { className: "h-4 w-4 text-white" }) }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-lg font-bold text-gray-900", children: "D\u1EEF li\u1EC7u nh\u00F3m" }), isGrouped && (_jsxs(Badge, { variant: "outline", className: "border-teal-300 bg-teal-50 text-teal-700 text-xs", children: ["Nh\u00F3m ", currentGroupNumber] })), !isFirstInGroup && (_jsx(Badge, { variant: "outline", className: "border-gray-300 bg-gray-50 text-gray-500 text-xs", children: "Ch\u1EC9 \u0111\u1ECDc" }))] }), _jsx("p", { className: "text-sm text-gray-500 mt-0.5", children: isFirstInGroup
355
- ? 'Thông tin Partner hình ảnh dùng chung cho toàn bộ nhóm câu hỏi'
356
- : 'Được quản lý bởi câu hỏi đầu tiên trong nhóm' })] })] }) }), _jsx(CardContent, { className: "space-y-5", children: isFirstInGroup ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-sm font-semibold text-gray-700", children: [_jsx(User, { className: "h-4 w-4 text-teal-500" }), "T\u00EAn nh\u00E2n v\u1EADt Partner"] }), _jsx(Input, { ...form.register('partnerName'), placeholder: "VD: Bingo", className: "border-gray-200 focus:border-teal-300 focus:ring-teal-200" }), _jsx("p", { className: "text-xs text-gray-400", children: "T\u00EAn hi\u1EC3n th\u1ECB c\u1EE7a nh\u00E2n v\u1EADt \u1EA3o (Partner) \u2014 d\u00F9ng trong giao di\u1EC7n thi." })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-sm font-semibold text-gray-700", children: [_jsx(User, { className: "h-4 w-4 text-teal-500" }), "Avatar Partner"] }), _jsx(FileUpload, { id: "partner-avatar-url", label: "", accept: "image/*", value: watchedPartnerAvatarUrl || '', onChange: (url) => form.setValue('partnerAvatarUrl', url, { shouldValidate: true }), maxSize: 5, placeholder: "Upload \u1EA3nh avatar Partner (PNG, JPG, ...)", autoUpload: true, prefix: "speaking/partner-avatar" })] }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { className: "flex items-center gap-2 text-sm font-semibold text-gray-700", children: [_jsx(Image, { className: "h-4 w-4 text-teal-500" }), "H\u00ECnh \u1EA3nh phase (t\u00F9y ch\u1ECDn)"] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: handleAddImage, className: "gap-1.5 border-teal-200 text-teal-700 hover:bg-teal-50 text-xs", children: [_jsx(Plus, { className: "h-3.5 w-3.5" }), "Th\u00EAm h\u00ECnh"] })] }), watchedImages.length === 0 ? (_jsxs("div", { className: "rounded-lg border-2 border-dashed border-teal-200 bg-teal-50/40 py-6 text-center", children: [_jsx(Image, { className: "mx-auto h-8 w-8 text-teal-300 mb-2" }), _jsx("p", { className: "text-sm text-gray-400", children: "Kh\u00F4ng c\u00F3 h\u00ECnh \u1EA3nh \u2014 d\u00F9ng cho Part 2 phases c\u00F3 tranh" })] })) : (_jsx("div", { className: "space-y-3", children: watchedImages.map((img, index) => (_jsxs("div", { className: "rounded-lg border border-gray-200 bg-gray-50 p-3 space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("span", { className: "text-xs font-semibold text-gray-600", children: ["H\u00ECnh ", index + 1] }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "h-6 w-6 text-red-400 hover:text-red-600 hover:bg-red-50", onClick: () => handleRemoveImage(index), children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) })] }), _jsx(FileUpload, { id: `image-url-${index}`, label: "", accept: "image/*", value: img.url, onChange: (url) => handleImageChange(index, 'url', url), maxSize: 10, placeholder: "Upload h\u00ECnh \u1EA3nh", autoUpload: true, prefix: "speaking/phase-images" }), _jsx(Input, { value: img.label, onChange: (e) => handleImageChange(index, 'label', e.target.value), placeholder: "Nh\u00E3n h\u00ECnh (VD: Park, Bedroom, Library ...)", className: "border-gray-200 text-sm focus:border-teal-300" })] }, img.id))) }))] })] })) : (
357
- /* Read-only group data view for non-first questions */
358
- _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-gray-100 bg-gray-50 px-4 py-3", children: [_jsx(User, { className: "h-4 w-4 text-teal-500 flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "text-xs text-gray-500", children: "T\u00EAn Partner" }), _jsx("p", { className: "text-sm font-medium text-gray-800", children: groupData.partnerName || (_jsx("span", { className: "italic text-gray-400", children: "Ch\u01B0a \u0111\u1EB7t t\u00EAn" })) })] })] }), groupData.images && groupData.images.length > 0 && (_jsxs("div", { className: "rounded-lg border border-gray-100 bg-gray-50 px-4 py-3", children: [_jsxs("p", { className: "text-xs text-gray-500 mb-2", children: ["H\u00ECnh \u1EA3nh (", groupData.images.length, ")"] }), _jsx("div", { className: "flex flex-wrap gap-2", children: groupData.images.map((img) => (_jsx("span", { className: "inline-flex items-center rounded-full bg-teal-100 px-2 py-0.5 text-xs text-teal-700", children: img.label || img.id }, img.id))) })] }))] })) })] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-indigo-100/50", children: [_jsx("div", { className: `h-1 bg-gradient-to-r ${isPartnerResponder ? 'from-orange-400 to-amber-400' : 'from-indigo-400 to-violet-400'}` }), _jsx(CardHeader, { className: "pb-4", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: `flex h-9 w-9 items-center justify-center rounded-lg shadow-sm ${isPartnerResponder ? 'bg-gradient-to-br from-orange-500 to-amber-500' : 'bg-gradient-to-br from-indigo-500 to-violet-600'}`, children: _jsx(Mic, { className: "h-4 w-4 text-white" }) }), _jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-lg font-bold text-gray-900", children: "N\u1ED9i dung c\u00E2u h\u1ECFi" }), isPartnerResponder && (_jsx(Badge, { className: "bg-orange-100 text-orange-700 border-orange-200 border text-xs font-semibold", children: "C\u00E2u h\u1ECFi m\u1EABu (Example)" }))] }), _jsx("p", { className: "text-sm text-gray-500 mt-0.5", children: isPartnerResponder
359
- ? 'Partner trả lời học sinh chỉ nghe, không ghi âm'
360
- : 'Student trả lời — học sinh ghi âm câu trả lời' })] })] }) }), _jsxs(CardContent, { className: "space-y-6", children: [_jsxs("div", { className: `rounded-xl border p-4 space-y-4 ${isPartnerResponder ? 'border-orange-200 bg-orange-50/40' : 'border-indigo-200 bg-indigo-50/40'}`, children: [_jsx("div", { className: "flex items-center justify-between", children: _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-base font-semibold text-gray-800", children: "Ng\u01B0\u1EDDi tr\u1EA3 l\u1EDDi" }), _jsx("p", { className: "text-sm text-gray-500", children: "Ai s\u1EBD tr\u1EA3 l\u1EDDi c\u00E2u h\u1ECFi n\u00E0y trong b\u00E0i thi?" })] }) }), _jsxs("div", { className: "flex gap-3", children: [_jsxs("button", { type: "button", onClick: () => form.setValue('responder', 'PARTNER', { shouldValidate: true }), className: `flex flex-1 items-center gap-3 rounded-xl border-2 p-3 transition-all ${isPartnerResponder
361
- ? 'border-orange-400 bg-orange-50 shadow-sm'
362
- : 'border-gray-200 bg-white hover:border-gray-300'}`, children: [_jsx("div", { className: `flex h-9 w-9 items-center justify-center rounded-full ${isPartnerResponder ? 'bg-orange-500' : 'bg-gray-200'}`, children: _jsx(User, { className: `h-4 w-4 ${isPartnerResponder ? 'text-white' : 'text-gray-500'}` }) }), _jsxs("div", { className: "text-left", children: [_jsx("p", { className: `text-sm font-semibold ${isPartnerResponder ? 'text-orange-800' : 'text-gray-700'}`, children: "Partner tr\u1EA3 l\u1EDDi" }), _jsx("p", { className: `text-xs ${isPartnerResponder ? 'text-orange-600' : 'text-gray-500'}`, children: "C\u00E2u m\u1EABu \u2014 is_example=true, points=0" })] })] }), _jsxs("button", { type: "button", onClick: () => form.setValue('responder', 'STUDENT', { shouldValidate: true }), className: `flex flex-1 items-center gap-3 rounded-xl border-2 p-3 transition-all ${!isPartnerResponder
363
- ? 'border-indigo-400 bg-indigo-50 shadow-sm'
364
- : 'border-gray-200 bg-white hover:border-gray-300'}`, children: [_jsx("div", { className: `flex h-9 w-9 items-center justify-center rounded-full ${!isPartnerResponder ? 'bg-indigo-500' : 'bg-gray-200'}`, children: _jsx(UserCheck, { className: `h-4 w-4 ${!isPartnerResponder ? 'text-white' : 'text-gray-500'}` }) }), _jsxs("div", { className: "text-left", children: [_jsx("p", { className: `text-sm font-semibold ${!isPartnerResponder ? 'text-indigo-800' : 'text-gray-700'}`, children: "Student tr\u1EA3 l\u1EDDi" }), _jsx("p", { className: `text-xs ${!isPartnerResponder ? 'text-indigo-600' : 'text-gray-500'}`, children: "C\u00E2u th\u1EF1c \u2014 h\u1ECDc sinh ghi \u00E2m" })] })] })] }), form.hasError('responder') && (_jsx("p", { className: "text-sm text-red-600", children: form.getFieldError('responder') }))] }), _jsxs("div", { className: "w-full md:w-1/2", children: [_jsx(PointsInput, { ...form.register('points', { valueAsNumber: true }), disabled: isPartnerResponder, error: form.hasError('points') ? form.getFieldError('points') : undefined }), isPartnerResponder && (_jsx("p", { className: "mt-1.5 text-xs text-orange-600", children: "C\u00E2u h\u1ECFi m\u1EABu (Partner) lu\u00F4n c\u00F3 0 \u0111i\u1EC3m" }))] }), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-sm font-semibold text-gray-700", children: [_jsx(Volume2, { className: "h-4 w-4 text-blue-500" }), "Audio Interlocutor", _jsx("span", { className: "text-xs font-normal text-gray-400", children: "(t\u00F9y ch\u1ECDn)" })] }), _jsx(FileUpload, { id: "interlocutor-audio-url", label: "", accept: "audio/*", value: watchedInterlocutorAudioUrl || '', onChange: (url) => form.setValue('interlocutorAudioUrl', url, { shouldValidate: true }), maxSize: 20, placeholder: "Upload audio c\u00E2u h\u1ECFi c\u1EE7a Interlocutor (MP3, WAV...)", autoUpload: true, prefix: "speaking/interlocutor" }), _jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-blue-100 bg-blue-50/60 px-3 py-2", children: [_jsx(Info, { className: "h-4 w-4 text-blue-500 mt-0.5 flex-shrink-0" }), _jsx("p", { className: "text-xs text-blue-700", children: "Audio c\u1EE7a Interlocutor (ng\u01B0\u1EDDi h\u1ECFi). Ph\u00E1t tr\u01B0\u1EDBc khi Partner ho\u1EB7c Student tr\u1EA3 l\u1EDDi." })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-sm font-semibold text-gray-700", children: [_jsx(Volume2, { className: "h-4 w-4 text-orange-500" }), "Audio Partner", isPartnerResponder && _jsx("span", { className: "text-red-500", children: "*" }), !isPartnerResponder && (_jsx("span", { className: "text-xs font-normal text-gray-400", children: "(t\u00F9y ch\u1ECDn)" }))] }), _jsx(FileUpload, { id: "partner-audio-url", label: "", accept: "audio/*", value: watchedPartnerAudioUrl || '', onChange: (url) => form.setValue('partnerAudioUrl', url, { shouldValidate: true }), maxSize: 20, placeholder: "Upload audio tr\u1EA3 l\u1EDDi c\u1EE7a Partner (MP3, WAV...)", autoUpload: true, prefix: "speaking/partner" }), form.hasError('partnerAudioUrl') && (_jsx("p", { className: "text-sm text-red-600", children: form.getFieldError('partnerAudioUrl') })), _jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-orange-100 bg-orange-50/60 px-3 py-2", children: [_jsx(Info, { className: "h-4 w-4 text-orange-500 mt-0.5 flex-shrink-0" }), _jsx("p", { className: "text-xs text-orange-700", children: isPartnerResponder
365
- ? 'Bắt buộc khi responder = Partner. Phát sau audio Interlocutor.'
366
- : 'Tùy chọn khi responder = Student — dùng cho Talk Together (Partner nói trước, Student trả lời sau).' })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-sm font-semibold text-gray-700", children: [_jsx(MessageSquareText, { className: "h-4 w-4 text-gray-500" }), "Text c\u00E2u h\u1ECFi (t\u00F9y ch\u1ECDn)"] }), _jsx(Textarea, { ...form.register('questionText'), placeholder: "VD: What's your name? How old are you?", rows: 2, className: "min-h-[60px] border-gray-200 focus:border-indigo-300 focus:ring-indigo-200 resize-none" }), _jsx("p", { className: "text-xs text-gray-400", children: "Ch\u1EC9 hi\u1EC3n th\u1ECB cho admin/gi\u00E1o vi\u00EAn khi review. H\u1ECDc sinh ch\u1EC9 nghe audio." })] }), _jsxs("div", { className: "flex items-center justify-between rounded-lg border border-gray-200 bg-gray-50 px-4 py-3", children: [_jsxs("div", { className: "space-y-0.5", children: [_jsx(Label, { className: "text-sm font-semibold text-gray-700", children: "C\u00E2u h\u1ECFi d\u1EF1 ph\u00F2ng" }), _jsx("p", { className: "text-xs text-gray-400", children: "\u0110\u00E1nh d\u1EA5u c\u00E2u h\u1ECFi n\u00E0y l\u00E0 d\u1EF1 ph\u00F2ng (backup)" })] }), _jsx(Switch, { checked: watchedIsBackup, onCheckedChange: (checked) => form.setValue('isBackup', checked, { shouldValidate: true }) })] })] })] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-green-100/50", children: [_jsx("div", { className: "h-1 bg-gradient-to-r from-green-400 to-emerald-500" }), _jsx(CardHeader, { className: "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-9 w-9 items-center justify-center rounded-lg bg-gradient-to-br from-green-500 to-emerald-600 shadow-sm", children: _jsx(MessageSquareText, { className: "h-4 w-4 text-white" }) }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-lg font-semibold text-gray-800", children: "\u0110\u00E1p \u00E1n mong mu\u1ED1n" }), _jsx("span", { className: "inline-flex items-center rounded-full border border-green-200 bg-green-50 px-2.5 py-0.5 text-xs font-medium text-green-600", children: "Kh\u00F4ng b\u1EAFt bu\u1ED9c" })] }), _jsx("p", { className: "text-sm text-gray-500 mt-0.5", children: isPartnerResponder
367
- ? 'Câu mẫu đáp án dùng để ghi nhớ nội dung (không chấm điểm)'
368
- : 'Đáp án tham chiếu để giáo viên chấm thủ công' })] })] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: handleAddExpectedAnswer, className: "gap-1.5 border-green-200 text-green-700 hover:bg-green-50", children: [_jsx(Plus, { className: "h-4 w-4" }), "Th\u00EAm \u0111\u00E1p \u00E1n"] })] }) }), _jsxs(CardContent, { className: "space-y-3", children: [_jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-blue-100 bg-blue-50/60 px-3 py-2.5", children: [_jsx(Info, { className: "h-4 w-4 text-blue-500 mt-0.5 flex-shrink-0" }), _jsx("p", { className: "text-xs text-blue-700", children: isPartnerResponder
369
- ? 'Câu hỏi mẫu: có thể nhập nội dung Partner nói để ghi nhớ. Không dùng để chấm điểm.'
370
- : 'Giáo viên dùng các đáp án này làm tham chiếu khi chấm thủ công câu trả lời của học sinh.' })] }), watchedExpectedAnswers.map((answer, index) => (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-full bg-green-100 text-xs font-semibold text-green-700 mt-1.5 flex-shrink-0", children: index + 1 }), _jsx(Textarea, { value: answer || '', onChange: (e) => handleExpectedAnswerChange(index, e.target.value), placeholder: index === 0
371
- ? 'VD: My name is Bingo. I am 8 years old.'
372
- : 'Thêm đáp án mẫu khác...', rows: 2, className: "min-h-[60px] border-gray-200 bg-white transition-all focus:border-green-300 focus:ring-green-200 resize-none flex-1" }), watchedExpectedAnswers.length > 1 && (_jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "mt-1.5 h-7 w-7 text-red-400 hover:text-red-600 hover:bg-red-50 flex-shrink-0", onClick: () => handleRemoveExpectedAnswer(index), "aria-label": `Xóa đáp án ${index + 1}`, children: _jsx(Trash2, { className: "h-4 w-4" }) }))] }, index)))] })] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-amber-100/50", children: [_jsx("div", { className: "h-1 bg-gradient-to-r from-amber-400 to-orange-400" }), _jsx(CardHeader, { className: "pb-4", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-9 w-9 items-center justify-center rounded-lg bg-gradient-to-br from-amber-500 to-orange-500 shadow-sm", children: _jsx(BookOpen, { className: "h-4 w-4 text-white" }) }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-lg font-semibold text-gray-800", children: "Gi\u1EA3i th\u00EDch" }), _jsx("span", { className: "inline-flex items-center rounded-full border border-amber-200 bg-amber-50 px-2.5 py-0.5 text-xs font-medium text-amber-600", children: "Kh\u00F4ng b\u1EAFt bu\u1ED9c" })] }), _jsx("p", { className: "text-sm text-gray-500 mt-0.5", children: "Gi\u1EA3i th\u00EDch th\u00EAm v\u1EC1 c\u00E2u tr\u1EA3 l\u1EDDi k\u1EF3 v\u1ECDng, d\u00F9ng khi review k\u1EBFt qu\u1EA3." })] })] }) }), _jsx(CardContent, { children: _jsx(Textarea, { value: watchedExplanation || '', onChange: (e) => form.setValue('explanation', e.target.value, { shouldValidate: true }), placeholder: "VD: C\u00E2u tr\u1EA3 l\u1EDDi \u0111\u00FAng: 'My name is...' v\u00EC c\u00E2u h\u1ECFi \u0111ang h\u1ECFi v\u1EC1 t\u00EAn v\u00E0 tu\u1ED5i.", rows: 3, className: "min-h-[80px] border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200 resize-none" }) })] }), externalErrors && externalErrors.length > 0 && (_jsx("div", { className: "flex items-start gap-3 rounded-xl border border-red-200 bg-red-50 p-4", children: _jsxs("div", { className: "text-sm", children: [_jsx("p", { className: "font-semibold text-red-800", children: "C\u1EA7n s\u1EEDa c\u00E1c l\u1ED7i sau:" }), _jsx("ul", { className: "mt-1 list-inside list-disc text-red-700", children: externalErrors.map((error, index) => (_jsx("li", { children: error }, index))) })] }) }))] }));
339
+ if (isClientMode) {
340
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(CompactPreviewBanner, { onBack: () => setIsClientMode(false) }), _jsx(SpeakingConversationPreviewClient, { questionData: {
341
+ questionText: watchedQuestionText,
342
+ responder: watchedResponder,
343
+ interlocutorAudioUrl: watchedInterlocutorAudioUrl,
344
+ partnerAudioUrl: watchedPartnerAudioUrl,
345
+ partnerName: watchedPartnerName,
346
+ partnerAvatarUrl: watchedPartnerAvatarUrl,
347
+ images: watchedImages,
348
+ isBackup: watchedIsBackup,
349
+ expectedAnswers: watchedExpectedAnswers,
350
+ }, isReviewMode: true })] }));
351
+ }
352
+ return (_jsxs("div", { className: "space-y-3", children: [_jsx(CompactFieldCard, { header: _jsx(CompactCreatorHeader, { icon: _jsx(Users, { className: "h-3.5 w-3.5" }), title: "D\u1EEF li\u1EC7u nh\u00F3m", extraActions: _jsxs(_Fragment, { children: [isGrouped && (_jsxs(Badge, { variant: "outline", className: "border-teal-300 bg-teal-50 text-teal-700 text-xs", children: ["Nh\u00F3m ", currentGroupNumber] })), !isFirstInGroup && (_jsx(Badge, { variant: "outline", className: "border-gray-300 bg-gray-50 text-gray-500 text-xs", children: "Ch\u1EC9 \u0111\u1ECDc" })), _jsx(PointsInput, { value: watchedPoints, onValueChange: (value) => form.setValue('points', value, { shouldValidate: true }), disabled: isPartnerResponder, error: form.hasError('points') ? form.getFieldError('points') : undefined })] }), preview: { onClick: () => setIsClientMode(true) } }), children: isFirstInGroup ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-sm font-semibold text-gray-700", children: [_jsx(User, { className: "h-4 w-4 text-teal-500" }), "T\u00EAn nh\u00E2n v\u1EADt Partner"] }), _jsx(Input, { ...form.register('partnerName'), placeholder: "VD: Bingo", className: "border-gray-200 focus:border-teal-300 focus:ring-teal-200" }), _jsx("p", { className: "text-xs text-gray-400", children: "T\u00EAn hi\u1EC3n th\u1ECB c\u1EE7a nh\u00E2n v\u1EADt \u1EA3o (Partner) \u2014 d\u00F9ng trong giao di\u1EC7n thi." })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-sm font-semibold text-gray-700", children: [_jsx(User, { className: "h-4 w-4 text-teal-500" }), "Avatar Partner"] }), _jsx(FileUpload, { id: "partner-avatar-url", label: "", accept: "image/*", value: watchedPartnerAvatarUrl || '', onChange: (url) => form.setValue('partnerAvatarUrl', url, { shouldValidate: true }), maxSize: 5, placeholder: "Upload \u1EA3nh avatar Partner (PNG, JPG, ...)", autoUpload: true, prefix: "speaking/partner-avatar" })] }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { className: "flex items-center gap-2 text-sm font-semibold text-gray-700", children: [_jsx(Image, { className: "h-4 w-4 text-teal-500" }), "H\u00ECnh \u1EA3nh phase (t\u00F9y ch\u1ECDn)"] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: handleAddImage, className: "gap-1.5 border-teal-200 text-teal-700 hover:bg-teal-50 text-xs", children: [_jsx(Plus, { className: "h-3.5 w-3.5" }), "Th\u00EAm h\u00ECnh"] })] }), watchedImages.length === 0 ? (_jsxs("div", { className: "rounded-lg border-2 border-dashed border-teal-200 bg-teal-50/40 py-6 text-center", children: [_jsx(Image, { className: "mx-auto h-8 w-8 text-teal-300 mb-2" }), _jsx("p", { className: "text-sm text-gray-400", children: "Kh\u00F4ng c\u00F3 h\u00ECnh \u1EA3nh \u2014 d\u00F9ng cho Part 2 phases c\u00F3 tranh" })] })) : (_jsx("div", { className: "space-y-3", children: watchedImages.map((img, index) => (_jsxs("div", { className: "rounded-lg border border-gray-200 bg-gray-50 p-3 space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("span", { className: "text-xs font-semibold text-gray-600", children: ["H\u00ECnh ", index + 1] }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "h-6 w-6 text-red-400 hover:text-red-600 hover:bg-red-50", onClick: () => handleRemoveImage(index), children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) })] }), _jsx(FileUpload, { id: `image-url-${index}`, label: "", accept: "image/*", value: img.url, onChange: (url) => handleImageChange(index, 'url', url), maxSize: 10, placeholder: "Upload h\u00ECnh \u1EA3nh", autoUpload: true, prefix: "speaking/phase-images" }), _jsx(Input, { value: img.label, onChange: (e) => handleImageChange(index, 'label', e.target.value), placeholder: "Nh\u00E3n h\u00ECnh (VD: Park, Bedroom, Library ...)", className: "border-gray-200 text-sm focus:border-teal-300" })] }, img.id))) }))] })] })) : (
353
+ /* Read-only group data view for non-first questions */
354
+ _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-gray-100 bg-gray-50 px-4 py-3", children: [_jsx(User, { className: "h-4 w-4 text-teal-500 flex-shrink-0" }), _jsxs("div", { children: [_jsx("p", { className: "text-xs text-gray-500", children: "T\u00EAn Partner" }), _jsx("p", { className: "text-sm font-medium text-gray-800", children: groupData.partnerName || (_jsx("span", { className: "italic text-gray-400", children: "Ch\u01B0a \u0111\u1EB7t t\u00EAn" })) })] })] }), groupData.images && groupData.images.length > 0 && (_jsxs("div", { className: "rounded-lg border border-gray-100 bg-gray-50 px-4 py-3", children: [_jsxs("p", { className: "text-xs text-gray-500 mb-2", children: ["H\u00ECnh \u1EA3nh (", groupData.images.length, ")"] }), _jsx("div", { className: "flex flex-wrap gap-2", children: groupData.images.map((img) => (_jsx("span", { className: "inline-flex items-center rounded-full bg-teal-100 px-2 py-0.5 text-xs text-teal-700", children: img.label || img.id }, img.id))) })] }))] })) }), _jsxs(CompactFieldCard, { header: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-md bg-gray-100", children: _jsx(Mic, { className: "h-3.5 w-3.5 text-gray-600" }) }), _jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("p", { className: "text-sm font-semibold text-gray-800", children: "N\u1ED9i dung c\u00E2u h\u1ECFi" }), isPartnerResponder && (_jsx(Badge, { className: "bg-orange-100 text-orange-700 border-orange-200 border text-xs font-semibold", children: "C\u00E2u h\u1ECFi m\u1EABu (Example)" }))] }), _jsx("p", { className: "text-sm text-gray-500 mt-0.5", children: isPartnerResponder
355
+ ? 'Partner trả lời học sinh chỉ nghe, không ghi âm'
356
+ : 'Student trả lời — học sinh ghi âm câu trả lời' })] })] }), children: [_jsxs("div", { className: `rounded-xl border p-4 space-y-4 ${isPartnerResponder ? 'border-orange-200 bg-orange-50/40' : 'border-indigo-200 bg-indigo-50/40'}`, children: [_jsx("div", { className: "flex items-center justify-between", children: _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-base font-semibold text-gray-800", children: "Ng\u01B0\u1EDDi tr\u1EA3 l\u1EDDi" }), _jsx("p", { className: "text-sm text-gray-500", children: "Ai s\u1EBD tr\u1EA3 l\u1EDDi c\u00E2u h\u1ECFi n\u00E0y trong b\u00E0i thi?" })] }) }), _jsxs("div", { className: "flex gap-3", children: [_jsxs("button", { type: "button", onClick: () => form.setValue('responder', 'PARTNER', { shouldValidate: true }), className: `flex flex-1 items-center gap-3 rounded-xl border-2 p-3 transition-all ${isPartnerResponder
357
+ ? 'border-orange-400 bg-orange-50 shadow-sm'
358
+ : 'border-gray-200 bg-white hover:border-gray-300'}`, children: [_jsx("div", { className: `flex h-9 w-9 items-center justify-center rounded-full ${isPartnerResponder ? 'bg-orange-500' : 'bg-gray-200'}`, children: _jsx(User, { className: `h-4 w-4 ${isPartnerResponder ? 'text-white' : 'text-gray-500'}` }) }), _jsxs("div", { className: "text-left", children: [_jsx("p", { className: `text-sm font-semibold ${isPartnerResponder ? 'text-orange-800' : 'text-gray-700'}`, children: "Partner tr\u1EA3 l\u1EDDi" }), _jsx("p", { className: `text-xs ${isPartnerResponder ? 'text-orange-600' : 'text-gray-500'}`, children: "C\u00E2u m\u1EABu \u2014 is_example=true, points=0" })] })] }), _jsxs("button", { type: "button", onClick: () => form.setValue('responder', 'STUDENT', { shouldValidate: true }), className: `flex flex-1 items-center gap-3 rounded-xl border-2 p-3 transition-all ${!isPartnerResponder
359
+ ? 'border-indigo-400 bg-indigo-50 shadow-sm'
360
+ : 'border-gray-200 bg-white hover:border-gray-300'}`, children: [_jsx("div", { className: `flex h-9 w-9 items-center justify-center rounded-full ${!isPartnerResponder ? 'bg-indigo-500' : 'bg-gray-200'}`, children: _jsx(UserCheck, { className: `h-4 w-4 ${!isPartnerResponder ? 'text-white' : 'text-gray-500'}` }) }), _jsxs("div", { className: "text-left", children: [_jsx("p", { className: `text-sm font-semibold ${!isPartnerResponder ? 'text-indigo-800' : 'text-gray-700'}`, children: "Student tr\u1EA3 l\u1EDDi" }), _jsx("p", { className: `text-xs ${!isPartnerResponder ? 'text-indigo-600' : 'text-gray-500'}`, children: "C\u00E2u th\u1EF1c \u2014 h\u1ECDc sinh ghi \u00E2m" })] })] })] }), form.hasError('responder') && (_jsx("p", { className: "text-sm text-red-600", children: form.getFieldError('responder') }))] }), isPartnerResponder && (_jsx("p", { className: "text-xs text-orange-600", children: "C\u00E2u h\u1ECFi m\u1EABu (Partner) lu\u00F4n c\u00F3 0 \u0111i\u1EC3m" })), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-sm font-semibold text-gray-700", children: [_jsx(Volume2, { className: "h-4 w-4 text-blue-500" }), "Audio Interlocutor", _jsx("span", { className: "text-xs font-normal text-gray-400", children: "(t\u00F9y ch\u1ECDn)" })] }), _jsx(FileUpload, { id: "interlocutor-audio-url", label: "", accept: "audio/*", value: watchedInterlocutorAudioUrl || '', onChange: (url) => form.setValue('interlocutorAudioUrl', url, { shouldValidate: true }), maxSize: 20, placeholder: "Upload audio c\u00E2u h\u1ECFi c\u1EE7a Interlocutor (MP3, WAV...)", autoUpload: true, prefix: "speaking/interlocutor" }), _jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-blue-100 bg-blue-50/60 px-3 py-2", children: [_jsx(Info, { className: "h-4 w-4 text-blue-500 mt-0.5 flex-shrink-0" }), _jsx("p", { className: "text-xs text-blue-700", children: "Audio c\u1EE7a Interlocutor (ng\u01B0\u1EDDi h\u1ECFi). Ph\u00E1t tr\u01B0\u1EDBc khi Partner ho\u1EB7c Student tr\u1EA3 l\u1EDDi." })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-sm font-semibold text-gray-700", children: [_jsx(Volume2, { className: "h-4 w-4 text-orange-500" }), "Audio Partner", isPartnerResponder && _jsx("span", { className: "text-red-500", children: "*" }), !isPartnerResponder && (_jsx("span", { className: "text-xs font-normal text-gray-400", children: "(t\u00F9y ch\u1ECDn)" }))] }), _jsx(FileUpload, { id: "partner-audio-url", label: "", accept: "audio/*", value: watchedPartnerAudioUrl || '', onChange: (url) => form.setValue('partnerAudioUrl', url, { shouldValidate: true }), maxSize: 20, placeholder: "Upload audio tr\u1EA3 l\u1EDDi c\u1EE7a Partner (MP3, WAV...)", autoUpload: true, prefix: "speaking/partner" }), form.hasError('partnerAudioUrl') && (_jsx("p", { className: "text-sm text-red-600", children: form.getFieldError('partnerAudioUrl') })), _jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-orange-100 bg-orange-50/60 px-3 py-2", children: [_jsx(Info, { className: "h-4 w-4 text-orange-500 mt-0.5 flex-shrink-0" }), _jsx("p", { className: "text-xs text-orange-700", children: isPartnerResponder
361
+ ? 'Bắt buộc khi responder = Partner. Phát sau audio Interlocutor.'
362
+ : 'Tùy chọn khi responder = Student — dùng cho Talk Together (Partner nói trước, Student trả lời sau).' })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-sm font-semibold text-gray-700", children: [_jsx(MessageSquareText, { className: "h-4 w-4 text-gray-500" }), "Text c\u00E2u h\u1ECFi (t\u00F9y ch\u1ECDn)"] }), _jsx(Textarea, { ...form.register('questionText'), placeholder: "VD: What's your name? How old are you?", rows: 2, className: "min-h-[60px] border-gray-200 focus:border-indigo-300 focus:ring-indigo-200 resize-none" }), _jsx("p", { className: "text-xs text-gray-400", children: "Ch\u1EC9 hi\u1EC3n th\u1ECB cho admin/gi\u00E1o vi\u00EAn khi review. H\u1ECDc sinh ch\u1EC9 nghe audio." })] }), _jsxs("div", { className: "flex items-center justify-between rounded-lg border border-gray-200 bg-gray-50 px-4 py-3", children: [_jsxs("div", { className: "space-y-0.5", children: [_jsx(Label, { className: "text-sm font-semibold text-gray-700", children: "C\u00E2u h\u1ECFi d\u1EF1 ph\u00F2ng" }), _jsx("p", { className: "text-xs text-gray-400", children: "\u0110\u00E1nh d\u1EA5u c\u00E2u h\u1ECFi n\u00E0y l\u00E0 d\u1EF1 ph\u00F2ng (backup)" })] }), _jsx(Switch, { checked: watchedIsBackup, onCheckedChange: (checked) => form.setValue('isBackup', checked, { shouldValidate: true }) })] })] }), _jsxs(CompactFieldCard, { header: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-md bg-gray-100", children: _jsx(MessageSquareText, { className: "h-3.5 w-3.5 text-gray-600" }) }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("p", { className: "text-sm font-semibold text-gray-800", children: "\u0110\u00E1p \u00E1n mong mu\u1ED1n" }), _jsx("span", { className: "inline-flex items-center rounded-full border border-green-200 bg-green-50 px-2.5 py-0.5 text-xs font-medium text-green-600", children: "Kh\u00F4ng b\u1EAFt bu\u1ED9c" })] }), _jsx("p", { className: "text-sm text-gray-500 mt-0.5", children: isPartnerResponder
363
+ ? 'Câu mẫu đáp án dùng để ghi nhớ nội dung (không chấm điểm)'
364
+ : 'Đáp án tham chiếu để giáo viên chấm thủ công' })] })] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: handleAddExpectedAnswer, className: "gap-1.5 border-green-200 text-green-700 hover:bg-green-50", children: [_jsx(Plus, { className: "h-4 w-4" }), "Th\u00EAm \u0111\u00E1p \u00E1n"] })] }), children: [_jsxs("div", { className: "flex items-start gap-2 rounded-lg border border-blue-100 bg-blue-50/60 px-3 py-2.5", children: [_jsx(Info, { className: "h-4 w-4 text-blue-500 mt-0.5 flex-shrink-0" }), _jsx("p", { className: "text-xs text-blue-700", children: isPartnerResponder
365
+ ? 'Câu hỏi mẫu: thể nhập nội dung Partner nói để ghi nhớ. Không dùng để chấm điểm.'
366
+ : 'Giáo viên dùng các đáp án này làm tham chiếu khi chấm thủ công câu trả lời của học sinh.' })] }), watchedExpectedAnswers.map((answer, index) => (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-full bg-green-100 text-xs font-semibold text-green-700 mt-1.5 flex-shrink-0", children: index + 1 }), _jsx(Textarea, { value: answer || '', onChange: (e) => handleExpectedAnswerChange(index, e.target.value), placeholder: index === 0
367
+ ? 'VD: My name is Bingo. I am 8 years old.'
368
+ : 'Thêm đáp án mẫu khác...', rows: 2, className: "min-h-[60px] border-gray-200 bg-white transition-all focus:border-green-300 focus:ring-green-200 resize-none flex-1" }), watchedExpectedAnswers.length > 1 && (_jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "mt-1.5 h-7 w-7 text-red-400 hover:text-red-600 hover:bg-red-50 flex-shrink-0", onClick: () => handleRemoveExpectedAnswer(index), "aria-label": `Xóa đáp án ${index + 1}`, children: _jsx(Trash2, { className: "h-4 w-4" }) }))] }, index)))] }), _jsx(CompactExplanationToggle, { value: watchedExplanation || '', onValueChange: (value) => form.setValue('explanation', value, { shouldValidate: true }), defaultVisible: Boolean(watchedExplanation) }), externalErrors && externalErrors.length > 0 && (_jsx("div", { className: "flex items-start gap-3 rounded-xl border border-red-200 bg-red-50 p-4", children: _jsxs("div", { className: "text-sm", children: [_jsx("p", { className: "font-semibold text-red-800", children: "C\u1EA7n s\u1EEDa c\u00E1c l\u1ED7i sau:" }), _jsx("ul", { className: "mt-1 list-inside list-disc text-red-700", children: externalErrors.map((error, index) => (_jsx("li", { children: error }, index))) })] }) }))] }));
373
369
  }
@@ -33,9 +33,9 @@ export function SpeakingConversationPreviewClient({ questionData, isReviewMode =
33
33
  : questionData.images.length === 4
34
34
  ? 'grid-cols-4'
35
35
  : 'grid-cols-3';
36
- return (_jsxs("div", { className: "space-y-4", children: [questionData.isBackup && (_jsxs("div", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md bg-amber-50 text-amber-700 border border-amber-200 text-xs font-bold shadow-sm", children: [_jsx("span", { children: "\uD83D\uDD04" }), " C\u00E2u h\u1ECFi d\u1EF1 ph\u00F2ng"] })), _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-100 bg-gradient-to-r from-indigo-50 to-blue-50 px-5 py-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-indigo-500 to-blue-600 text-white shadow-sm", children: _jsx(MessageCircle, { className: "h-4 w-4" }) }), _jsx("span", { className: "text-sm font-medium text-gray-700", children: "H\u1ED9i tho\u1EA1i Speaking (KFS)" })] }), _jsxs("div", { className: `inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold ${isPartnerQuestion
36
+ return (_jsxs("div", { className: "space-y-4", children: [questionData.isBackup && (_jsxs("div", { className: "inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md bg-amber-50 text-amber-700 border border-amber-200 text-xs font-bold shadow-sm", children: [_jsx("span", { children: "\uD83D\uDD04" }), " C\u00E2u h\u1ECFi d\u1EF1 ph\u00F2ng"] })), _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-100 bg-gray-50 px-3 py-2", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-md bg-gray-100 text-gray-600", children: _jsx(MessageCircle, { className: "h-4 w-4" }) }), _jsx("span", { className: "text-sm font-medium text-gray-700", children: "H\u1ED9i tho\u1EA1i Speaking (KFS)" })] }), _jsxs("div", { className: `inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold ${isPartnerQuestion
37
37
  ? 'bg-orange-100 text-orange-700 border border-orange-200'
38
- : 'bg-green-100 text-green-700 border border-green-200'}`, children: [_jsx(Mic, { className: "h-3 w-3" }), isPartnerQuestion ? 'Bạn thi (ví dụ)' : 'Học sinh trả lời'] })] }), _jsxs("div", { className: "p-5 space-y-5", children: [(questionData.partnerName || questionData.partnerAvatarUrl) && (_jsxs("div", { className: "flex items-center gap-2 rounded-lg bg-orange-50 border border-orange-100 px-4 py-2.5", children: [_jsx("span", { className: "text-xs font-medium text-orange-600", children: "Nh\u00E2n v\u1EADt b\u1EA1n thi:" }), _jsx(PartnerAvatar, { avatarUrl: questionData.partnerAvatarUrl, name: questionData.partnerName })] })), questionData.questionText && (_jsxs("div", { className: "rounded-lg bg-blue-50 border border-blue-200 px-4 py-3", children: [_jsx("p", { className: "text-xs font-medium text-blue-600 mb-1", children: "N\u1ED9i dung c\u00E2u h\u1ECFi:" }), _jsx("p", { className: "text-sm font-semibold text-gray-800", children: questionData.questionText })] })), _jsxs("div", { className: "space-y-3", children: [questionData.interlocutorAudioUrl && (_jsx(ConversationAudioPlayer, { audioUrl: questionData.interlocutorAudioUrl, label: "Audio ng\u01B0\u1EDDi h\u1ECFi (Interlocutor)" })), questionData.partnerAudioUrl && (_jsx(ConversationAudioPlayer, { audioUrl: questionData.partnerAudioUrl, label: "Audio b\u1EA1n thi (Partner)" }))] }), hasImages && (_jsxs("div", { children: [_jsx("p", { className: "text-xs font-medium text-gray-500 mb-2", children: "H\u00ECnh \u1EA3nh th\u1EA3o lu\u1EADn:" }), _jsx("div", { className: `grid ${gridCols} gap-3`, style: { maxWidth: '500px' }, children: questionData.images.map((img) => (_jsx(PreviewImageItem, { url: img.url, label: img.label }, img.id))) })] })), _jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-dashed border-gray-300 bg-gray-50/80 px-4 py-3", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-indigo-50 ring-2 ring-indigo-100/50", children: _jsx(Mic, { className: "w-4 h-4 text-indigo-400" }) }), _jsx("p", { className: "text-xs text-gray-400", children: isPartnerQuestion
38
+ : 'bg-green-100 text-green-700 border border-green-200'}`, children: [_jsx(Mic, { className: "h-3 w-3" }), isPartnerQuestion ? 'Bạn thi (ví dụ)' : 'Học sinh trả lời'] })] }), _jsxs("div", { className: "p-3 space-y-3", children: [(questionData.partnerName || questionData.partnerAvatarUrl) && (_jsxs("div", { className: "flex items-center gap-2 rounded-lg bg-orange-50 border border-orange-100 px-4 py-2.5", children: [_jsx("span", { className: "text-xs font-medium text-orange-600", children: "Nh\u00E2n v\u1EADt b\u1EA1n thi:" }), _jsx(PartnerAvatar, { avatarUrl: questionData.partnerAvatarUrl, name: questionData.partnerName })] })), questionData.questionText && (_jsxs("div", { className: "rounded-lg bg-blue-50 border border-blue-200 px-4 py-3", children: [_jsx("p", { className: "text-xs font-medium text-blue-600 mb-1", children: "N\u1ED9i dung c\u00E2u h\u1ECFi:" }), _jsx("p", { className: "text-sm font-semibold text-gray-800", children: questionData.questionText })] })), _jsxs("div", { className: "space-y-3", children: [questionData.interlocutorAudioUrl && (_jsx(ConversationAudioPlayer, { audioUrl: questionData.interlocutorAudioUrl, label: "Audio ng\u01B0\u1EDDi h\u1ECFi (Interlocutor)" })), questionData.partnerAudioUrl && (_jsx(ConversationAudioPlayer, { audioUrl: questionData.partnerAudioUrl, label: "Audio b\u1EA1n thi (Partner)" }))] }), hasImages && (_jsxs("div", { children: [_jsx("p", { className: "text-xs font-medium text-gray-500 mb-2", children: "H\u00ECnh \u1EA3nh th\u1EA3o lu\u1EADn:" }), _jsx("div", { className: `grid ${gridCols} gap-3`, style: { maxWidth: '500px' }, children: questionData.images.map((img) => (_jsx(PreviewImageItem, { url: img.url, label: img.label }, img.id))) })] })), _jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-dashed border-gray-300 bg-gray-50/80 px-4 py-3", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-indigo-50 ring-2 ring-indigo-100/50", children: _jsx(Mic, { className: "w-4 h-4 text-indigo-400" }) }), _jsx("p", { className: "text-xs text-gray-400", children: isPartnerQuestion
39
39
  ? 'Câu hỏi ví dụ — Bạn thi sẽ trả lời, học sinh lắng nghe'
40
40
  : 'Học sinh sẽ nhấn nút ghi âm và nói câu trả lời tại đây' })] }), isReviewMode && questionData.expectedAnswers && questionData.expectedAnswers.length > 0 && (_jsxs("div", { className: "rounded-xl border border-green-200 bg-green-50/80 p-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-3", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-green-600" }), _jsx("h4", { className: "text-sm font-semibold text-green-800", children: "C\u00E1c \u0111\u00E1p \u00E1n mong mu\u1ED1n" })] }), _jsx("div", { className: "space-y-2", children: questionData.expectedAnswers.map((answer, index) => (_jsxs("div", { className: "flex items-center gap-2.5 rounded-lg bg-white/70 border border-green-100 px-3 py-2", children: [_jsx("span", { className: "flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-green-100 text-green-700 text-xs font-bold", children: index + 1 }), _jsx("span", { className: "text-sm text-green-800", children: answer })] }, index))) })] }))] })] })] }));
41
41
  }
@@ -23,5 +23,5 @@ export function mapQuestionToSpeakingCueCardData(question) {
23
23
  }
24
24
  export function SpeakingCueCardClient({ questionData, isReviewMode = false, }) {
25
25
  const answers = questionData.expectedAnswers || [];
26
- return (_jsxs("div", { className: "space-y-4", children: [questionData.isBackup && (_jsxs("div", { className: "inline-flex self-center items-center gap-1.5 px-3 py-1.5 rounded-md bg-amber-50 text-amber-700 border border-amber-200 text-xs font-bold shadow-sm", children: [_jsx("span", { children: "\uD83D\uDD04" }), " C\u00E2u h\u1ECFi d\u1EF1 ph\u00F2ng"] })), _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm", children: [_jsx("div", { className: "flex items-center justify-between border-b border-gray-100 bg-gradient-to-r from-purple-50 to-indigo-50 px-5 py-3", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-purple-500 to-indigo-600 text-white shadow-sm", children: _jsx(CreditCard, { className: "h-4 w-4" }) }), _jsx("span", { className: "text-sm font-medium text-gray-700", children: "Th\u1EBB g\u1EE3i \u00FD (Cue Card)" })] }) }), _jsxs("div", { className: "p-5 space-y-5", children: [_jsx("div", { className: "rounded-xl border border-purple-100 bg-purple-50/40 px-5 py-4", children: _jsx(RichTextHtml, { html: questionData.cueCardHtml, className: "text-sm text-slate-800", fallback: _jsx("p", { className: "text-sm text-gray-400", children: "Ch\u01B0a c\u00F3 n\u1ED9i dung cue card" }) }) }), _jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-dashed border-gray-300 bg-gray-50/80 px-4 py-3", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-purple-50 ring-2 ring-purple-100/50", children: _jsx(Mic, { className: "w-4 h-4 text-purple-400" }) }), _jsx("p", { className: "text-xs text-gray-400", children: "H\u1ECDc sinh \u0111\u1ECDc th\u1EBB g\u1EE3i \u00FD, chu\u1EA9n b\u1ECB, r\u1ED3i tr\u1EA3 l\u1EDDi b\u1EB1ng gi\u1ECDng n\u00F3i" })] }), isReviewMode && answers.length > 0 && (_jsxs("div", { className: "rounded-xl border border-green-200 bg-green-50/80 p-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-3", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-green-600" }), _jsx("h4", { className: "text-sm font-semibold text-green-800", children: "\u0110\u00E1p \u00E1n m\u1EABu" })] }), _jsx("div", { className: "space-y-2", children: answers.map((answer, index) => (_jsxs("div", { className: "flex items-center gap-2.5 rounded-lg bg-white/70 border border-green-100 px-3 py-2", children: [_jsx("span", { className: "flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-green-100 text-green-700 text-xs font-bold", children: index + 1 }), _jsx("span", { className: "text-sm text-green-800", children: answer })] }, `${answer}-${index}`))) })] })), isReviewMode && questionData.explanation && (_jsxs("div", { className: "rounded-xl border border-amber-200 bg-amber-50 p-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-2", children: [_jsx(Info, { className: "h-4 w-4 text-amber-600" }), _jsx("p", { className: "text-sm font-semibold text-amber-800", children: "Gi\u1EA3i th\u00EDch" })] }), _jsx("p", { className: "text-sm text-amber-700 leading-relaxed whitespace-pre-wrap", children: questionData.explanation })] }))] })] })] }));
26
+ return (_jsxs("div", { className: "space-y-4", children: [questionData.isBackup && (_jsxs("div", { className: "inline-flex self-center items-center gap-1.5 px-3 py-1.5 rounded-md bg-amber-50 text-amber-700 border border-amber-200 text-xs font-bold shadow-sm", children: [_jsx("span", { children: "\uD83D\uDD04" }), " C\u00E2u h\u1ECFi d\u1EF1 ph\u00F2ng"] })), _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm", children: [_jsx("div", { className: "flex items-center justify-between border-b border-gray-100 bg-gray-50 px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-md bg-gray-100 text-gray-600", children: _jsx(CreditCard, { className: "h-4 w-4" }) }), _jsx("span", { className: "text-sm font-medium text-gray-700", children: "Th\u1EBB g\u1EE3i \u00FD (Cue Card)" })] }) }), _jsxs("div", { className: "p-3 space-y-3", children: [_jsx("div", { className: "rounded-xl border border-purple-100 bg-purple-50/40 px-5 py-4", children: _jsx(RichTextHtml, { html: questionData.cueCardHtml, className: "text-sm text-slate-800", fallback: _jsx("p", { className: "text-sm text-gray-400", children: "Ch\u01B0a c\u00F3 n\u1ED9i dung cue card" }) }) }), _jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-dashed border-gray-300 bg-gray-50/80 px-4 py-3", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-purple-50 ring-2 ring-purple-100/50", children: _jsx(Mic, { className: "w-4 h-4 text-purple-400" }) }), _jsx("p", { className: "text-xs text-gray-400", children: "H\u1ECDc sinh \u0111\u1ECDc th\u1EBB g\u1EE3i \u00FD, chu\u1EA9n b\u1ECB, r\u1ED3i tr\u1EA3 l\u1EDDi b\u1EB1ng gi\u1ECDng n\u00F3i" })] }), isReviewMode && answers.length > 0 && (_jsxs("div", { className: "rounded-xl border border-green-200 bg-green-50/80 p-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-3", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-green-600" }), _jsx("h4", { className: "text-sm font-semibold text-green-800", children: "\u0110\u00E1p \u00E1n m\u1EABu" })] }), _jsx("div", { className: "space-y-2", children: answers.map((answer, index) => (_jsxs("div", { className: "flex items-center gap-2.5 rounded-lg bg-white/70 border border-green-100 px-3 py-2", children: [_jsx("span", { className: "flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-green-100 text-green-700 text-xs font-bold", children: index + 1 }), _jsx("span", { className: "text-sm text-green-800", children: answer })] }, `${answer}-${index}`))) })] })), isReviewMode && questionData.explanation && (_jsxs("div", { className: "rounded-xl border border-amber-200 bg-amber-50 p-4", children: [_jsxs("div", { className: "flex items-center gap-2 mb-2", children: [_jsx(Info, { className: "h-4 w-4 text-amber-600" }), _jsx("p", { className: "text-sm font-semibold text-amber-800", children: "Gi\u1EA3i th\u00EDch" })] }), _jsx("p", { className: "text-sm text-amber-700 leading-relaxed whitespace-pre-wrap", children: questionData.explanation })] }))] })] })] }));
27
27
  }
@@ -1,15 +1,15 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useRef, useCallback } from 'react';
4
- import { Card, CardContent, CardHeader, CardTitle } from '../../../../components/ui/card';
5
- import { Input } from '../../../../components/ui/input';
6
4
  import { Label } from '../../../../components/ui/label';
7
5
  import { CueCardEditor } from '../../../../components/shared/CueCardEditor';
8
- import { CreatorGuide } from '../../components/CreatorGuide';
9
6
  import { CreditCard } from 'lucide-react';
7
+ import { CompactCreatorHeader, CompactFieldCard, CompactPreviewBanner, } from '../../_shared/components/compact';
8
+ import { SpeakingCueCardClient } from './SpeakingCueCardClient';
10
9
  export function SpeakingCueCardCreator({ initialData, onChange, onUnsavedChangesChange, externalErrors, validationRef, }) {
11
10
  const [htmlContent, setHtmlContent] = useState(initialData?.cueCardHtml || '');
12
11
  const [points, setPoints] = useState(initialData?.points ?? 5);
12
+ const [isClientMode, setIsClientMode] = useState(false);
13
13
  const isInitializingRef = useRef(true);
14
14
  const previousInitialDataRef = useRef(initialData);
15
15
  const previousPayloadRef = useRef(null);
@@ -66,9 +66,8 @@ export function SpeakingCueCardCreator({ initialData, onChange, onUnsavedChanges
66
66
  };
67
67
  }
68
68
  }, [validationRef, htmlContent, points, buildPayload]);
69
- return (_jsxs("div", { className: "space-y-6", children: [_jsx(CreatorGuide, { colorScheme: "purple", steps: [
70
- { text: 'Nhập nội dung Cue Card bao gồm chủ đề các gợi ý (bullet points)', highlight: true },
71
- ], tips: [
72
- 'Cue Card nên 1 chủ đề chính 3-4 gợi ý (bullet points) theo format IELTS Part 2.',
73
- ] }), _jsxs(Card, { className: "overflow-hidden border border-slate-200 bg-white shadow-sm", children: [_jsx(CardHeader, { className: "border-b border-slate-100 bg-slate-50/50 pb-4", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-lg bg-purple-100 text-purple-700", children: _jsx(CreditCard, { className: "h-4 w-4" }) }), _jsx(CardTitle, { className: "text-lg font-semibold text-slate-800", children: "C\u00E2u h\u1ECFi Th\u1EBB g\u1EE3i \u00FD (Cue Card)" })] }) }), _jsxs(CardContent, { className: "p-0", children: [_jsxs("div", { className: "p-6 space-y-8", children: [_jsxs("div", { className: "w-full xl:w-1/3 space-y-1.5 animate-in fade-in zoom-in-95 duration-200", children: [_jsxs(Label, { htmlFor: "points", className: "text-sm font-semibold text-slate-700", children: ["\u0110i\u1EC3m s\u1ED1 ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { id: "points", type: "number", step: "1", min: "1", value: points, onChange: (e) => setPoints(parseInt(e.target.value) || 0), className: "w-24 border-slate-200 focus:border-blue-400 focus:ring-blue-100" })] }), _jsx("hr", { className: "border-slate-100" }), _jsx("div", { className: "space-y-3", children: _jsx(CueCardEditor, { value: htmlContent, onChange: setHtmlContent, label: _jsxs(Label, { className: "text-sm font-semibold text-slate-700", children: ["N\u1ED9i dung Cue Card ", _jsx("span", { className: "text-red-500", children: "*" })] }) }) })] }), externalErrors && externalErrors.length > 0 && (_jsx("div", { className: "border-t border-red-100 bg-red-50 p-6", children: _jsx("div", { className: "flex items-start gap-3", children: _jsxs("div", { className: "text-sm", children: [_jsx("p", { className: "font-semibold text-red-800", children: "C\u1EA7n ph\u1EA3i s\u1EEDa c\u00E1c l\u1ED7i sau:" }), _jsx("ul", { className: "mt-1 list-inside list-disc text-red-700", children: externalErrors.map((error, index) => (_jsx("li", { children: error }, index))) })] }) }) }))] })] })] }));
69
+ if (isClientMode) {
70
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(CompactPreviewBanner, { onBack: () => setIsClientMode(false) }), _jsx(SpeakingCueCardClient, { questionData: { cueCardHtml: htmlContent }, isReviewMode: true })] }));
71
+ }
72
+ return (_jsx("div", { className: "space-y-3", children: _jsxs(CompactFieldCard, { header: _jsx(CompactCreatorHeader, { icon: _jsx(CreditCard, { className: "h-3.5 w-3.5" }), title: "C\u00E2u h\u1ECFi Th\u1EBB g\u1EE3i \u00FD (Cue Card)", points: { value: points, onValueChange: setPoints }, preview: { onClick: () => setIsClientMode(true) } }), children: [_jsx(CueCardEditor, { value: htmlContent, onChange: setHtmlContent, label: _jsxs(Label, { className: "text-sm font-semibold text-slate-700", children: ["N\u1ED9i dung Cue Card ", _jsx("span", { className: "text-red-500", children: "*" })] }) }), externalErrors && externalErrors.length > 0 && (_jsxs("div", { className: "rounded-md border border-red-100 bg-red-50 px-3 py-2 text-xs", children: [_jsx("p", { className: "font-semibold text-red-800", children: "C\u1EA7n ph\u1EA3i s\u1EEDa c\u00E1c l\u1ED7i sau:" }), _jsx("ul", { className: "mt-1 list-inside list-disc text-red-700", children: externalErrors.map((error, index) => (_jsx("li", { children: error }, index))) })] }))] }) }));
74
73
  }
@@ -4,7 +4,7 @@ import { Mic, CheckCircle2, Info, ImageIcon, FileQuestion } from 'lucide-react';
4
4
  import { usePresignedFileUrl } from '../../../../shared/lib/hooks';
5
5
  export function SpeakingDescribeImageClient({ questionData, isReviewMode = false, }) {
6
6
  const { previewUrl: imageUrl } = usePresignedFileUrl(questionData.imageUrl || '');
7
- return (_jsxs("div", { className: "space-y-4", children: [questionData.isBackup && (_jsxs("div", { className: "inline-flex self-center items-center gap-1.5 px-3 py-1.5 rounded-md bg-amber-50 text-amber-700 border border-amber-200 text-xs font-bold shadow-sm", children: [_jsx("span", { children: "\uD83D\uDD04" }), " C\u00E2u h\u1ECFi d\u1EF1 ph\u00F2ng"] })), _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm", children: [_jsx("div", { className: "flex items-center justify-between border-b border-gray-100 bg-gradient-to-r from-indigo-50 to-blue-50 px-5 py-3", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-indigo-500 to-blue-600 text-white shadow-sm", children: _jsx(Mic, { className: "h-4 w-4" }) }), _jsx("span", { className: "text-sm font-medium text-gray-700", children: "M\u00F4 t\u1EA3 h\u00ECnh \u1EA3nh (Speaking)" })] }) }), _jsxs("div", { className: "p-5 space-y-5", children: [questionData.question && (_jsxs("div", { className: "flex gap-3", children: [_jsx(FileQuestion, { className: "h-5 w-5 text-indigo-500 shrink-0 mt-0.5" }), _jsx("div", { className: "text-base font-semibold text-gray-800", children: questionData.question })] })), imageUrl ? (_jsx("div", { className: "w-full max-w-3xl mx-auto rounded-xl overflow-hidden shadow-sm border border-gray-200 bg-gray-50 flex justify-center", children: _jsx("img", { src: imageUrl, alt: "Scene", className: "w-[80%] max-h-[400px] object-contain flex-shrink-0" }) })) : (_jsxs("div", { className: "flex flex-col items-center justify-center py-10 rounded-xl border border-dashed border-gray-300 bg-gray-50", children: [_jsx(ImageIcon, { className: "h-8 w-8 text-gray-400 mb-2" }), _jsx("span", { className: "text-sm text-gray-500", children: "Ch\u01B0a t\u1EA3i h\u00ECnh \u1EA3nh m\u00F4 t\u1EA3" })] })), _jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-dashed border-gray-300 bg-gray-50/80 px-4 py-3", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-indigo-50 ring-2 ring-indigo-100/50", children: _jsx(Mic, { className: "w-4 h-4 text-indigo-400" }) }), _jsx("p", { className: "text-xs text-gray-400", children: isReviewMode && questionData.audioUrl
7
+ return (_jsxs("div", { className: "space-y-4", children: [questionData.isBackup && (_jsxs("div", { className: "inline-flex self-center items-center gap-1.5 px-3 py-1.5 rounded-md bg-amber-50 text-amber-700 border border-amber-200 text-xs font-bold shadow-sm", children: [_jsx("span", { children: "\uD83D\uDD04" }), " C\u00E2u h\u1ECFi d\u1EF1 ph\u00F2ng"] })), _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm", children: [_jsx("div", { className: "flex items-center justify-between border-b border-gray-100 bg-gray-50 px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-md bg-gray-100 text-gray-600", children: _jsx(Mic, { className: "h-4 w-4" }) }), _jsx("span", { className: "text-sm font-medium text-gray-700", children: "M\u00F4 t\u1EA3 h\u00ECnh \u1EA3nh (Speaking)" })] }) }), _jsxs("div", { className: "p-3 space-y-3", children: [questionData.question && (_jsxs("div", { className: "flex gap-3", children: [_jsx(FileQuestion, { className: "h-5 w-5 text-indigo-500 shrink-0 mt-0.5" }), _jsx("div", { className: "text-base font-semibold text-gray-800", children: questionData.question })] })), imageUrl ? (_jsx("div", { className: "w-full max-w-3xl mx-auto rounded-xl overflow-hidden shadow-sm border border-gray-200 bg-gray-50 flex justify-center", children: _jsx("img", { src: imageUrl, alt: "Scene", className: "w-[80%] max-h-[400px] object-contain flex-shrink-0" }) })) : (_jsxs("div", { className: "flex flex-col items-center justify-center py-10 rounded-xl border border-dashed border-gray-300 bg-gray-50", children: [_jsx(ImageIcon, { className: "h-8 w-8 text-gray-400 mb-2" }), _jsx("span", { className: "text-sm text-gray-500", children: "Ch\u01B0a t\u1EA3i h\u00ECnh \u1EA3nh m\u00F4 t\u1EA3" })] })), _jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-dashed border-gray-300 bg-gray-50/80 px-4 py-3", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-indigo-50 ring-2 ring-indigo-100/50", children: _jsx(Mic, { className: "w-4 h-4 text-indigo-400" }) }), _jsx("p", { className: "text-xs text-gray-400", children: isReviewMode && questionData.audioUrl
8
8
  ? "Audio ghi âm của học sinh (đã lưu)"
9
9
  : "Học sinh sẽ nhìn hình ảnh và nhấn nút micro để mô tả" })] }), isReviewMode && questionData.expectedAnswers && questionData.expectedAnswers.length > 0 && (_jsxs("div", { className: "rounded-xl border border-green-200 bg-green-50/80 p-4 mt-6", children: [_jsxs("div", { className: "flex items-center gap-2 mb-3", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-green-600" }), _jsx("h4", { className: "text-sm font-semibold text-green-800", children: "C\u00E1c \u0111\u00E1p \u00E1n t\u1EF1 \u0111\u1ED9ng (Tham chi\u1EBFu AI)" })] }), _jsx("div", { className: "space-y-2", children: questionData.expectedAnswers.map((answer, index) => (_jsxs("div", { className: "flex items-center gap-2.5 rounded-lg bg-white/70 border border-green-100 px-3 py-2", children: [_jsx("span", { className: "flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-green-100 text-green-700 text-xs font-bold", children: index + 1 }), _jsx("span", { className: "text-sm text-green-800", children: answer })] }, index))) })] })), isReviewMode && questionData.explanation && (_jsxs("div", { className: "rounded-xl border border-amber-200 bg-amber-50 p-4 mt-2", children: [_jsxs("div", { className: "flex items-center gap-2 mb-2", children: [_jsx(Info, { className: "h-4 w-4 text-amber-600" }), _jsx("p", { className: "text-sm font-semibold text-amber-800", children: "Gi\u1EA3i th\u00EDch gi\u00E1o vi\u00EAn" })] }), _jsx("p", { className: "text-sm text-amber-700 leading-relaxed whitespace-pre-wrap", children: questionData.explanation })] }))] })] })] }));
10
10
  }