@tinyweb_dev/oe-exam-sdk 1.0.6 → 1.0.8

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 (239) 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/choose-the-correct-answer-group.type.d.ts +2 -2
  29. package/dist/components/questions/_shared/types/choose-the-correct-answer-group.type.js +5 -1
  30. package/dist/components/questions/_shared/types/index.d.ts +0 -1
  31. package/dist/components/questions/_shared/types/index.js +0 -1
  32. package/dist/components/questions/_shared/types/look-and-choose-answer.type.d.ts +0 -13
  33. package/dist/components/questions/_shared/utils/answer-builder.js +0 -11
  34. package/dist/components/questions/components/ColorRegionCreator.js +66 -63
  35. package/dist/components/questions/components/QuestionSearchDropdown.js +0 -8
  36. package/dist/components/questions/components/QuestionTypeSelector.js +0 -2
  37. package/dist/components/questions/components/index.d.ts +1 -0
  38. package/dist/components/questions/components/index.js +1 -0
  39. package/dist/components/questions/creator/question-type-registry.js +0 -8
  40. package/dist/components/questions/groups/ArticlesGroupCard.js +2 -2
  41. package/dist/components/questions/groups/BasicQuestionGroupCard.js +1 -1
  42. package/dist/components/questions/groups/DocumentGroupCard.js +1 -1
  43. package/dist/components/questions/groups/ImageLabelGroupCard.js +1 -1
  44. package/dist/components/questions/groups/MatchAnswerGroupCard.js +2 -2
  45. package/dist/components/questions/question-bank/QuestionEditorRenderer.d.ts +0 -3
  46. package/dist/components/questions/question-bank/QuestionEditorRenderer.js +1 -10
  47. package/dist/components/questions/question-bank/editor-adapters/choice-adapters.d.ts +0 -2
  48. package/dist/components/questions/question-bank/editor-adapters/choice-adapters.js +0 -41
  49. package/dist/components/questions/question-bank/editor-adapters/index.d.ts +2 -2
  50. package/dist/components/questions/question-bank/editor-adapters/index.js +2 -2
  51. package/dist/components/questions/question-bank/editor-adapters/media-adapters.d.ts +0 -1
  52. package/dist/components/questions/question-bank/editor-adapters/media-adapters.js +0 -28
  53. package/dist/components/questions/question-bank/question-bank-picker.utils.js +0 -7
  54. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +16 -16
  55. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionCreator.js +36 -30
  56. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupClient.js +1 -1
  57. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupCreator.js +7 -6
  58. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +2 -2
  59. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsCreator.js +11 -7
  60. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +1 -1
  61. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js +11 -5
  62. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +5 -5
  63. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +34 -28
  64. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseAnswerGroupImageUpload.d.ts +7 -0
  65. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseAnswerGroupImageUpload.js +5 -2
  66. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupClient.js +9 -5
  67. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupCreator.js +65 -62
  68. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupItemEditor.d.ts +6 -0
  69. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupItemEditor.js +145 -0
  70. package/dist/components/questions/types/choose-the-correct-answer-group/map-choose-the-correct-answer-group-data.js +6 -15
  71. package/dist/components/questions/types/choose-the-correct-answer-group/transform.js +5 -4
  72. package/dist/components/questions/types/choose-then-answer-group/ChooseThenAnswerGroupClient.js +7 -7
  73. package/dist/components/questions/types/choose-then-answer-group/ChooseThenAnswerGroupCreator.js +8 -5
  74. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupClient.js +2 -2
  75. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupCreator.js +20 -16
  76. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleClient.js +1 -1
  77. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleCreator.js +66 -29
  78. package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +5 -5
  79. package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +45 -37
  80. package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupCreator.js +24 -20
  81. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +2 -2
  82. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridCreator.js +68 -65
  83. package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixClient.js +1 -1
  84. package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixCreator.js +45 -5
  85. package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +2 -2
  86. package/dist/components/questions/types/label-the-picture/LabelThePictureCreator.js +18 -14
  87. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +2 -2
  88. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupCreator.js +30 -30
  89. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneClient.js +2 -2
  90. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneCreator.js +24 -31
  91. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneClient.js +2 -2
  92. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneCreator.js +29 -32
  93. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +1 -1
  94. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerCreator.js +27 -29
  95. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +1 -1
  96. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesCreator.js +11 -15
  97. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +1 -1
  98. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupCreator.js +22 -24
  99. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +1 -1
  100. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeCreator.js +17 -24
  101. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +1 -1
  102. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutCreator.js +31 -31
  103. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +1 -1
  104. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListCreator.js +11 -15
  105. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +1 -1
  106. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesCreator.js +14 -15
  107. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +2 -2
  108. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerCreator.js +27 -25
  109. package/dist/components/questions/types/match-columns-to-make-sentences/MatchColumnsToMakeSentencesClient.js +12 -12
  110. package/dist/components/questions/types/match-columns-to-make-sentences/MatchColumnsToMakeSentencesCreator.js +8 -5
  111. package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureClient.js +8 -8
  112. package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureCreator.js +25 -20
  113. package/dist/components/questions/types/match-word-to-picture-group/MatchWordToPictureGroupClient.js +1 -1
  114. package/dist/components/questions/types/match-word-to-picture-group/MatchWordToPictureGroupCreator.js +13 -10
  115. package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesGroupCreator.js +8 -5
  116. package/dist/components/questions/types/read-displayed-content/ReadDisplayedContentCreator.js +7 -11
  117. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +1 -1
  118. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsCreator.js +15 -12
  119. package/dist/components/questions/types/sort-words-into-categories/SortWordsIntoCategoriesClient.js +1 -1
  120. package/dist/components/questions/types/sort-words-into-categories/SortWordsIntoCategoriesCreator.js +5 -5
  121. package/dist/components/questions/types/speaking-conversation/SpeakingConversationCreator.js +35 -39
  122. package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +2 -2
  123. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardClient.js +1 -1
  124. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +7 -8
  125. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +1 -1
  126. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageCreator.js +30 -23
  127. package/dist/components/questions/types/spontaneous-qa/SpontaneousQAClient.js +1 -1
  128. package/dist/components/questions/types/spontaneous-qa/SpontaneousQACreator.js +26 -19
  129. package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupClient.d.ts +1 -1
  130. package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupClient.js +79 -3
  131. package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupCreator.js +13 -11
  132. package/dist/components/questions/types/spontaneous-qa-group/index.d.ts +1 -0
  133. package/dist/components/questions/types/spontaneous-qa-group/index.js +1 -0
  134. package/dist/components/questions/types/spontaneous-qa-group/map-spontaneous-qa-group-data.d.ts +2 -0
  135. package/dist/components/questions/types/spontaneous-qa-group/map-spontaneous-qa-group-data.js +74 -0
  136. package/dist/components/questions/types/true-false/TrueFalseClient.js +2 -2
  137. package/dist/components/questions/types/true-false/TrueFalseCreator.js +35 -29
  138. package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupClient.js +1 -1
  139. package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupCreator.js +11 -7
  140. package/dist/components/questions/types/true-false-group/TrueFalseGroupClient.js +1 -1
  141. package/dist/components/questions/types/true-false-group/TrueFalseGroupCreator.js +11 -7
  142. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +2 -2
  143. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphCreator.js +21 -56
  144. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -1
  145. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +30 -24
  146. package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupClient.js +3 -3
  147. package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupCreator.js +12 -14
  148. package/dist/components/questions/types/word-ordering/WordOrderingClient.js +1 -1
  149. package/dist/components/questions/types/word-ordering/WordOrderingCreator.js +27 -18
  150. package/dist/components/questions/types/word-ordering-group/WordOrderingGroupClient.js +7 -7
  151. package/dist/components/questions/types/word-ordering-group/WordOrderingGroupCreator.js +16 -13
  152. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +2 -2
  153. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +34 -28
  154. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +2 -2
  155. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js +22 -22
  156. package/dist/components/questions/types/write-sentences/WriteSentencesCreator.js +21 -18
  157. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphClient.js +1 -1
  158. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphCreator.js +7 -4
  159. package/dist/components/questions/viewer/QuestionViewer.js +0 -98
  160. package/dist/components/questions/viewer/SpontaneousQaGroupViewer.js +4 -79
  161. package/dist/components/results/renderers/review-question-body-movers.js +2 -26
  162. package/dist/components/results/review-data.js +0 -4
  163. package/dist/components/ui/points-input.d.ts +1 -0
  164. package/dist/components/ui/points-input.js +12 -2
  165. package/dist/shared/constants/question-skills.js +0 -11
  166. package/dist/shared/lib/i18n/messages/en/admin.d.ts +0 -3
  167. package/dist/shared/lib/i18n/messages/en/admin.js +0 -3
  168. package/dist/shared/lib/i18n/messages/en.d.ts +0 -3
  169. package/dist/shared/lib/i18n/messages/vi/admin.d.ts +0 -3
  170. package/dist/shared/lib/i18n/messages/vi/admin.js +0 -3
  171. package/dist/shared/lib/i18n/messages/vi.d.ts +0 -3
  172. package/dist/shared/lib/utils/question-reverse-transform.js +4 -23
  173. package/dist/shared/lib/utils/question-transform-types.d.ts +1 -23
  174. package/dist/shared/lib/utils/question-transform-validation.js +0 -40
  175. package/dist/shared/lib/utils/question-transform.js +0 -9
  176. package/dist/shared/types/common.types.d.ts +1 -1
  177. package/dist/shared/types/entities/question.types.d.ts +1 -11
  178. package/dist/shared/types/questions/choose-the-correct-answer-group.d.ts +1 -1
  179. package/dist/shared/types/questions/index.d.ts +0 -3
  180. package/dist/shared/types/questions/index.js +0 -6
  181. package/package.json +1 -1
  182. package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.d.ts +0 -2
  183. package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.js +0 -131
  184. package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.d.ts +0 -2
  185. package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.js +0 -76
  186. package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.d.ts +0 -2
  187. package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.js +0 -68
  188. package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.d.ts +0 -16
  189. package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.js +0 -212
  190. package/dist/components/questions/_shared/types/gn-speaking-interview.type.d.ts +0 -32
  191. package/dist/components/questions/_shared/types/gn-speaking-interview.type.js +0 -1
  192. package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.d.ts +0 -47
  193. package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.js +0 -1
  194. package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.d.ts +0 -2
  195. package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.js +0 -262
  196. package/dist/components/questions/types/gn-speaking-interview/register.d.ts +0 -2
  197. package/dist/components/questions/types/gn-speaking-interview/register.js +0 -121
  198. package/dist/components/questions/types/gn-speaking-interview/transform.d.ts +0 -2
  199. package/dist/components/questions/types/gn-speaking-interview/transform.js +0 -48
  200. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.d.ts +0 -20
  201. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.js +0 -72
  202. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.d.ts +0 -15
  203. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.js +0 -230
  204. package/dist/components/questions/types/look-picture-choose-correct-answer/index.d.ts +0 -1
  205. package/dist/components/questions/types/look-picture-choose-correct-answer/index.js +0 -1
  206. package/dist/components/questions/types/look-picture-choose-correct-answer/register.d.ts +0 -2
  207. package/dist/components/questions/types/look-picture-choose-correct-answer/register.js +0 -66
  208. package/dist/components/questions/types/look-picture-choose-correct-answer/transform.d.ts +0 -2
  209. package/dist/components/questions/types/look-picture-choose-correct-answer/transform.js +0 -42
  210. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.d.ts +0 -6
  211. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.js +0 -96
  212. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.d.ts +0 -15
  213. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.js +0 -238
  214. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.d.ts +0 -2
  215. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.js +0 -2
  216. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.d.ts +0 -2
  217. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.js +0 -76
  218. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.d.ts +0 -2
  219. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.js +0 -19
  220. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.d.ts +0 -7
  221. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.js +0 -134
  222. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.d.ts +0 -3
  223. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.js +0 -617
  224. package/dist/components/questions/types/look-picture-fill-word-hint/index.d.ts +0 -2
  225. package/dist/components/questions/types/look-picture-fill-word-hint/index.js +0 -2
  226. package/dist/components/questions/types/look-picture-fill-word-hint/register.d.ts +0 -2
  227. package/dist/components/questions/types/look-picture-fill-word-hint/register.js +0 -82
  228. package/dist/components/questions/types/look-picture-fill-word-hint/transform.d.ts +0 -2
  229. package/dist/components/questions/types/look-picture-fill-word-hint/transform.js +0 -29
  230. package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.d.ts +0 -9
  231. package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.js +0 -12
  232. package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.d.ts +0 -17
  233. package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.js +0 -47
  234. package/dist/shared/types/questions/look-picture-choose-correct-answer.d.ts +0 -38
  235. package/dist/shared/types/questions/look-picture-choose-correct-answer.js +0 -5
  236. package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.d.ts +0 -63
  237. package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.js +0 -9
  238. package/dist/shared/types/questions/look-picture-fill-word-hint.d.ts +0 -57
  239. package/dist/shared/types/questions/look-picture-fill-word-hint.js +0 -7
@@ -20,8 +20,8 @@ export function CrossOutWordGroupClient({ questionData, isReviewMode = false, us
20
20
  return (_jsxs("div", { className: "space-y-4", children: [questionData.instruction && (_jsx("div", { className: "rounded-xl border border-indigo-100 bg-indigo-50 px-4 py-3 text-sm font-medium text-indigo-800", children: questionData.instruction })), items.map((item, itemIndex) => {
21
21
  const userValue = userAnswers[itemIndex];
22
22
  const isReplace = item.type === 'CROSS_OUT_AND_REPLACE';
23
- return (_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-gray-50 to-white px-4 py-2.5", 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-gradient-to-br from-blue-500 to-indigo-600 text-white", children: _jsx(CircleHelp, { className: "h-3.5 w-3.5" }) }), _jsxs("span", { className: "text-sm font-medium text-gray-700", children: ["C\u00E2u ", item.questionNumber || itemIndex + 1] }), item.isExample && (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-amber-100 px-2 py-0.5 text-xs font-semibold text-amber-700", children: [_jsx(Star, { className: "h-3 w-3" }), "Example"] })), _jsx("span", { className: cn('rounded-full px-2 py-0.5 text-xs font-semibold', isReplace
23
+ return (_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-gray-50 to-white px-3 py-2", 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-gradient-to-br from-blue-500 to-indigo-600 text-white", children: _jsx(CircleHelp, { className: "h-3.5 w-3.5" }) }), _jsxs("span", { className: "text-sm font-medium text-gray-700", children: ["C\u00E2u ", item.questionNumber || itemIndex + 1] }), item.isExample && (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-amber-100 px-2 py-0.5 text-xs font-semibold text-amber-700", children: [_jsx(Star, { className: "h-3 w-3" }), "Example"] })), _jsx("span", { className: cn('rounded-full px-2 py-0.5 text-xs font-semibold', isReplace
24
24
  ? 'bg-violet-100 text-violet-700'
25
- : 'bg-sky-100 text-sky-700'), children: isReplace ? 'Gạch + thay' : 'Chỉ gạch' })] }), _jsxs("span", { className: "text-xs text-gray-500", children: [item.points || 0, " \u0111i\u1EC3m"] })] }), _jsxs("div", { className: "space-y-3 p-4", children: [_jsx("p", { className: "text-sm font-semibold leading-relaxed text-gray-800", children: item.question || 'Câu hỏi chưa được nhập' }), _jsxs("div", { className: "rounded-lg border border-gray-100 bg-gray-50 px-3 py-2 text-sm text-gray-700", children: [_jsx("span", { className: "font-medium text-gray-500", children: "\u0110\u00E1p \u00E1n: " }), formatAnswer(item.correctAnswer)] }), isReviewMode && (_jsxs("div", { className: "rounded-lg border border-blue-100 bg-blue-50 px-3 py-2 text-sm text-blue-800", children: [_jsx("span", { className: "font-medium", children: "H\u1ECDc sinh: " }), formatAnswer(userValue)] }))] })] }, `${item.questionNumber}-${itemIndex}`));
25
+ : 'bg-sky-100 text-sky-700'), children: isReplace ? 'Gạch + thay' : 'Chỉ gạch' })] }), _jsxs("span", { className: "text-xs text-gray-500", children: [item.points || 0, " \u0111i\u1EC3m"] })] }), _jsxs("div", { className: "space-y-3 p-3", children: [_jsx("p", { className: "text-sm font-semibold leading-relaxed text-gray-800", children: item.question || 'Câu hỏi chưa được nhập' }), _jsxs("div", { className: "rounded-lg border border-gray-100 bg-gray-50 px-3 py-2 text-sm text-gray-700", children: [_jsx("span", { className: "font-medium text-gray-500", children: "\u0110\u00E1p \u00E1n: " }), formatAnswer(item.correctAnswer)] }), isReviewMode && (_jsxs("div", { className: "rounded-lg border border-blue-100 bg-blue-50 px-3 py-2 text-sm text-blue-800", children: [_jsx("span", { className: "font-medium", children: "H\u1ECDc sinh: " }), formatAnswer(userValue)] }))] })] }, `${item.questionNumber}-${itemIndex}`));
26
26
  }), 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] }))] }));
27
27
  }
@@ -10,7 +10,8 @@ import { Card, CardContent, CardHeader, CardTitle } from '../../../../components
10
10
  import { Switch } from '../../../../components/ui/switch';
11
11
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../../../components/ui/select';
12
12
  import { useDebouncedCallback } from '../../../../shared/lib/hooks';
13
- import { Eye, Pencil, Plus, Star, Trash2 } from 'lucide-react';
13
+ import { HelpCircle, Plus, Star, Trash2 } from 'lucide-react';
14
+ import { CompactCreatorHeader, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, } from '../../_shared/components/compact';
14
15
  import { CrossOutWordGroupClient } from './CrossOutWordGroupClient';
15
16
  function parsePointsValue(raw, allowZero = false) {
16
17
  if (raw === '')
@@ -213,19 +214,22 @@ export function CrossOutWordGroupCreator({ initialData, onChange, externalErrors
213
214
  };
214
215
  const currentPayload = buildPayload();
215
216
  const displayErrors = externalErrors && externalErrors.length > 0 ? externalErrors : errors;
216
- return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-lg font-medium text-gray-900", children: "T\u1EA1o c\u00E2u h\u1ECFi G\u1EA1ch t\u1EEB / S\u1EEDa t\u1EEB (Nh\u00F3m)" }), _jsx("p", { className: "text-sm text-gray-500", children: "Mix 2 d\u1EA1ng: ch\u1EC9 g\u1EA1ch t\u1EEB th\u1EEBa, ho\u1EB7c g\u1EA1ch t\u1EEB sai r\u1ED3i thay b\u1EB1ng t\u1EEB \u0111\u00FAng. Click v\u00E0o t\u1EEB trong c\u00E2u \u0111\u1EC3 g\u00E1n v\u1ECB tr\u00ED (wordIndex) ch\u00EDnh x\u00E1c." })] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setIsClientMode((prev) => !prev), className: "gap-2", children: [isClientMode ? _jsx(Pencil, { className: "h-4 w-4" }) : _jsx(Eye, { className: "h-4 w-4" }), isClientMode ? 'Chế độ chỉnh sửa' : 'Xem trước học sinh'] })] }), displayErrors.length > 0 && (_jsxs("div", { className: "rounded-lg border border-red-200 bg-red-50 p-4", children: [_jsx("h3", { className: "text-sm font-medium text-red-800", children: "C\u1EA7n s\u1EEDa c\u00E1c l\u1ED7i sau:" }), _jsx("ul", { className: "mt-2 list-disc space-y-1 pl-5 text-sm text-red-700", children: displayErrors.map((err, i) => (_jsx("li", { children: err }, i))) })] })), isClientMode ? (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { className: "text-base font-semibold", children: "Xem tr\u01B0\u1EDBc hi\u1EC3n th\u1ECB h\u1ECDc sinh" }) }), _jsx(CardContent, { children: _jsx(CrossOutWordGroupClient, { questionData: currentPayload }) })] })) : (_jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { className: "text-base font-semibold", children: "H\u01B0\u1EDBng d\u1EABn chung (Instruction)" }) }), _jsxs(CardContent, { children: [_jsx(Label, { htmlFor: "instruction", children: "H\u01B0\u1EDBng d\u1EABn b\u00E0i l\u00E0m" }), _jsx(Input, { id: "instruction", value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: DEFAULT_INSTRUCTION, className: "mt-1" })] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between", children: [_jsxs(CardTitle, { className: "text-base font-semibold", children: ["Danh s\u00E1ch c\u00E2u (", items.length, ")"] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: addItem, className: "gap-2", children: [_jsx(Plus, { className: "h-4 w-4" }), "Th\u00EAm c\u00E2u"] })] }), _jsx(CardContent, { className: "space-y-4", children: items.map((item, index) => {
217
- const tokens = tokenize(item.question);
218
- const selectedWordIndex = item.correctAnswer.wordIndex;
219
- return (_jsxs("div", { className: "space-y-4 rounded-lg border border-gray-200 bg-gray-50/50 p-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "flex h-7 w-7 items-center justify-center rounded-full bg-blue-100 text-xs font-semibold text-blue-700", children: item.questionNumber || index + 1 }), _jsxs("span", { className: "text-sm font-medium text-gray-700", children: ["C\u00E2u ", index + 1] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-4", children: [_jsx("div", { className: "w-52", children: _jsxs(Select, { value: item.type, onValueChange: (value) => updateItemType(index, value), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Lo\u1EA1i c\u00E2u" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "CROSS_OUT", children: "Ch\u1EC9 g\u1EA1ch (CROSS_OUT)" }), _jsx(SelectItem, { value: "CROSS_OUT_AND_REPLACE", children: "G\u1EA1ch + thay (CROSS_OUT_AND_REPLACE)" })] })] }) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Switch, { id: `example-${index}`, checked: item.isExample || false, onCheckedChange: (checked) => updateItem(index, {
220
- isExample: checked,
221
- points: checked ? 0 : 1,
222
- }) }), _jsxs(Label, { htmlFor: `example-${index}`, className: "flex cursor-pointer items-center gap-1 text-xs", children: [_jsx(Star, { className: "h-3 w-3 text-amber-500" }), "Example"] })] }), !item.isExample && (_jsx("div", { className: "w-24", children: _jsx(PointsInput, { value: item.points, allowZero: true, onChange: (event) => updateItem(index, {
223
- points: parsePointsValue(event.target.value, true),
224
- }) }) })), items.length > 1 && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => removeItem(index), className: "text-red-500 hover:bg-red-50 hover:text-red-600", children: _jsx(Trash2, { className: "h-4 w-4" }) }))] })] }), _jsxs("div", { children: [_jsx(Label, { htmlFor: `question-${index}`, children: "N\u1ED9i dung c\u00E2u" }), _jsx(Textarea, { id: `question-${index}`, value: item.question, onChange: (e) => updateItem(index, { question: e.target.value }), placeholder: "Nh\u1EADp c\u00E2u g\u1ED1c...", className: "mt-1 bg-white", rows: 2 })] }), tokens.length > 0 && (_jsxs("div", { className: "rounded-lg border border-slate-200 bg-white p-3 space-y-1.5", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { className: "text-xs font-semibold text-slate-700", children: "Click t\u1EEB c\u1EA7n g\u1EA1ch trong c\u00E2u (t\u1EF1 \u0111\u1ED9ng g\u00E1n wordIndex):" }), typeof selectedWordIndex === 'number' && (_jsxs("span", { className: "text-[11px] font-bold text-rose-600", children: ["\u0110\u00E3 ch\u1ECDn token #", selectedWordIndex + 1, ": \"", tokens[selectedWordIndex], "\""] }))] }), _jsx("div", { className: "flex flex-wrap gap-1.5 pt-1", children: tokens.map((token, tokenIdx) => {
225
- const isSelected = selectedWordIndex === tokenIdx;
226
- return (_jsx("button", { type: "button", onClick: () => toggleSelectToken(index, tokenIdx, token), className: `rounded-md px-2 py-1 text-xs font-medium transition-all ${isSelected
227
- ? 'bg-rose-500 text-white font-bold line-through shadow-sm scale-105'
228
- : 'bg-slate-100 text-slate-700 hover:bg-blue-100 hover:text-blue-700'}`, children: token }, tokenIdx));
229
- }) })] })), _jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs("div", { children: [_jsxs(Label, { htmlFor: `crossout-${index}`, children: ["T\u1EEB c\u1EA7n g\u1EA1ch (crossOut)", item.type === 'CROSS_OUT' && (_jsx("span", { className: "ml-1 text-xs font-normal text-gray-500", children: "\u2014 \u0111\u1EC3 tr\u1ED1ng n\u1EBFu c\u00E2u \u0111\u00FAng" }))] }), _jsxs("div", { className: "flex gap-2 items-center mt-1", children: [_jsx(Input, { id: `crossout-${index}`, value: item.correctAnswer.crossOut, onChange: (e) => updateItemAnswer(index, { crossOut: e.target.value }), placeholder: item.type === 'CROSS_OUT' ? 'VD: to (hoặc trống)' : 'VD: have', className: "bg-white" }), typeof selectedWordIndex === 'number' && (_jsxs("span", { className: "whitespace-nowrap rounded bg-slate-100 px-2 py-1 text-xs text-slate-600 font-mono", children: ["idx: ", selectedWordIndex] }))] })] }), item.type === 'CROSS_OUT_AND_REPLACE' && (_jsxs("div", { children: [_jsx(Label, { htmlFor: `replace-${index}`, children: "T\u1EEB thay th\u1EBF (replaceWith)" }), _jsx(Input, { id: `replace-${index}`, value: item.correctAnswer.replaceWith || '', onChange: (e) => updateItemAnswer(index, { replaceWith: e.target.value }), placeholder: "VD: has", className: "mt-1 bg-white" })] }))] })] }, index));
230
- }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { className: "text-base", children: "Gi\u1EA3i th\u00EDch" }) }), _jsx(CardContent, { children: _jsx(Textarea, { id: "explanation", value: explanation, onChange: (event) => setExplanation(event.target.value), placeholder: "VD: C\u00E2u tr\u1EA3 l\u1EDDi \u0111\u00FAng l\u00E0... v\u00EC...", rows: 3 }) })] })] }))] }));
217
+ if (isClientMode) {
218
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(CompactPreviewBanner, { onBack: () => setIsClientMode(false) }), _jsx(CrossOutWordGroupClient, { questionData: currentPayload })] }));
219
+ }
220
+ return (_jsxs("div", { className: "space-y-3", children: [displayErrors.length > 0 && (_jsx("div", { className: "rounded-md border border-red-200 bg-red-50 p-2 text-xs text-red-700", children: _jsx("ul", { className: "list-disc space-y-1 pl-4", children: displayErrors.map((err, i) => (_jsx("li", { children: err }, i))) }) })), _jsx(CompactFieldCard, { header: _jsx(CompactCreatorHeader, { icon: _jsx(HelpCircle, { className: "h-3.5 w-3.5" }), title: "G\u1EA1ch t\u1EEB / S\u1EEDa t\u1EEB (Nh\u00F3m)", preview: { onClick: () => setIsClientMode(true) } }), children: _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "instruction", className: "text-sm font-semibold text-gray-800", children: "H\u01B0\u1EDBng d\u1EABn b\u00E0i l\u00E0m" }), _jsx(Input, { id: "instruction", value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: DEFAULT_INSTRUCTION, className: "h-10 border-gray-200 bg-white" })] }) }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-sm", children: [_jsx(CardHeader, { className: "px-3 py-2", children: _jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs(CardTitle, { className: "text-sm font-semibold text-gray-800", children: ["Danh s\u00E1ch c\u00E2u (", items.length, ")"] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: addItem, className: "h-8 gap-1.5 px-2.5 text-xs", children: [_jsx(Plus, { className: "h-3.5 w-3.5" }), "Th\u00EAm c\u00E2u"] })] }) }), _jsxs(CardContent, { className: "space-y-2.5 px-3 pb-3", children: [items.map((item, index) => {
221
+ const tokens = tokenize(item.question);
222
+ const selectedWordIndex = item.correctAnswer.wordIndex;
223
+ return (_jsxs("div", { className: "space-y-2.5 rounded-md border border-gray-200 bg-white px-3 py-2.5", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "flex h-7 w-7 items-center justify-center rounded-full bg-blue-100 text-xs font-semibold text-blue-700", children: item.questionNumber || index + 1 }), _jsxs("span", { className: "text-sm font-medium text-gray-700", children: ["C\u00E2u ", index + 1] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("div", { className: "w-52", children: _jsxs(Select, { value: item.type, onValueChange: (value) => updateItemType(index, value), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Lo\u1EA1i c\u00E2u" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "CROSS_OUT", children: "Ch\u1EC9 g\u1EA1ch (CROSS_OUT)" }), _jsx(SelectItem, { value: "CROSS_OUT_AND_REPLACE", children: "G\u1EA1ch + thay (CROSS_OUT_AND_REPLACE)" })] })] }) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Switch, { id: `example-${index}`, checked: item.isExample || false, onCheckedChange: (checked) => updateItem(index, {
224
+ isExample: checked,
225
+ points: checked ? 0 : 1,
226
+ }) }), _jsxs(Label, { htmlFor: `example-${index}`, className: "flex cursor-pointer items-center gap-1 text-xs", children: [_jsx(Star, { className: "h-3 w-3 text-amber-500" }), "Example"] })] }), !item.isExample && (_jsx("div", { className: "w-24", children: _jsx(PointsInput, { value: item.points, allowZero: true, onChange: (event) => updateItem(index, {
227
+ points: parsePointsValue(event.target.value, true),
228
+ }) }) })), items.length > 1 && (_jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => removeItem(index), className: "h-7 w-7 text-red-500 hover:bg-red-50 hover:text-red-600", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }))] })] }), _jsxs("div", { children: [_jsx(Label, { htmlFor: `question-${index}`, children: "N\u1ED9i dung c\u00E2u" }), _jsx(Textarea, { id: `question-${index}`, value: item.question, onChange: (e) => updateItem(index, { question: e.target.value }), placeholder: "Nh\u1EADp c\u00E2u g\u1ED1c...", className: "mt-1 bg-white", rows: 2 })] }), tokens.length > 0 && (_jsxs("div", { className: "rounded-lg border border-slate-200 bg-white p-3 space-y-1.5", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { className: "text-xs font-semibold text-slate-700", children: "Click t\u1EEB c\u1EA7n g\u1EA1ch trong c\u00E2u (t\u1EF1 \u0111\u1ED9ng g\u00E1n wordIndex):" }), typeof selectedWordIndex === 'number' && (_jsxs("span", { className: "text-[11px] font-bold text-rose-600", children: ["\u0110\u00E3 ch\u1ECDn token #", selectedWordIndex + 1, ": \"", tokens[selectedWordIndex], "\""] }))] }), _jsx("div", { className: "flex flex-wrap gap-1.5 pt-1", children: tokens.map((token, tokenIdx) => {
229
+ const isSelected = selectedWordIndex === tokenIdx;
230
+ return (_jsx("button", { type: "button", onClick: () => toggleSelectToken(index, tokenIdx, token), className: `rounded-md px-2 py-1 text-xs font-medium transition-all ${isSelected
231
+ ? 'bg-rose-500 text-white font-bold line-through shadow-sm scale-105'
232
+ : 'bg-slate-100 text-slate-700 hover:bg-blue-100 hover:text-blue-700'}`, children: token }, tokenIdx));
233
+ }) })] })), _jsxs("div", { className: "grid gap-2.5 md:grid-cols-2", children: [_jsxs("div", { children: [_jsxs(Label, { htmlFor: `crossout-${index}`, children: ["T\u1EEB c\u1EA7n g\u1EA1ch (crossOut)", item.type === 'CROSS_OUT' && (_jsx("span", { className: "ml-1 text-xs font-normal text-gray-500", children: "\u2014 \u0111\u1EC3 tr\u1ED1ng n\u1EBFu c\u00E2u \u0111\u00FAng" }))] }), _jsxs("div", { className: "flex gap-2 items-center mt-1", children: [_jsx(Input, { id: `crossout-${index}`, value: item.correctAnswer.crossOut, onChange: (e) => updateItemAnswer(index, { crossOut: e.target.value }), placeholder: item.type === 'CROSS_OUT' ? 'VD: to (hoặc trống)' : 'VD: have', className: "bg-white" }), typeof selectedWordIndex === 'number' && (_jsxs("span", { className: "whitespace-nowrap rounded bg-slate-100 px-2 py-1 text-xs text-slate-600 font-mono", children: ["idx: ", selectedWordIndex] }))] })] }), item.type === 'CROSS_OUT_AND_REPLACE' && (_jsxs("div", { children: [_jsx(Label, { htmlFor: `replace-${index}`, children: "T\u1EEB thay th\u1EBF (replaceWith)" }), _jsx(Input, { id: `replace-${index}`, value: item.correctAnswer.replaceWith || '', onChange: (e) => updateItemAnswer(index, { replaceWith: e.target.value }), placeholder: "VD: has", className: "mt-1 bg-white" })] }))] })] }, index));
234
+ }), _jsx(CompactExplanationToggle, { value: explanation, onValueChange: setExplanation, defaultVisible: Boolean(initialData?.explanation) })] })] })] }));
231
235
  }
@@ -30,7 +30,7 @@ export function CrosswordPuzzleClient({ content, correctAnswer, isReviewMode = f
30
30
  }
31
31
  return { cellMap: cMap, clueNumberMap: numMap };
32
32
  }, [acrossClues, downClues]);
33
- return (_jsxs("div", { className: "flex flex-col gap-6 p-4 bg-white rounded-xl border border-gray-200", children: [content?.title && (_jsx("h3", { className: "text-lg font-bold text-gray-800 text-center", children: content.title })), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-12 gap-6 items-start", children: [_jsxs("div", { className: "lg:col-span-5 flex flex-col gap-4", children: [_jsxs("div", { className: "rounded-lg border border-blue-200 bg-blue-50/50 p-4", children: [_jsxs("h4", { className: "font-bold text-blue-900 mb-2.5 flex items-center gap-2", children: [_jsx("span", { className: "px-2 py-0.5 rounded bg-blue-600 text-white text-xs font-semibold", children: "Across" }), _jsx("span", { children: "H\u00E0ng ngang" })] }), _jsx("div", { className: "flex flex-col gap-2 max-h-60 overflow-y-auto pr-1", children: acrossClues.map((c) => {
33
+ return (_jsxs("div", { className: "flex flex-col gap-3 p-3 bg-white rounded-xl border border-gray-200 shadow-sm", children: [content?.title && (_jsx("h3", { className: "text-lg font-bold text-gray-800 text-center", children: content.title })), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-12 gap-6 items-start", children: [_jsxs("div", { className: "lg:col-span-5 flex flex-col gap-4", children: [_jsxs("div", { className: "rounded-lg border border-blue-200 bg-blue-50/50 p-4", children: [_jsxs("h4", { className: "font-bold text-blue-900 mb-2.5 flex items-center gap-2", children: [_jsx("span", { className: "px-2 py-0.5 rounded bg-blue-600 text-white text-xs font-semibold", children: "Across" }), _jsx("span", { children: "H\u00E0ng ngang" })] }), _jsx("div", { className: "flex flex-col gap-2 max-h-60 overflow-y-auto pr-1", children: acrossClues.map((c) => {
34
34
  const answer = correctAnswer?.answers?.[`across-${c.number}`];
35
35
  const userAns = userAnswers[`across-${c.number}`];
36
36
  return (_jsxs("div", { className: "flex items-start gap-2 text-sm bg-white p-2 rounded border border-blue-100", children: [_jsxs("span", { className: "font-bold text-blue-700 min-w-[20px]", children: [c.number, "."] }), _jsxs("div", { className: "flex-1", children: [_jsx("span", { className: "text-gray-800", children: c.clue }), isReviewMode && answer && (_jsxs("div", { className: "text-xs mt-1", children: [_jsx("span", { className: "text-gray-500", children: "\u0110\u00E1p \u00E1n: " }), _jsx("span", { className: "font-bold text-green-700", children: answer }), userAns && userAns !== answer && (_jsx("span", { className: "ml-2 line-through text-red-500 font-semibold", children: userAns }))] }))] }), _jsxs("span", { className: "text-xs text-gray-400", children: ["(", c.length, " ch\u1EEF)"] })] }, `across-${c.number}`));
@@ -1,7 +1,9 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useMemo } from 'react';
4
- import { Plus, Trash2, Edit2, Check, AlertCircle } from 'lucide-react';
4
+ import { Plus, Trash2, Edit2, Check, AlertCircle, Grid3X3 } from 'lucide-react';
5
+ import { CompactCreatorHeader, CompactFieldCard, CompactPreviewBanner, } from '../../_shared/components/compact';
6
+ import { CrosswordPuzzleClient } from './CrosswordPuzzleClient';
5
7
  export function CrosswordPuzzleCreator({ initialData, onChange, onUnsavedChangesChange, }) {
6
8
  const [title, setTitle] = useState(() => {
7
9
  return initialData?.content?.title || 'Nationalities Crossword';
@@ -18,6 +20,7 @@ export function CrosswordPuzzleCreator({ initialData, onChange, onUnsavedChanges
18
20
  const [points, setPoints] = useState(() => {
19
21
  return initialData?.points ?? 11;
20
22
  });
23
+ const [isClientMode, setIsClientMode] = useState(false);
21
24
  const [clues, setClues] = useState(() => {
22
25
  if (Array.isArray(initialData?.content?.clues)) {
23
26
  return initialData.content.clues;
@@ -182,32 +185,66 @@ export function CrosswordPuzzleCreator({ initialData, onChange, onUnsavedChanges
182
185
  setFormAnswer('');
183
186
  }
184
187
  };
185
- return (_jsxs("div", { className: "flex flex-col gap-6 p-4 bg-white rounded-xl border border-gray-200", children: [_jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4 p-4 bg-gray-50 rounded-lg border border-gray-200", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-xs font-bold text-gray-700 mb-1", children: "Ti\u00EAu \u0111\u1EC1 \u00F4 ch\u1EEF" }), _jsx("input", { type: "text", value: title, onChange: (e) => setTitle(e.target.value), placeholder: "vd: Nationalities Crossword", className: "w-full px-3 py-1.5 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 outline-none" })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-xs font-bold text-gray-700 mb-1", children: "K\u00EDch th\u01B0\u1EDBc l\u01B0\u1EDBi (H\u00E0ng x C\u1ED9t)" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "number", min: 3, max: 30, value: rows, onChange: (e) => setRows(Math.max(3, parseInt(e.target.value) || 12)), className: "w-20 px-2 py-1.5 text-sm border border-gray-300 rounded outline-none" }), _jsx("span", { className: "text-gray-500 font-bold", children: "x" }), _jsx("input", { type: "number", min: 3, max: 30, value: cols, onChange: (e) => setCols(Math.max(3, parseInt(e.target.value) || 12)), className: "w-20 px-2 py-1.5 text-sm border border-gray-300 rounded outline-none" })] })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-xs font-bold text-gray-700 mb-1", children: "\u0110i\u1EC3m s\u1ED1" }), _jsx("input", { type: "number", min: 0, step: 0.5, value: points, onChange: (e) => setPoints(parseFloat(e.target.value) || 1), className: "w-full px-3 py-1.5 text-sm border border-gray-300 rounded outline-none" })] }), _jsx("div", { className: "flex items-center pt-5", children: _jsxs("label", { className: "flex items-center gap-2 text-sm text-gray-700 cursor-pointer", children: [_jsx("input", { type: "checkbox", checked: caseSensitive, onChange: (e) => setCaseSensitive(e.target.checked), className: "rounded text-blue-600 focus:ring-blue-500 h-4 w-4" }), _jsx("span", { children: "Ph\u00E2n bi\u1EC7t hoa/th\u01B0\u1EDDng" })] }) })] }), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-12 gap-6", children: [_jsxs("div", { className: "lg:col-span-5 flex flex-col gap-4", children: [_jsxs("form", { onSubmit: handleSaveClue, className: "p-4 rounded-xl border border-blue-200 bg-blue-50/40 flex flex-col gap-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-bold text-blue-900", children: editingClueId ? 'Chỉnh sửa gợi ý' : 'Thêm gợi ý mới' }), editingClueId && (_jsx("button", { type: "button", onClick: () => {
186
- setEditingClueId(null);
187
- setFormClue('');
188
- setFormAnswer('');
189
- }, className: "text-xs text-gray-500 hover:text-gray-700 underline", children: "H\u1EE7y ch\u1EC9nh s\u1EEDa" }))] }), _jsxs("div", { className: "grid grid-cols-3 gap-2", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-[11px] font-semibold text-gray-600 mb-0.5", children: "S\u1ED1 Clue" }), _jsx("input", { type: "number", min: 1, value: formNumber, onChange: (e) => setFormNumber(parseInt(e.target.value) || 1), className: "w-full px-2 py-1 text-sm border border-gray-300 rounded outline-none" })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[11px] font-semibold text-gray-600 mb-0.5", children: "H\u01B0\u1EDBng" }), _jsxs("select", { value: formDirection, onChange: (e) => setFormDirection(e.target.value), className: "w-full px-2 py-1 text-sm border border-gray-300 rounded outline-none bg-white", children: [_jsx("option", { value: "across", children: "Across (Ngang)" }), _jsx("option", { value: "down", children: "Down (D\u1ECDc)" })] })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[11px] font-semibold text-gray-600 mb-0.5", children: "To\u1EA1 \u0111\u1ED9 (R, C)" }), _jsxs("div", { className: "flex gap-1", children: [_jsx("input", { type: "number", min: 1, max: rows, value: formStartRow, onChange: (e) => setFormStartRow(parseInt(e.target.value) || 1), placeholder: "R", className: "w-1/2 px-1 py-1 text-xs border border-gray-300 rounded text-center" }), _jsx("input", { type: "number", min: 1, max: cols, value: formStartCol, onChange: (e) => setFormStartCol(parseInt(e.target.value) || 1), placeholder: "C", className: "w-1/2 px-1 py-1 text-xs border border-gray-300 rounded text-center" })] })] })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[11px] font-semibold text-gray-600 mb-0.5", children: "C\u00E2u g\u1EE3i \u00FD (Clue)" }), _jsx("input", { type: "text", value: formClue, onChange: (e) => setFormClue(e.target.value), placeholder: "vd: Spain, Capital of France...", className: "w-full px-3 py-1.5 text-sm border border-gray-300 rounded outline-none", required: true })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[11px] font-semibold text-gray-600 mb-0.5", children: "T\u1EEB \u0111\u00E1p \u00E1n (Answer Word)" }), _jsx("input", { type: "text", value: formAnswer, onChange: (e) => setFormAnswer(e.target.value), placeholder: "vd: SPANISH", className: "w-full px-3 py-1.5 text-sm border border-gray-300 rounded outline-none uppercase font-semibold", required: true })] }), _jsxs("button", { type: "submit", className: "mt-1 flex items-center justify-center gap-1.5 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded text-sm font-semibold transition", children: [editingClueId ? _jsx(Check, { className: "h-4 w-4" }) : _jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: editingClueId ? 'Cập nhật gợi ý' : 'Thêm vào danh sách' })] })] }), _jsxs("div", { className: "flex flex-col gap-2 max-h-[420px] overflow-y-auto pr-1", children: [_jsxs("span", { className: "text-xs font-bold text-gray-600", children: ["Danh s\u00E1ch (", clues.length, " t\u1EEB):"] }), clues.length === 0 && (_jsx("p", { className: "text-xs text-gray-400 italic", children: "Ch\u01B0a c\u00F3 g\u1EE3i \u00FD n\u00E0o. H\u00E3y th\u00EAm g\u1EE3i \u00FD \u1EDF tr\u00EAn." })), clues.map((c) => (_jsxs("div", { className: "flex items-center justify-between p-2.5 bg-white rounded-lg border border-gray-200 hover:border-blue-300 transition text-sm shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [_jsx("span", { className: `flex items-center justify-center h-6 w-6 rounded text-xs font-bold text-white ${c.direction === 'across' ? 'bg-blue-600' : 'bg-purple-600'}`, children: c.number }), _jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [_jsx("span", { className: "font-semibold text-gray-800 truncate", children: c.clue }), _jsxs("span", { className: "text-xs text-gray-500 flex items-center gap-2", children: [_jsx("span", { className: "font-bold text-blue-700", children: c.answer }), _jsxs("span", { children: ["(", c.length, " ch\u1EEF)"] }), _jsxs("span", { children: ["[", c.direction === 'across' ? '→ Ngang' : '↓ Dọc', " (", c.startRow, ",", c.startCol, ")]"] })] })] })] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { type: "button", onClick: () => handleEditClue(c), className: "p-1 text-gray-500 hover:text-blue-600 rounded", title: "S\u1EEDa", children: _jsx(Edit2, { className: "h-4 w-4" }) }), _jsx("button", { type: "button", onClick: () => handleDeleteClue(c.id), className: "p-1 text-gray-500 hover:text-red-600 rounded", title: "X\u00F3a", children: _jsx(Trash2, { className: "h-4 w-4" }) })] })] }, c.id)))] })] }), _jsxs("div", { className: "lg:col-span-7 flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-bold text-gray-700", children: "Ma tr\u1EADn l\u01B0\u1EDBi \u00F4 ch\u1EEF tr\u1EF1c quan:" }), conflicts.length > 0 && (_jsxs("span", { className: "flex items-center gap-1 text-xs font-bold text-red-600 bg-red-50 px-2 py-0.5 rounded border border-red-200", children: [_jsx(AlertCircle, { className: "h-3.5 w-3.5" }), _jsxs("span", { children: ["C\u00F3 ", conflicts.length, " \u00F4 b\u1ECB xung \u0111\u1ED9t ch\u1EEF c\u00E1i!"] })] }))] }), _jsx("div", { className: "flex justify-center overflow-x-auto p-4 bg-gray-100 rounded-xl border border-gray-300 min-h-[380px]", children: _jsx("div", { className: "inline-grid gap-1", style: {
190
- gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
191
- }, children: Array.from({ length: rows }).map((_, rIdx) => {
192
- const r = rIdx + 1;
193
- return Array.from({ length: cols }).map((_, cIdx) => {
194
- const c = cIdx + 1;
195
- const key = `${r}-${c}`;
196
- const cellEntries = cellMap.get(key);
197
- const clueNums = clueNumberMap.get(key);
198
- const isConflict = conflicts.includes(key);
199
- if (!cellEntries || cellEntries.length === 0) {
200
- return (_jsx("button", { type: "button", onClick: () => {
201
- setFormStartRow(r);
202
- setFormStartCol(c);
203
- }, title: `Ô trống (${r},${c}) - Click để chọn toạ độ bắt đầu`, className: "h-8 w-8 sm:h-9 sm:w-9 md:h-10 md:w-10 bg-transparent hover:bg-gray-200/60 rounded flex items-center justify-center transition text-[10px] text-gray-300 hover:text-gray-500", children: "\u00B7" }, key));
204
- }
205
- const displayLetter = cellEntries[0]?.letter || '';
206
- return (_jsxs("div", { className: `relative flex items-center justify-center rounded border-2 font-bold shadow-sm h-8 w-8 sm:h-9 sm:w-9 md:h-10 md:w-10 text-sm sm:text-base md:text-lg select-none transition ${isConflict
207
- ? 'border-red-500 bg-red-100 text-red-700 animate-pulse'
208
- : cellEntries.length > 1
209
- ? 'border-indigo-400 bg-indigo-50 text-indigo-900'
210
- : 'border-gray-400 bg-white text-gray-800'}`, children: [clueNums && clueNums.length > 0 && (_jsx("span", { className: "absolute top-0.5 left-0.5 text-[9px] font-bold text-gray-500 leading-none", children: clueNums.join('/') })), _jsx("span", { children: displayLetter })] }, key));
211
- });
212
- }) }) })] })] })] }));
188
+ if (isClientMode) {
189
+ const across = clues
190
+ .filter((c) => c.direction === 'across')
191
+ .map((c) => ({
192
+ number: c.number,
193
+ clue: c.clue.trim(),
194
+ startRow: c.startRow,
195
+ startCol: c.startCol,
196
+ length: c.length || c.answer.trim().length,
197
+ }));
198
+ const down = clues
199
+ .filter((c) => c.direction === 'down')
200
+ .map((c) => ({
201
+ number: c.number,
202
+ clue: c.clue.trim(),
203
+ startRow: c.startRow,
204
+ startCol: c.startCol,
205
+ length: c.length || c.answer.trim().length,
206
+ }));
207
+ const answers = {};
208
+ for (const c of clues) {
209
+ if (c.answer) {
210
+ answers[`${c.direction}-${c.number}`] = c.answer.trim().toUpperCase();
211
+ }
212
+ }
213
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(CompactPreviewBanner, { onBack: () => setIsClientMode(false) }), _jsx(CrosswordPuzzleClient, { content: {
214
+ title,
215
+ gridSize: { rows, cols },
216
+ clues: { across, down },
217
+ }, correctAnswer: { answers, caseSensitive }, isReviewMode: true, userAnswers: answers })] }));
218
+ }
219
+ return (_jsx("div", { className: "space-y-3", children: _jsx(CompactFieldCard, { header: _jsx(CompactCreatorHeader, { icon: _jsx(Grid3X3, { className: "h-3.5 w-3.5" }), title: "\u00D4 ch\u1EEF (Crossword)", points: {
220
+ value: points,
221
+ onValueChange: setPoints,
222
+ }, preview: { onClick: () => setIsClientMode(true) } }), children: _jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 p-3 bg-gray-50 rounded-lg border border-gray-200", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-xs font-bold text-gray-700 mb-1", children: "Ti\u00EAu \u0111\u1EC1 \u00F4 ch\u1EEF" }), _jsx("input", { type: "text", value: title, onChange: (e) => setTitle(e.target.value), placeholder: "vd: Nationalities Crossword", className: "w-full px-3 py-1.5 text-sm border border-gray-300 rounded focus:ring-1 focus:ring-blue-500 outline-none" })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-xs font-bold text-gray-700 mb-1", children: "K\u00EDch th\u01B0\u1EDBc l\u01B0\u1EDBi (H\u00E0ng x C\u1ED9t)" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("input", { type: "number", min: 3, max: 30, value: rows, onChange: (e) => setRows(Math.max(3, parseInt(e.target.value) || 12)), className: "w-20 px-2 py-1.5 text-sm border border-gray-300 rounded outline-none" }), _jsx("span", { className: "text-gray-500 font-bold", children: "x" }), _jsx("input", { type: "number", min: 3, max: 30, value: cols, onChange: (e) => setCols(Math.max(3, parseInt(e.target.value) || 12)), className: "w-20 px-2 py-1.5 text-sm border border-gray-300 rounded outline-none" })] })] }), _jsx("div", { className: "flex items-center pt-5", children: _jsxs("label", { className: "flex items-center gap-2 text-sm text-gray-700 cursor-pointer", children: [_jsx("input", { type: "checkbox", checked: caseSensitive, onChange: (e) => setCaseSensitive(e.target.checked), className: "rounded text-blue-600 focus:ring-blue-500 h-4 w-4" }), _jsx("span", { children: "Ph\u00E2n bi\u1EC7t hoa/th\u01B0\u1EDDng" })] }) })] }), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-12 gap-6", children: [_jsxs("div", { className: "lg:col-span-5 flex flex-col gap-4", children: [_jsxs("form", { onSubmit: handleSaveClue, className: "p-4 rounded-xl border border-blue-200 bg-blue-50/40 flex flex-col gap-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-bold text-blue-900", children: editingClueId ? 'Chỉnh sửa gợi ý' : 'Thêm gợi ý mới' }), editingClueId && (_jsx("button", { type: "button", onClick: () => {
223
+ setEditingClueId(null);
224
+ setFormClue('');
225
+ setFormAnswer('');
226
+ }, className: "text-xs text-gray-500 hover:text-gray-700 underline", children: "H\u1EE7y ch\u1EC9nh s\u1EEDa" }))] }), _jsxs("div", { className: "grid grid-cols-3 gap-2", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-[11px] font-semibold text-gray-600 mb-0.5", children: "S\u1ED1 Clue" }), _jsx("input", { type: "number", min: 1, value: formNumber, onChange: (e) => setFormNumber(parseInt(e.target.value) || 1), className: "w-full px-2 py-1 text-sm border border-gray-300 rounded outline-none" })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[11px] font-semibold text-gray-600 mb-0.5", children: "H\u01B0\u1EDBng" }), _jsxs("select", { value: formDirection, onChange: (e) => setFormDirection(e.target.value), className: "w-full px-2 py-1 text-sm border border-gray-300 rounded outline-none bg-white", children: [_jsx("option", { value: "across", children: "Across (Ngang)" }), _jsx("option", { value: "down", children: "Down (D\u1ECDc)" })] })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[11px] font-semibold text-gray-600 mb-0.5", children: "To\u1EA1 \u0111\u1ED9 (R, C)" }), _jsxs("div", { className: "flex gap-1", children: [_jsx("input", { type: "number", min: 1, max: rows, value: formStartRow, onChange: (e) => setFormStartRow(parseInt(e.target.value) || 1), placeholder: "R", className: "w-1/2 px-1 py-1 text-xs border border-gray-300 rounded text-center" }), _jsx("input", { type: "number", min: 1, max: cols, value: formStartCol, onChange: (e) => setFormStartCol(parseInt(e.target.value) || 1), placeholder: "C", className: "w-1/2 px-1 py-1 text-xs border border-gray-300 rounded text-center" })] })] })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[11px] font-semibold text-gray-600 mb-0.5", children: "C\u00E2u g\u1EE3i \u00FD (Clue)" }), _jsx("input", { type: "text", value: formClue, onChange: (e) => setFormClue(e.target.value), placeholder: "vd: Spain, Capital of France...", className: "w-full px-3 py-1.5 text-sm border border-gray-300 rounded outline-none", required: true })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[11px] font-semibold text-gray-600 mb-0.5", children: "T\u1EEB \u0111\u00E1p \u00E1n (Answer Word)" }), _jsx("input", { type: "text", value: formAnswer, onChange: (e) => setFormAnswer(e.target.value), placeholder: "vd: SPANISH", className: "w-full px-3 py-1.5 text-sm border border-gray-300 rounded outline-none uppercase font-semibold", required: true })] }), _jsxs("button", { type: "submit", className: "mt-1 flex items-center justify-center gap-1.5 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded text-sm font-semibold transition", children: [editingClueId ? _jsx(Check, { className: "h-4 w-4" }) : _jsx(Plus, { className: "h-4 w-4" }), _jsx("span", { children: editingClueId ? 'Cập nhật gợi ý' : 'Thêm vào danh sách' })] })] }), _jsxs("div", { className: "flex flex-col gap-2 max-h-[420px] overflow-y-auto pr-1", children: [_jsxs("span", { className: "text-xs font-bold text-gray-600", children: ["Danh s\u00E1ch (", clues.length, " t\u1EEB):"] }), clues.length === 0 && (_jsx("p", { className: "text-xs text-gray-400 italic", children: "Ch\u01B0a c\u00F3 g\u1EE3i \u00FD n\u00E0o. H\u00E3y th\u00EAm g\u1EE3i \u00FD \u1EDF tr\u00EAn." })), clues.map((c) => (_jsxs("div", { className: "flex items-center justify-between p-2.5 bg-white rounded-lg border border-gray-200 hover:border-blue-300 transition text-sm shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-2 flex-1 min-w-0", children: [_jsx("span", { className: `flex items-center justify-center h-6 w-6 rounded text-xs font-bold text-white ${c.direction === 'across' ? 'bg-blue-600' : 'bg-purple-600'}`, children: c.number }), _jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [_jsx("span", { className: "font-semibold text-gray-800 truncate", children: c.clue }), _jsxs("span", { className: "text-xs text-gray-500 flex items-center gap-2", children: [_jsx("span", { className: "font-bold text-blue-700", children: c.answer }), _jsxs("span", { children: ["(", c.length, " ch\u1EEF)"] }), _jsxs("span", { children: ["[", c.direction === 'across' ? '→ Ngang' : '↓ Dọc', " (", c.startRow, ",", c.startCol, ")]"] })] })] })] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { type: "button", onClick: () => handleEditClue(c), className: "p-1 text-gray-500 hover:text-blue-600 rounded", title: "S\u1EEDa", children: _jsx(Edit2, { className: "h-4 w-4" }) }), _jsx("button", { type: "button", onClick: () => handleDeleteClue(c.id), className: "p-1 text-gray-500 hover:text-red-600 rounded", title: "X\u00F3a", children: _jsx(Trash2, { className: "h-4 w-4" }) })] })] }, c.id)))] })] }), _jsxs("div", { className: "lg:col-span-7 flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-bold text-gray-700", children: "Ma tr\u1EADn l\u01B0\u1EDBi \u00F4 ch\u1EEF tr\u1EF1c quan:" }), conflicts.length > 0 && (_jsxs("span", { className: "flex items-center gap-1 text-xs font-bold text-red-600 bg-red-50 px-2 py-0.5 rounded border border-red-200", children: [_jsx(AlertCircle, { className: "h-3.5 w-3.5" }), _jsxs("span", { children: ["C\u00F3 ", conflicts.length, " \u00F4 b\u1ECB xung \u0111\u1ED9t ch\u1EEF c\u00E1i!"] })] }))] }), _jsx("div", { className: "flex justify-center overflow-x-auto p-4 bg-gray-100 rounded-xl border border-gray-300 min-h-[380px]", children: _jsx("div", { className: "inline-grid gap-1", style: {
227
+ gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
228
+ }, children: Array.from({ length: rows }).map((_, rIdx) => {
229
+ const r = rIdx + 1;
230
+ return Array.from({ length: cols }).map((_, cIdx) => {
231
+ const c = cIdx + 1;
232
+ const key = `${r}-${c}`;
233
+ const cellEntries = cellMap.get(key);
234
+ const clueNums = clueNumberMap.get(key);
235
+ const isConflict = conflicts.includes(key);
236
+ if (!cellEntries || cellEntries.length === 0) {
237
+ return (_jsx("button", { type: "button", onClick: () => {
238
+ setFormStartRow(r);
239
+ setFormStartCol(c);
240
+ }, title: `Ô trống (${r},${c}) - Click để chọn toạ độ bắt đầu`, className: "h-8 w-8 sm:h-9 sm:w-9 md:h-10 md:w-10 bg-transparent hover:bg-gray-200/60 rounded flex items-center justify-center transition text-[10px] text-gray-300 hover:text-gray-500", children: "\u00B7" }, key));
241
+ }
242
+ const displayLetter = cellEntries[0]?.letter || '';
243
+ return (_jsxs("div", { className: `relative flex items-center justify-center rounded border-2 font-bold shadow-sm h-8 w-8 sm:h-9 sm:w-9 md:h-10 md:w-10 text-sm sm:text-base md:text-lg select-none transition ${isConflict
244
+ ? 'border-red-500 bg-red-100 text-red-700 animate-pulse'
245
+ : cellEntries.length > 1
246
+ ? 'border-indigo-400 bg-indigo-50 text-indigo-900'
247
+ : 'border-gray-400 bg-white text-gray-800'}`, children: [clueNums && clueNums.length > 0 && (_jsx("span", { className: "absolute top-0.5 left-0.5 text-[9px] font-bold text-gray-500 leading-none", children: clueNums.join('/') })), _jsx("span", { children: displayLetter })] }, key));
248
+ });
249
+ }) }) })] })] })] }) }) }));
213
250
  }
@@ -187,7 +187,7 @@ export function FillInBlankClient({ questionData, questionConfig, onSubmit, isRe
187
187
  const explText = explanation || questionData.explanation;
188
188
  if (!isReviewMode || !explText)
189
189
  return null;
190
- return (_jsxs("div", { className: "overflow-hidden rounded-xl border border-blue-200 bg-gradient-to-br from-blue-50 to-indigo-50 shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-2.5 border-b border-blue-100 bg-white/60 px-5 py-3", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-amber-400 to-orange-500 text-white shadow-sm", children: _jsx(Lightbulb, { className: "h-4 w-4" }) }), _jsx("h4", { className: "text-sm font-semibold text-slate-800", children: "Gi\u1EA3i th\u00EDch" })] }), _jsx("div", { className: "p-5", children: _jsx("p", { className: "text-sm text-slate-700 leading-relaxed", children: explText }) })] }));
190
+ return (_jsxs("div", { className: "overflow-hidden rounded-xl border border-blue-200 bg-gradient-to-br from-blue-50 to-indigo-50 shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-2 border-b border-blue-100 bg-white/60 px-3 py-2", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-md bg-gradient-to-br from-amber-400 to-orange-500 text-white", children: _jsx(Lightbulb, { className: "h-3.5 w-3.5" }) }), _jsx("h4", { className: "text-sm font-semibold text-slate-800", children: "Gi\u1EA3i th\u00EDch" })] }), _jsx("div", { className: "p-3", children: _jsx("p", { className: "text-sm text-slate-700 leading-relaxed", children: explText }) })] }));
191
191
  };
192
192
  /** Question-level image (non-group) */
193
193
  const renderQuestionImage = () => {
@@ -208,11 +208,11 @@ export function FillInBlankClient({ questionData, questionConfig, onSubmit, isRe
208
208
  // =====================================================
209
209
  if (!isLegacyFormat) {
210
210
  const hasAnyAnswer = placeholderIndices.some(idx => (answers[idx] || '').trim());
211
- return (_jsxs("div", { className: "space-y-4", children: [renderGroupBlock(), _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm transition-all hover:shadow-md", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white 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-orange-500 to-amber-600 text-white shadow-sm", children: _jsx(PenLine, { className: "h-4 w-4" }) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700", children: "\u0110i\u1EC1n v\u00E0o ch\u1ED7 tr\u1ED1ng" }), _jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-orange-100 px-2 py-0.5 text-xs font-medium text-orange-700 ring-1 ring-inset ring-orange-200/60", children: [_jsx(Hash, { className: "h-3 w-3" }), placeholderIndices.length] })] })] }), isReviewMode && score && (_jsxs("div", { className: cn('flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-bold', score.correct === score.total
211
+ return (_jsxs("div", { className: "space-y-4", children: [renderGroupBlock(), _jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm transition-all hover:shadow-md", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-3 py-2", 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-gradient-to-br from-orange-500 to-amber-600 text-white", children: _jsx(PenLine, { className: "h-3.5 w-3.5" }) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm font-semibold text-gray-700", children: "\u0110i\u1EC1n v\u00E0o ch\u1ED7 tr\u1ED1ng" }), _jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-orange-100 px-2 py-0.5 text-xs font-medium text-orange-700 ring-1 ring-inset ring-orange-200/60", children: [_jsx(Hash, { className: "h-3 w-3" }), placeholderIndices.length] })] })] }), isReviewMode && score && (_jsxs("div", { className: cn('flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-bold', score.correct === score.total
212
212
  ? 'bg-emerald-100 text-emerald-700 ring-1 ring-emerald-200/60'
213
213
  : score.correct >= score.total / 2
214
214
  ? 'bg-yellow-100 text-yellow-700 ring-1 ring-yellow-200/60'
215
- : 'bg-red-100 text-red-700 ring-1 ring-red-200/60'), children: [score.correct === score.total && _jsx(Check, { className: "h-3 w-3" }), score.correct, "/", score.total, " \u0111\u00FAng"] }))] }), _jsxs("div", { className: "p-5 space-y-4", children: [showAudio && cleanAudioUrl && (_jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-indigo-100 bg-gradient-to-r from-indigo-50 to-blue-50 p-3", children: [_jsx("div", { className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg bg-indigo-100", children: _jsx(Volume2, { className: "h-4 w-4 text-indigo-600" }) }), _jsx("audio", { controls: true, className: "h-9 w-full", src: audioPreviewUrl || cleanAudioUrl, preload: "metadata", children: "Tr\u00ECnh duy\u1EC7t kh\u00F4ng h\u1ED7 tr\u1EE3 audio." })] })), _jsx("div", { className: "rounded-xl bg-gradient-to-r from-orange-50/80 to-amber-50/50 p-5 border border-orange-100/80", children: renderQuestionWithBlanks() }), renderQuestionImage(), renderHints(), isReviewMode && (_jsxs("div", { className: "rounded-xl border border-gray-200 bg-white overflow-hidden shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-2 border-b border-gray-100 bg-gradient-to-r from-slate-50 to-gray-50 px-4 py-2.5", children: [_jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-slate-500 text-white", children: _jsx(ClipboardList, { className: "h-3 w-3" }) }), _jsx("h4", { className: "text-xs font-semibold text-gray-600 uppercase tracking-wider", children: "Chi ti\u1EBFt \u0111\u00E1p \u00E1n" })] }), _jsx("div", { className: "p-4 space-y-2.5", children: placeholderIndices.map((idx) => {
215
+ : 'bg-red-100 text-red-700 ring-1 ring-red-200/60'), children: [score.correct === score.total && _jsx(Check, { className: "h-3 w-3" }), score.correct, "/", score.total, " \u0111\u00FAng"] }))] }), _jsxs("div", { className: "space-y-3 p-3", children: [showAudio && cleanAudioUrl && (_jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-indigo-100 bg-gradient-to-r from-indigo-50 to-blue-50 p-3", children: [_jsx("div", { className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg bg-indigo-100", children: _jsx(Volume2, { className: "h-4 w-4 text-indigo-600" }) }), _jsx("audio", { controls: true, className: "h-9 w-full", src: audioPreviewUrl || cleanAudioUrl, preload: "metadata", children: "Tr\u00ECnh duy\u1EC7t kh\u00F4ng h\u1ED7 tr\u1EE3 audio." })] })), _jsx("div", { className: "rounded-xl bg-gradient-to-r from-orange-50/80 to-amber-50/50 p-5 border border-orange-100/80", children: renderQuestionWithBlanks() }), renderQuestionImage(), renderHints(), isReviewMode && (_jsxs("div", { className: "rounded-xl border border-gray-200 bg-white overflow-hidden shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-2 border-b border-gray-100 bg-gradient-to-r from-slate-50 to-gray-50 px-4 py-2.5", children: [_jsx("div", { className: "flex h-5 w-5 items-center justify-center rounded-full bg-slate-500 text-white", children: _jsx(ClipboardList, { className: "h-3 w-3" }) }), _jsx("h4", { className: "text-xs font-semibold text-gray-600 uppercase tracking-wider", children: "Chi ti\u1EBFt \u0111\u00E1p \u00E1n" })] }), _jsx("div", { className: "p-4 space-y-2.5", children: placeholderIndices.map((idx) => {
216
216
  const userInput = answers[idx] || '';
217
217
  const correctAnswer = formatBlankAnswersDisplay(correctAnswersMatrix[idx]) || '—';
218
218
  const isCorrect = isAnswerCorrect(idx, userInput);
@@ -231,9 +231,9 @@ export function FillInBlankClient({ questionData, questionConfig, onSubmit, isRe
231
231
  const userInput = answers[index] || '';
232
232
  const isCorrect = isReviewMode && isAnswerCorrect(index, userInput);
233
233
  const hasAnswered = userInput.trim() !== '';
234
- return (_jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm transition-all hover:shadow-md", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white 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-orange-500 to-amber-600 text-white shadow-sm", children: _jsx(PenLine, { className: "h-4 w-4" }) }), _jsxs("span", { className: "text-sm font-semibold text-gray-700", children: ["C\u00E2u ", index + 1, ": \u0110i\u1EC1n v\u00E0o ch\u1ED7 tr\u1ED1ng"] })] }), isReviewMode && hasAnswered && (_jsxs("div", { className: cn('flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-bold', isCorrect
234
+ return (_jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm transition-all hover:shadow-md", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-3 py-2", 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-gradient-to-br from-orange-500 to-amber-600 text-white", children: _jsx(PenLine, { className: "h-3.5 w-3.5" }) }), _jsxs("span", { className: "text-sm font-semibold text-gray-700", children: ["C\u00E2u ", index + 1, ": \u0110i\u1EC1n v\u00E0o ch\u1ED7 tr\u1ED1ng"] })] }), isReviewMode && hasAnswered && (_jsxs("div", { className: cn('flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-bold', isCorrect
235
235
  ? 'bg-emerald-100 text-emerald-700 ring-1 ring-emerald-200/60'
236
- : 'bg-red-100 text-red-700 ring-1 ring-red-200/60'), 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-4", children: [index === 0 && showAudio && cleanAudioUrl && (_jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-indigo-100 bg-gradient-to-r from-indigo-50 to-blue-50 p-3", children: [_jsx("div", { className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg bg-indigo-100", children: _jsx(Volume2, { className: "h-4 w-4 text-indigo-600" }) }), _jsx("audio", { controls: true, className: "h-9 w-full", src: audioPreviewUrl || cleanAudioUrl, preload: "metadata", children: "Tr\u00ECnh duy\u1EC7t kh\u00F4ng h\u1ED7 tr\u1EE3 audio." })] })), _jsx("div", { className: "rounded-xl bg-gradient-to-r from-orange-50/80 to-amber-50/50 p-5 border border-orange-100/80", children: renderLegacyBlank(blank.text, blank.id, index) }), index === 0 && renderQuestionImage(), index === 0 && renderHints(), isReviewMode && (_jsx("div", { className: cn('rounded-xl border p-3 transition-colors', isCorrect
236
+ : 'bg-red-100 text-red-700 ring-1 ring-red-200/60'), 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: "space-y-3 p-3", children: [index === 0 && showAudio && cleanAudioUrl && (_jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-indigo-100 bg-gradient-to-r from-indigo-50 to-blue-50 p-3", children: [_jsx("div", { className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg bg-indigo-100", children: _jsx(Volume2, { className: "h-4 w-4 text-indigo-600" }) }), _jsx("audio", { controls: true, className: "h-9 w-full", src: audioPreviewUrl || cleanAudioUrl, preload: "metadata", children: "Tr\u00ECnh duy\u1EC7t kh\u00F4ng h\u1ED7 tr\u1EE3 audio." })] })), _jsx("div", { className: "rounded-xl bg-gradient-to-r from-orange-50/80 to-amber-50/50 p-5 border border-orange-100/80", children: renderLegacyBlank(blank.text, blank.id, index) }), index === 0 && renderQuestionImage(), index === 0 && renderHints(), isReviewMode && (_jsx("div", { className: cn('rounded-xl border p-3 transition-colors', isCorrect
237
237
  ? 'border-emerald-200 bg-emerald-50/50'
238
238
  : hasAnswered
239
239
  ? 'border-red-200 bg-red-50/50'
@@ -6,10 +6,9 @@ import { Button } from '../../../../components/ui/button';
6
6
  import { Label } from '../../../../components/ui/label';
7
7
  import { Input } from '../../../../components/ui/input';
8
8
  import { Textarea } from '../../../../components/ui/textarea';
9
- import { PointsInput } from '../../../../components/ui/points-input';
10
- import { Card, CardContent, CardHeader, CardTitle } from '../../../../components/ui/card';
11
9
  import { Switch } from '../../../../components/ui/switch';
12
- import { Pencil, Eye, Lightbulb, Type, MessageSquare, Plus, Trash2, ListChecks, ImageIcon, Volume2, BookOpen } from 'lucide-react';
10
+ import { Eye, Type, MessageSquare, Plus, Trash2, ListChecks, ImageIcon, Volume2 } from 'lucide-react';
11
+ import { CompactCreatorHeader, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, } from '../../_shared/components/compact';
13
12
  import { FillInBlankClient } from './FillInBlankClient';
14
13
  import { blankHasAnswer, compactFillInBlankAnswers, formatBlankAnswersDisplay, extractPlaceholderIndices, getMaxPlaceholderIndex, normalizeFillInBlankAnswers, } from './answer-utils';
15
14
  import { useDebouncedCallback, usePresignedFileUrl } from '../../../../shared/lib/hooks';
@@ -151,6 +150,8 @@ function FillInBlankCreatorContent({ initialData, onChange, externalErrors, vali
151
150
  // UI State
152
151
  const [isClientMode, setIsClientMode] = useState(false);
153
152
  const [imagePreviewUrl, setImagePreviewUrl] = useState('');
153
+ const [isImageInputVisible, setIsImageInputVisible] = useState(() => Boolean(initialData?.content?.imageUrl || initialData?.imageUrl));
154
+ const [isAudioInputVisible, setIsAudioInputVisible] = useState(() => Boolean(initialData?.audioUrl || initialData?.content?.audioUrl));
154
155
  // Presigned URL for per-question image preview (non-grouped only)
155
156
  const { previewUrl: generatedPreviewUrl } = usePresignedFileUrl(imageUrl);
156
157
  const displayPreviewUrl = imagePreviewUrl || generatedPreviewUrl || '';
@@ -418,42 +419,49 @@ function FillInBlankCreatorContent({ initialData, onChange, externalErrors, vali
418
419
  groupNumber: isGrouped ? currentGroupNumber : undefined,
419
420
  ...(isGrouped && isImageLabelGroup ? { imageLabels } : {}),
420
421
  };
421
- return (_jsxs("div", { className: "space-y-4", children: [_jsx(Card, { children: _jsx(CardHeader, { children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx(CardTitle, { children: "Fill In Blank (Preview)" }), _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(FillInBlankClient, { questionData: questionData, questionConfig: questionConfig, autoFillCorrectAnswers: true, isReviewMode: false, explanation: explanation })] }));
422
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(CompactPreviewBanner, { onBack: () => setIsClientMode(false) }), _jsx(FillInBlankClient, { questionData: questionData, questionConfig: questionConfig, autoFillCorrectAnswers: true, isReviewMode: false, explanation: explanation })] }));
422
423
  }
423
424
  // ============ CREATOR UI ============
424
- return (_jsxs("div", { className: "space-y-4", children: [isGrouped && isImageLabelGroup && (_jsx(ImageLabelGroupCard, { groupNumber: currentGroupNumber, imageLabels: imageLabels, onImageLabelsChange: setImageLabels, title: groupTitle, onTitleChange: setGroupTitle, isReadOnly: !isFirstInGroup, uploadIdPrefix: `fill-in-blank-${partId ?? 'image-label'}` })), isGrouped && !isImageLabelGroup && (_jsx(BasicQuestionGroupCard, { groupNumber: currentGroupNumber, title: groupTitle, subtitle: groupSubtitle, content: groupContent, imageUrl: groupImageUrl, onTitleChange: setGroupTitle, onSubtitleChange: setGroupSubtitle, onContentChange: setGroupContent, onImageChange: setGroupImageUrl, uploadIdPrefix: `fill-in-blank-${partId ?? 'group'}` })), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-blue-100/50", children: [_jsx(CardHeader, { className: "px-4 py-3", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-blue-500 to-indigo-600 shadow-sm", children: _jsx(Type, { className: "h-4 w-4 text-white" }) }), _jsxs("div", { children: [_jsx(CardTitle, { className: "text-base font-bold text-gray-900", children: "\u0110i\u1EC1n v\u00E0o ch\u1ED7 tr\u1ED1ng" }), _jsx("p", { className: "text-xs text-gray-500", children: "H\u1ED7 tr\u1EE3 nhi\u1EC1u ch\u1ED7 tr\u1ED1ng trong m\u1ED9t c\u00E2u h\u1ECFi" })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [headerExtra, _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setIsClientMode(true), disabled: !question?.trim() || placeholderIndices.length === 0, className: "gap-2 border-indigo-200 text-indigo-600 hover:bg-indigo-50 hover:text-indigo-700", children: [_jsx(Eye, { className: "h-4 w-4" }), "Xem tr\u01B0\u1EDBc"] })] })] }) }), _jsxs(CardContent, { className: "space-y-4 px-4 pb-4", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-6", children: [_jsx(PointsInput, { value: points, onChange: (e) => setPoints(parseFloat(e.target.value) || 1) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Switch, { id: "show-suggested-words", checked: showHints, onCheckedChange: setShowHints }), _jsx(Label, { htmlFor: "show-suggested-words", className: "cursor-pointer text-sm font-medium text-gray-700", children: "Hi\u1EC3n th\u1ECB t\u1EEB g\u1EE3i \u00FD" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Switch, { id: "isExample", checked: isExample, onCheckedChange: setIsExample }), _jsx(Label, { htmlFor: "isExample", className: "cursor-pointer text-sm font-medium text-gray-700", children: "\u0110\u00E1nh d\u1EA5u l\u00E0 c\u00E2u h\u1ECFi Example" })] })] }), _jsx("div", { className: "rounded-xl border border-blue-200 bg-gradient-to-r from-blue-50 to-indigo-50 p-5 shadow-sm", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-blue-100", children: _jsx(Lightbulb, { className: "h-4 w-4 text-blue-600" }) }), _jsxs("div", { className: "text-sm text-blue-900", children: [_jsx("p", { className: "font-semibold text-blue-800", children: "H\u01B0\u1EDBng d\u1EABn t\u1EA1o c\u00E2u h\u1ECFi" }), _jsxs("ul", { className: "mt-2 space-y-1.5 text-blue-700", children: [_jsxs("li", { className: "flex items-center gap-2", children: [_jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-blue-400" }), "S\u1EED d\u1EE5ng ", _jsx("code", { className: "mx-1 rounded bg-blue-100 px-1.5 py-0.5 font-mono text-blue-800", children: '{0}' }), ", ", _jsx("code", { className: "mx-1 rounded bg-blue-100 px-1.5 py-0.5 font-mono text-blue-800", children: '{1}' }), ", ", _jsx("code", { className: "mx-1 rounded bg-blue-100 px-1.5 py-0.5 font-mono text-blue-800", children: '{2}' }), "... \u0111\u1EC3 \u0111\u00E1nh d\u1EA5u c\u00E1c ch\u1ED7 tr\u1ED1ng"] }), _jsxs("li", { className: "flex items-center gap-2", children: [_jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-blue-400" }), "H\u1EC7 th\u1ED1ng s\u1EBD t\u1EF1 \u0111\u1ED9ng t\u1EA1o \u00F4 nh\u1EADp \u0111\u00E1p \u00E1n cho m\u1ED7i ch\u1ED7 tr\u1ED1ng"] }), _jsxs("li", { className: "flex items-center gap-2", children: [_jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-blue-400" }), "V\u00ED d\u1EE5: \u201CHe ", '{0}', " 10 years old and she ", '{1}', " 12.\u201D"] })] })] })] }) }), !isGrouped && (_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(ImageIcon, { className: "h-4 w-4 text-indigo-500" }), "H\u00ECnh \u1EA3nh ", _jsx("span", { className: "text-sm font-normal text-gray-500", children: "(T\u00F9y ch\u1ECDn)" })] }), _jsx(FileUpload, { id: "fill-in-blank-image", label: "", accept: "image/*", value: imageUrl || '', onChange: (url) => {
425
- setImageUrl(url);
426
- }, onPresignedUrlChange: setImagePreviewUrl, maxSize: 5, placeholder: "Upload \u1EA3nh ho\u1EB7c paste URL", autoUpload: true, prefix: "questions" }), displayPreviewUrl && (_jsx(ImagePreview, { src: displayPreviewUrl, alt: "Preview", className: "mt-2 h-48 w-full max-w-md rounded-lg border border-gray-200" }))] })), includesAudio && (_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(Volume2, { className: "h-4 w-4 text-indigo-500" }), "Audio c\u00E2u h\u1ECFi"] }), _jsx(FileUpload, { id: "fill-in-blank-audio", label: "", accept: "audio/*", value: audioUrl || '', onChange: (url) => {
427
- setAudioUrl(url);
428
- }, maxSize: 20, placeholder: "Upload file audio", autoUpload: true, prefix: "questions", showPlayButton: true })] })), _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(Textarea, { id: "question", value: question, onChange: (e) => {
429
- setQuestion(e.target.value);
430
- if (validationErrors.question) {
431
- setValidationErrors(prev => ({ ...prev, question: undefined }));
432
- }
433
- }, placeholder: "V\u00ED d\u1EE5: He {0} 10 years old and she {1} 12.", rows: 3, className: `min-h-[100px] 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 })), placeholderIndices.length > 0 && (_jsx("div", { className: "flex items-center gap-2 rounded-lg bg-green-50 px-3 py-2", children: _jsxs("span", { className: "text-sm text-green-700", children: ["\u2713 \u0110\u00E3 ph\u00E1t hi\u1EC7n ", _jsx("strong", { children: placeholderIndices.length }), " ch\u1ED7 tr\u1ED1ng: ", placeholderIndices.map(i => (_jsx("code", { className: "mx-0.5 rounded bg-green-100 px-1.5 py-0.5 font-mono text-green-800", children: `{${i}}` }, i)))] }) }))] }), _jsxs("div", { className: "space-y-4", 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(Type, { className: "h-3.5 w-3.5 text-indigo-600" }) }), _jsxs(Label, { className: "text-base font-semibold text-gray-800", children: ["\u0110\u00E1p \u00E1n cho c\u00E1c ch\u1ED7 tr\u1ED1ng ", _jsx("span", { className: "text-red-500", children: "*" })] })] }), _jsxs("div", { className: "grid gap-6 lg:grid-cols-2", children: [_jsx("div", { className: "space-y-3", children: (placeholderIndices.length > 0 ? placeholderIndices : [0]).map((idx) => {
434
- const blankAlts = answers[idx]?.length ? answers[idx] : [''];
435
- const hasAnswer = blankHasAnswer(blankAlts);
436
- return (_jsxs("div", { className: `rounded-xl border-2 p-4 transition-all ${hasAnswer
437
- ? 'border-green-200 bg-gradient-to-r from-green-50 to-emerald-50'
438
- : 'border-gray-200 bg-white'}`, children: [_jsxs("div", { className: "mb-3 flex items-center gap-3", children: [_jsx("div", { className: `flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-xl font-mono font-bold transition-all ${hasAnswer
439
- ? 'bg-gradient-to-br from-green-500 to-emerald-600 text-white shadow-md'
440
- : 'bg-indigo-100 text-indigo-700'}`, children: `{${idx}}` }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("p", { className: "text-sm font-medium text-gray-700", children: ["Ch\u1ED7 tr\u1ED1ng ", idx + 1] }), _jsx("p", { className: "text-xs text-gray-500", children: "C\u00F3 th\u1EC3 th\u00EAm nhi\u1EC1u \u0111\u00E1p \u00E1n \u0111\u00FAng t\u01B0\u01A1ng \u0111\u01B0\u01A1ng" })] })] }), _jsx("div", { className: "space-y-2", children: blankAlts.map((alt, altIdx) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { value: alt, onChange: (e) => updateBlankAnswer(idx, altIdx, e.target.value), placeholder: altIdx === 0 ? `Đáp án chính cho {${idx}}` : `Đáp án thay thế ${altIdx + 1}`, className: `border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 ${validationErrors.answers?.[idx] ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` }), blankAlts.length > 1 && (_jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => removeBlankAlternative(idx, altIdx), className: "h-9 w-9 flex-shrink-0 text-red-500 hover:bg-red-50 hover:text-red-600", title: "X\u00F3a \u0111\u00E1p \u00E1n n\u00E0y", children: _jsx(Trash2, { className: "h-4 w-4" }) }))] }, altIdx))) }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => addBlankAlternative(idx), className: "mt-2 gap-1.5 border-dashed border-indigo-200 text-indigo-600 hover:bg-indigo-50", children: [_jsx(Plus, { className: "h-3.5 w-3.5" }), "Th\u00EAm \u0111\u00E1p \u00E1n \u0111\u00FAng"] }), validationErrors.answers?.[idx] && (_jsx("p", { className: "mt-2 text-sm text-red-600", children: validationErrors.answers[idx] }))] }, idx));
441
- }) }), showHints && (_jsxs("div", { className: "space-y-4 rounded-xl border-2 border-purple-200 bg-gradient-to-r from-purple-50 to-indigo-50 p-4", 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-purple-100", children: _jsx(ListChecks, { className: "h-3.5 w-3.5 text-purple-600" }) }), _jsxs(Label, { className: "text-base font-semibold text-gray-800", children: ["Danh s\u00E1ch t\u1EEB g\u1EE3i \u00FD ", _jsxs("span", { className: "text-sm font-normal text-gray-500", children: ["(", hints.length, " t\u1EEB)"] })] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Input, { value: newHint, onChange: (e) => setNewHint(e.target.value), placeholder: "Nh\u1EADp t\u1EEB g\u1EE3i \u00FD m\u1EDBi...", className: "flex-1 border-gray-200 bg-white", onKeyDown: (e) => {
442
- if (e.key === 'Enter' && newHint.trim()) {
443
- e.preventDefault();
444
- if (!hints.includes(newHint.trim())) {
445
- setHints([...hints, newHint.trim()]);
446
- }
447
- setNewHint('');
448
- }
449
- } }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => {
450
- if (newHint.trim() && !hints.includes(newHint.trim())) {
451
- setHints([...hints, newHint.trim()]);
452
- setNewHint('');
453
- }
454
- }, disabled: !newHint.trim(), 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"] })] }), hints.length > 0 ? (_jsx("div", { className: "flex flex-wrap gap-2", children: hints.map((word, index) => (_jsxs("div", { className: "flex items-center gap-2 rounded-lg border border-purple-200 bg-white px-3 py-2 shadow-sm transition-all hover:border-purple-300 hover:shadow", children: [_jsx("span", { className: "text-sm font-medium text-gray-700", children: word }), _jsx("button", { type: "button", onClick: () => {
455
- setHints(hints.filter((_, i) => i !== index));
456
- }, className: "rounded-full p-0.5 text-gray-400 transition-colors hover:bg-red-100 hover:text-red-500", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) })] }, index))) })) : (_jsx("p", { className: "text-center text-sm text-gray-500 italic", children: "Ch\u01B0a c\u00F3 t\u1EEB g\u1EE3i \u00FD n\u00E0o. Th\u00EAm t\u1EEB \u0111\u1EC3 hi\u1EC3n th\u1ECB cho h\u1ECDc sinh." }))] }))] })] }), question && (_jsxs("div", { className: "rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2 text-xs font-semibold text-gray-600", children: [_jsx(Eye, { className: "h-3.5 w-3.5" }), "Xem tr\u01B0\u1EDBc c\u00E2u ho\u00E0n ch\u1EC9nh"] }), _jsx("p", { className: "text-sm text-gray-700", children: getPreviewText() })] })), 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-amber-100/50", children: [_jsx(CardHeader, { className: "px-4 py-3", 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-gradient-to-br from-amber-500 to-orange-500 shadow-sm", children: _jsx(BookOpen, { className: "h-3.5 w-3.5 text-white" }) }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-base 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-xs 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, { className: "px-4 pb-4", 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" }) })] })] }));
425
+ return (_jsxs("div", { className: "space-y-3", children: [isGrouped && isImageLabelGroup && (_jsx(ImageLabelGroupCard, { groupNumber: currentGroupNumber, imageLabels: imageLabels, onImageLabelsChange: setImageLabels, title: groupTitle, onTitleChange: setGroupTitle, isReadOnly: !isFirstInGroup, uploadIdPrefix: `fill-in-blank-${partId ?? 'image-label'}` })), isGrouped && !isImageLabelGroup && (_jsx(BasicQuestionGroupCard, { groupNumber: currentGroupNumber, title: groupTitle, subtitle: groupSubtitle, content: groupContent, imageUrl: groupImageUrl, onTitleChange: setGroupTitle, onSubtitleChange: setGroupSubtitle, onContentChange: setGroupContent, onImageChange: setGroupImageUrl, uploadIdPrefix: `fill-in-blank-${partId ?? 'group'}` })), _jsxs(CompactFieldCard, { header: _jsx(CompactCreatorHeader, { icon: _jsx(Type, { className: "h-3.5 w-3.5" }), title: "\u0110i\u1EC1n v\u00E0o ch\u1ED7 tr\u1ED1ng", points: { value: points, onValueChange: setPoints }, example: { checked: isExample, onChange: setIsExample }, extraActions: _jsxs("div", { className: "flex h-8 items-center gap-1.5 rounded-md border border-gray-200 bg-gray-50 px-2.5", children: [_jsx(Switch, { id: "show-suggested-words", checked: showHints, onCheckedChange: setShowHints }), _jsx(Label, { htmlFor: "show-suggested-words", className: "cursor-pointer text-xs font-medium text-gray-700", children: "T\u1EEB g\u1EE3i \u00FD" })] }), headerExtra: headerExtra, preview: {
426
+ onClick: () => setIsClientMode(true),
427
+ disabled: !question?.trim() || placeholderIndices.length === 0,
428
+ } }), children: [_jsxs("div", { className: "space-y-1.5", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs(Label, { htmlFor: "question", className: "flex items-center gap-1.5 text-sm font-semibold text-gray-800", children: [_jsx(MessageSquare, { className: "h-3.5 w-3.5 text-indigo-500" }), "C\u00E2u h\u1ECFi ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsxs("div", { className: "flex items-center gap-1", children: [!isGrouped && (_jsx("button", { type: "button", title: "Th\u00EAm h\u00ECnh \u1EA3nh", onClick: () => setIsImageInputVisible(true), className: `inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors ${imageUrl || isImageInputVisible
429
+ ? 'bg-indigo-600 text-white shadow-sm'
430
+ : 'bg-indigo-50 text-indigo-600 hover:bg-indigo-100'}`, children: _jsx(ImageIcon, { className: "h-4 w-4" }) })), includesAudio && (_jsx("button", { type: "button", title: "Th\u00EAm audio", onClick: () => setIsAudioInputVisible(true), className: `inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors ${audioUrl || isAudioInputVisible
431
+ ? 'bg-violet-600 text-white shadow-sm'
432
+ : 'bg-violet-50 text-violet-600 hover:bg-violet-100'}`, children: _jsx(Volume2, { className: "h-4 w-4" }) }))] })] }), _jsx(Textarea, { id: "question", value: question, onChange: (e) => {
433
+ setQuestion(e.target.value);
434
+ if (validationErrors.question) {
435
+ setValidationErrors(prev => ({ ...prev, question: undefined }));
436
+ }
437
+ }, placeholder: "V\u00ED d\u1EE5: He {0} 10 years old and she {1} 12.", rows: 3, className: `min-h-[72px] 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 })), placeholderIndices.length > 0 && (_jsx("div", { className: "flex items-center gap-2 rounded-md bg-green-50 px-2.5 py-1.5", children: _jsxs("span", { className: "text-xs text-green-700", children: ["\u2713 ", _jsx("strong", { children: placeholderIndices.length }), " ch\u1ED7 tr\u1ED1ng: ", placeholderIndices.map(i => (_jsx("code", { className: "mx-0.5 rounded bg-green-100 px-1.5 py-0.5 font-mono text-green-800", children: `{${i}}` }, i)))] }) }))] }), !isGrouped && isImageInputVisible && (_jsxs("div", { className: "space-y-2", children: [_jsx(FileUpload, { id: "fill-in-blank-image", label: "", accept: "image/*", value: imageUrl || '', onChange: (url) => {
438
+ setImageUrl(url);
439
+ }, onPresignedUrlChange: setImagePreviewUrl, maxSize: 5, placeholder: "Upload \u1EA3nh ho\u1EB7c paste URL", autoUpload: true, prefix: "questions" }), displayPreviewUrl && (_jsx(ImagePreview, { src: displayPreviewUrl, alt: "Preview", className: "mt-2 h-48 w-full max-w-md rounded-lg border border-gray-200" }))] })), includesAudio && isAudioInputVisible && (_jsx(FileUpload, { id: "fill-in-blank-audio", label: "", accept: "audio/*", value: audioUrl || '', onChange: (url) => {
440
+ setAudioUrl(url);
441
+ }, maxSize: 20, placeholder: "Upload file audio", autoUpload: true, prefix: "questions", showPlayButton: true })), _jsxs("div", { className: "space-y-2", 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(Type, { className: "h-3.5 w-3.5 text-indigo-600" }) }), _jsxs(Label, { className: "text-sm font-semibold text-gray-800", children: ["\u0110\u00E1p \u00E1n cho c\u00E1c ch\u1ED7 tr\u1ED1ng ", _jsx("span", { className: "text-red-500", children: "*" })] })] }), _jsxs("div", { className: "grid gap-3 lg:grid-cols-2", children: [_jsx("div", { className: "space-y-2", children: (placeholderIndices.length > 0 ? placeholderIndices : [0]).map((idx) => {
442
+ const blankAlts = answers[idx]?.length ? answers[idx] : [''];
443
+ const hasAnswer = blankHasAnswer(blankAlts);
444
+ return (_jsxs("div", { className: `rounded-md border p-2.5 transition-all ${hasAnswer
445
+ ? 'border-green-200 bg-gradient-to-r from-green-50 to-emerald-50'
446
+ : 'border-gray-200 bg-white'}`, children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx("div", { className: `flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md font-mono text-xs font-bold ${hasAnswer
447
+ ? 'bg-gradient-to-br from-green-500 to-emerald-600 text-white'
448
+ : 'bg-indigo-100 text-indigo-700'}`, children: `{${idx}}` }), _jsxs("p", { className: "text-xs font-medium text-gray-700", children: ["Ch\u1ED7 tr\u1ED1ng ", idx + 1] })] }), _jsx("div", { className: "space-y-1.5", children: blankAlts.map((alt, altIdx) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { value: alt, onChange: (e) => updateBlankAnswer(idx, altIdx, e.target.value), placeholder: altIdx === 0 ? `Đáp án chính cho {${idx}}` : `Đáp án thay thế ${altIdx + 1}`, className: `h-8 border-gray-200 bg-white ${validationErrors.answers?.[idx] ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` }), blankAlts.length > 1 && (_jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: () => removeBlankAlternative(idx, altIdx), className: "h-7 w-7 flex-shrink-0 text-red-500 hover:bg-red-50 hover:text-red-600", title: "X\u00F3a \u0111\u00E1p \u00E1n n\u00E0y", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }))] }, altIdx))) }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => addBlankAlternative(idx), className: "mt-2 h-8 gap-1.5 border-dashed border-indigo-200 px-2.5 text-xs text-indigo-600 hover:bg-indigo-50", children: [_jsx(Plus, { className: "h-3.5 w-3.5" }), "Th\u00EAm \u0111\u00E1p \u00E1n \u0111\u00FAng"] }), validationErrors.answers?.[idx] && (_jsx("p", { className: "mt-2 text-sm text-red-600", children: validationErrors.answers[idx] }))] }, idx));
449
+ }) }), showHints && (_jsxs("div", { className: "space-y-2.5 rounded-md border border-purple-200 bg-purple-50/70 p-2.5", 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-purple-100", children: _jsx(ListChecks, { className: "h-3.5 w-3.5 text-purple-600" }) }), _jsxs(Label, { className: "text-sm font-semibold text-gray-800", children: ["T\u1EEB g\u1EE3i \u00FD ", _jsxs("span", { className: "text-xs font-normal text-gray-500", children: ["(", hints.length, " t\u1EEB)"] })] })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Input, { value: newHint, onChange: (e) => setNewHint(e.target.value), placeholder: "Nh\u1EADp t\u1EEB g\u1EE3i \u00FD m\u1EDBi...", className: "h-8 flex-1 border-gray-200 bg-white", onKeyDown: (e) => {
450
+ if (e.key === 'Enter' && newHint.trim()) {
451
+ e.preventDefault();
452
+ if (!hints.includes(newHint.trim())) {
453
+ setHints([...hints, newHint.trim()]);
454
+ }
455
+ setNewHint('');
456
+ }
457
+ } }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => {
458
+ if (newHint.trim() && !hints.includes(newHint.trim())) {
459
+ setHints([...hints, newHint.trim()]);
460
+ setNewHint('');
461
+ }
462
+ }, disabled: !newHint.trim(), className: "h-8 gap-1.5 border-green-200 px-2.5 text-xs text-green-600 hover:bg-green-50 hover:text-green-700", children: [_jsx(Plus, { className: "h-3.5 w-3.5" }), "Th\u00EAm"] })] }), hints.length > 0 ? (_jsx("div", { className: "flex flex-wrap gap-1.5", children: hints.map((word, index) => (_jsxs("div", { className: "flex items-center gap-1.5 rounded-md border border-purple-200 bg-white px-2 py-1", children: [_jsx("span", { className: "text-xs font-medium text-gray-700", children: word }), _jsx("button", { type: "button", onClick: () => {
463
+ setHints(hints.filter((_, i) => i !== index));
464
+ }, className: "rounded-full p-0.5 text-gray-400 transition-colors hover:bg-red-100 hover:text-red-500", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) })] }, index))) })) : (_jsx("p", { className: "text-center text-xs text-gray-500 italic", children: "Ch\u01B0a c\u00F3 t\u1EEB g\u1EE3i \u00FD n\u00E0o. Th\u00EAm t\u1EEB \u0111\u1EC3 hi\u1EC3n th\u1ECB cho h\u1ECDc sinh." }))] }))] })] }), question && (_jsxs("div", { className: "rounded-md border border-gray-200 bg-gray-50 p-2.5", children: [_jsxs("div", { className: "mb-1 flex items-center gap-1.5 text-xs font-semibold text-gray-600", children: [_jsx(Eye, { className: "h-3.5 w-3.5" }), "Xem tr\u01B0\u1EDBc c\u00E2u ho\u00E0n ch\u1EC9nh"] }), _jsx("p", { className: "text-sm text-gray-700", children: getPreviewText() })] })), externalErrors && externalErrors.length > 0 && (_jsxs("div", { className: "flex items-center gap-2 rounded-md border border-red-200 bg-red-50 p-2 text-xs text-red-700", children: [_jsx("span", { className: "font-semibold text-red-800", children: "L\u1ED7i:" }), _jsx("span", { children: externalErrors.join(' · ') })] })), _jsx(CompactExplanationToggle, { value: explanation, onValueChange: setExplanation, defaultVisible: Boolean(initialData?.explanation) })] })] }));
457
465
  }
458
466
  export function FillInBlankCreator(props) {
459
467
  return _jsx(FillInBlankCreatorContent, { ...props });