@tinyweb_dev/oe-exam-sdk 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/dist/components/exams/ExamCreator.js +1 -16
  2. package/dist/components/exams/take/ExamTakingPageContainer.js +0 -12
  3. package/dist/components/exams/take/components/QuestionRenderer.js +2 -15
  4. package/dist/components/exams/take/components/question-renderers/index.d.ts +0 -3
  5. package/dist/components/exams/take/components/question-renderers/index.js +0 -3
  6. package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionRenderer.js +0 -4
  7. package/dist/components/exams/take/types/speaking.types.d.ts +0 -31
  8. package/dist/components/exams/take/types.d.ts +0 -65
  9. package/dist/components/exams/take/utils/answer-transformers.js +6 -60
  10. package/dist/components/exams/take/utils/question-transformers.d.ts +2 -15
  11. package/dist/components/exams/take/utils/question-transformers.js +0 -143
  12. package/dist/components/questions/_shared/components/compact/CompactCreatorHeader.d.ts +23 -0
  13. package/dist/components/questions/_shared/components/compact/CompactCreatorHeader.js +9 -0
  14. package/dist/components/questions/_shared/components/compact/CompactExampleToggle.d.ts +6 -0
  15. package/dist/components/questions/_shared/components/compact/CompactExampleToggle.js +8 -0
  16. package/dist/components/questions/_shared/components/compact/CompactExplanationToggle.d.ts +7 -0
  17. package/dist/components/questions/_shared/components/compact/CompactExplanationToggle.js +14 -0
  18. package/dist/components/questions/_shared/components/compact/CompactFieldCard.d.ts +9 -0
  19. package/dist/components/questions/_shared/components/compact/CompactFieldCard.js +7 -0
  20. package/dist/components/questions/_shared/components/compact/CompactPreviewBanner.d.ts +7 -0
  21. package/dist/components/questions/_shared/components/compact/CompactPreviewBanner.js +7 -0
  22. package/dist/components/questions/_shared/components/compact/CompactPreviewButton.d.ts +6 -0
  23. package/dist/components/questions/_shared/components/compact/CompactPreviewButton.js +7 -0
  24. package/dist/components/questions/_shared/components/compact/index.d.ts +6 -0
  25. package/dist/components/questions/_shared/components/compact/index.js +6 -0
  26. package/dist/components/questions/_shared/config/question-types.config.js +0 -24
  27. package/dist/components/questions/_shared/hooks/useQuestionInitialization.js +0 -9
  28. package/dist/components/questions/_shared/types/index.d.ts +0 -1
  29. package/dist/components/questions/_shared/types/index.js +0 -1
  30. package/dist/components/questions/_shared/types/look-and-choose-answer.type.d.ts +0 -13
  31. package/dist/components/questions/_shared/utils/answer-builder.js +0 -11
  32. package/dist/components/questions/components/ColorRegionCreator.js +66 -63
  33. package/dist/components/questions/components/QuestionSearchDropdown.js +0 -8
  34. package/dist/components/questions/components/QuestionTypeSelector.js +0 -2
  35. package/dist/components/questions/components/index.d.ts +1 -0
  36. package/dist/components/questions/components/index.js +1 -0
  37. package/dist/components/questions/creator/question-type-registry.js +0 -8
  38. package/dist/components/questions/groups/ArticlesGroupCard.js +2 -2
  39. package/dist/components/questions/groups/BasicQuestionGroupCard.js +1 -1
  40. package/dist/components/questions/groups/DocumentGroupCard.js +1 -1
  41. package/dist/components/questions/groups/ImageLabelGroupCard.js +1 -1
  42. package/dist/components/questions/groups/MatchAnswerGroupCard.js +2 -2
  43. package/dist/components/questions/question-bank/QuestionEditorRenderer.d.ts +0 -3
  44. package/dist/components/questions/question-bank/QuestionEditorRenderer.js +1 -10
  45. package/dist/components/questions/question-bank/editor-adapters/choice-adapters.d.ts +0 -2
  46. package/dist/components/questions/question-bank/editor-adapters/choice-adapters.js +0 -41
  47. package/dist/components/questions/question-bank/editor-adapters/index.d.ts +2 -2
  48. package/dist/components/questions/question-bank/editor-adapters/index.js +2 -2
  49. package/dist/components/questions/question-bank/editor-adapters/media-adapters.d.ts +0 -1
  50. package/dist/components/questions/question-bank/editor-adapters/media-adapters.js +0 -28
  51. package/dist/components/questions/question-bank/question-bank-picker.utils.js +0 -7
  52. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +16 -16
  53. package/dist/components/questions/types/answer-the-question/AnswerTheQuestionCreator.js +36 -30
  54. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupClient.js +1 -1
  55. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupCreator.js +7 -6
  56. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +2 -2
  57. package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsCreator.js +11 -7
  58. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +1 -1
  59. package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js +11 -5
  60. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +5 -5
  61. package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +34 -28
  62. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseAnswerGroupImageUpload.js +2 -2
  63. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupClient.js +1 -1
  64. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupCreator.js +44 -28
  65. package/dist/components/questions/types/choose-then-answer-group/ChooseThenAnswerGroupClient.js +7 -7
  66. package/dist/components/questions/types/choose-then-answer-group/ChooseThenAnswerGroupCreator.js +8 -5
  67. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupClient.js +2 -2
  68. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupCreator.js +20 -16
  69. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleClient.js +1 -1
  70. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleCreator.js +66 -29
  71. package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +5 -5
  72. package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +45 -37
  73. package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupCreator.js +24 -20
  74. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +2 -2
  75. package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridCreator.js +68 -65
  76. package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixClient.js +1 -1
  77. package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixCreator.js +45 -5
  78. package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +2 -2
  79. package/dist/components/questions/types/label-the-picture/LabelThePictureCreator.js +18 -14
  80. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +2 -2
  81. package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupCreator.js +30 -30
  82. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneClient.js +2 -2
  83. package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneCreator.js +24 -31
  84. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneClient.js +2 -2
  85. package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneCreator.js +29 -32
  86. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +1 -1
  87. package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerCreator.js +27 -29
  88. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +1 -1
  89. package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesCreator.js +11 -15
  90. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +1 -1
  91. package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupCreator.js +22 -24
  92. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +1 -1
  93. package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeCreator.js +17 -24
  94. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +1 -1
  95. package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutCreator.js +31 -31
  96. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +1 -1
  97. package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListCreator.js +11 -15
  98. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +1 -1
  99. package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesCreator.js +14 -15
  100. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +2 -2
  101. package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerCreator.js +27 -25
  102. package/dist/components/questions/types/match-columns-to-make-sentences/MatchColumnsToMakeSentencesClient.js +12 -12
  103. package/dist/components/questions/types/match-columns-to-make-sentences/MatchColumnsToMakeSentencesCreator.js +8 -5
  104. package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureClient.js +8 -8
  105. package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureCreator.js +25 -20
  106. package/dist/components/questions/types/match-word-to-picture-group/MatchWordToPictureGroupClient.js +1 -1
  107. package/dist/components/questions/types/match-word-to-picture-group/MatchWordToPictureGroupCreator.js +13 -10
  108. package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesGroupCreator.js +8 -5
  109. package/dist/components/questions/types/read-displayed-content/ReadDisplayedContentCreator.js +7 -11
  110. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +1 -1
  111. package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsCreator.js +15 -12
  112. package/dist/components/questions/types/sort-words-into-categories/SortWordsIntoCategoriesClient.js +1 -1
  113. package/dist/components/questions/types/sort-words-into-categories/SortWordsIntoCategoriesCreator.js +5 -5
  114. package/dist/components/questions/types/speaking-conversation/SpeakingConversationCreator.js +35 -39
  115. package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +2 -2
  116. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardClient.js +1 -1
  117. package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +7 -8
  118. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +1 -1
  119. package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageCreator.js +30 -23
  120. package/dist/components/questions/types/spontaneous-qa/SpontaneousQAClient.js +1 -1
  121. package/dist/components/questions/types/spontaneous-qa/SpontaneousQACreator.js +26 -19
  122. package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupClient.js +1 -1
  123. package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupCreator.js +13 -11
  124. package/dist/components/questions/types/true-false/TrueFalseClient.js +2 -2
  125. package/dist/components/questions/types/true-false/TrueFalseCreator.js +35 -29
  126. package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupClient.js +1 -1
  127. package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupCreator.js +11 -7
  128. package/dist/components/questions/types/true-false-group/TrueFalseGroupClient.js +1 -1
  129. package/dist/components/questions/types/true-false-group/TrueFalseGroupCreator.js +11 -7
  130. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +2 -2
  131. package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphCreator.js +21 -56
  132. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -1
  133. package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +30 -24
  134. package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupClient.js +3 -3
  135. package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupCreator.js +12 -14
  136. package/dist/components/questions/types/word-ordering/WordOrderingClient.js +1 -1
  137. package/dist/components/questions/types/word-ordering/WordOrderingCreator.js +27 -18
  138. package/dist/components/questions/types/word-ordering-group/WordOrderingGroupClient.js +7 -7
  139. package/dist/components/questions/types/word-ordering-group/WordOrderingGroupCreator.js +16 -13
  140. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +2 -2
  141. package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +34 -28
  142. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +2 -2
  143. package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js +22 -22
  144. package/dist/components/questions/types/write-sentences/WriteSentencesCreator.js +21 -18
  145. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphClient.js +1 -1
  146. package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphCreator.js +7 -4
  147. package/dist/components/questions/viewer/QuestionViewer.js +0 -98
  148. package/dist/components/results/renderers/review-question-body-movers.js +2 -26
  149. package/dist/components/results/review-data.js +0 -4
  150. package/dist/components/ui/points-input.d.ts +1 -0
  151. package/dist/components/ui/points-input.js +12 -2
  152. package/dist/shared/constants/question-skills.js +0 -11
  153. package/dist/shared/lib/i18n/messages/en/admin.d.ts +0 -3
  154. package/dist/shared/lib/i18n/messages/en/admin.js +0 -3
  155. package/dist/shared/lib/i18n/messages/en.d.ts +0 -3
  156. package/dist/shared/lib/i18n/messages/vi/admin.d.ts +0 -3
  157. package/dist/shared/lib/i18n/messages/vi/admin.js +0 -3
  158. package/dist/shared/lib/i18n/messages/vi.d.ts +0 -3
  159. package/dist/shared/lib/utils/question-reverse-transform.js +0 -19
  160. package/dist/shared/lib/utils/question-transform-types.d.ts +1 -23
  161. package/dist/shared/lib/utils/question-transform-validation.js +0 -40
  162. package/dist/shared/lib/utils/question-transform.js +0 -9
  163. package/dist/shared/types/common.types.d.ts +1 -1
  164. package/dist/shared/types/entities/question.types.d.ts +1 -11
  165. package/dist/shared/types/questions/index.d.ts +0 -3
  166. package/dist/shared/types/questions/index.js +0 -6
  167. package/package.json +1 -1
  168. package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.d.ts +0 -2
  169. package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.js +0 -131
  170. package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.d.ts +0 -2
  171. package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.js +0 -76
  172. package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.d.ts +0 -2
  173. package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.js +0 -68
  174. package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.d.ts +0 -16
  175. package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.js +0 -212
  176. package/dist/components/questions/_shared/types/gn-speaking-interview.type.d.ts +0 -32
  177. package/dist/components/questions/_shared/types/gn-speaking-interview.type.js +0 -1
  178. package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.d.ts +0 -47
  179. package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.js +0 -1
  180. package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.d.ts +0 -2
  181. package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.js +0 -262
  182. package/dist/components/questions/types/gn-speaking-interview/register.d.ts +0 -2
  183. package/dist/components/questions/types/gn-speaking-interview/register.js +0 -121
  184. package/dist/components/questions/types/gn-speaking-interview/transform.d.ts +0 -2
  185. package/dist/components/questions/types/gn-speaking-interview/transform.js +0 -48
  186. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.d.ts +0 -20
  187. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.js +0 -72
  188. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.d.ts +0 -15
  189. package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.js +0 -230
  190. package/dist/components/questions/types/look-picture-choose-correct-answer/index.d.ts +0 -1
  191. package/dist/components/questions/types/look-picture-choose-correct-answer/index.js +0 -1
  192. package/dist/components/questions/types/look-picture-choose-correct-answer/register.d.ts +0 -2
  193. package/dist/components/questions/types/look-picture-choose-correct-answer/register.js +0 -66
  194. package/dist/components/questions/types/look-picture-choose-correct-answer/transform.d.ts +0 -2
  195. package/dist/components/questions/types/look-picture-choose-correct-answer/transform.js +0 -42
  196. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.d.ts +0 -6
  197. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.js +0 -96
  198. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.d.ts +0 -15
  199. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.js +0 -238
  200. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.d.ts +0 -2
  201. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.js +0 -2
  202. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.d.ts +0 -2
  203. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.js +0 -76
  204. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.d.ts +0 -2
  205. package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.js +0 -19
  206. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.d.ts +0 -7
  207. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.js +0 -134
  208. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.d.ts +0 -3
  209. package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.js +0 -617
  210. package/dist/components/questions/types/look-picture-fill-word-hint/index.d.ts +0 -2
  211. package/dist/components/questions/types/look-picture-fill-word-hint/index.js +0 -2
  212. package/dist/components/questions/types/look-picture-fill-word-hint/register.d.ts +0 -2
  213. package/dist/components/questions/types/look-picture-fill-word-hint/register.js +0 -82
  214. package/dist/components/questions/types/look-picture-fill-word-hint/transform.d.ts +0 -2
  215. package/dist/components/questions/types/look-picture-fill-word-hint/transform.js +0 -29
  216. package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.d.ts +0 -9
  217. package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.js +0 -12
  218. package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.d.ts +0 -17
  219. package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.js +0 -47
  220. package/dist/shared/types/questions/look-picture-choose-correct-answer.d.ts +0 -38
  221. package/dist/shared/types/questions/look-picture-choose-correct-answer.js +0 -5
  222. package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.d.ts +0 -63
  223. package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.js +0 -9
  224. package/dist/shared/types/questions/look-picture-fill-word-hint.d.ts +0 -57
  225. package/dist/shared/types/questions/look-picture-fill-word-hint.js +0 -7
@@ -0,0 +1,9 @@
1
+ import type { ReactNode } from 'react';
2
+ interface CompactFieldCardProps {
3
+ header?: ReactNode;
4
+ children: ReactNode;
5
+ className?: string;
6
+ contentClassName?: string;
7
+ }
8
+ export declare function CompactFieldCard({ header, children, className, contentClassName, }: CompactFieldCardProps): import("react").JSX.Element;
9
+ export {};
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Card, CardContent, CardHeader } from '../../../../../components/ui/card';
4
+ import { cn } from '../../../../../shared/lib/utils';
5
+ export function CompactFieldCard({ header, children, className, contentClassName, }) {
6
+ return (_jsxs(Card, { className: cn('overflow-hidden border-0 bg-white shadow-sm', className), children: [header ? _jsx(CardHeader, { className: "px-3 py-2", children: header }) : null, _jsx(CardContent, { className: cn('space-y-2.5 px-3 pb-3', !header && 'pt-3', contentClassName), children: children })] }));
7
+ }
@@ -0,0 +1,7 @@
1
+ interface CompactPreviewBannerProps {
2
+ message?: string;
3
+ onBack: () => void;
4
+ backLabel?: string;
5
+ }
6
+ export declare function CompactPreviewBanner({ message, onBack, backLabel, }: CompactPreviewBannerProps): import("react").JSX.Element;
7
+ export {};
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button } from '../../../../../components/ui/button';
4
+ import { Pencil } from 'lucide-react';
5
+ export function CompactPreviewBanner({ message = 'Xem trước — hiển thị đáp án đúng, ảnh và audio đã thêm', onBack, backLabel = 'Quay lại chỉnh sửa', }) {
6
+ return (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 rounded-xl border border-indigo-100 bg-indigo-50/70 px-4 py-2.5", children: [_jsx("p", { className: "text-sm font-medium text-indigo-800", children: message }), _jsxs(Button, { variant: "outline", size: "sm", onClick: onBack, children: [_jsx(Pencil, { className: "mr-2 h-4 w-4" }), backLabel] })] }));
7
+ }
@@ -0,0 +1,6 @@
1
+ interface CompactPreviewButtonProps {
2
+ onClick: () => void;
3
+ disabled?: boolean;
4
+ }
5
+ export declare function CompactPreviewButton({ onClick, disabled }: CompactPreviewButtonProps): import("react").JSX.Element;
6
+ export {};
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button } from '../../../../../components/ui/button';
4
+ import { Eye } from 'lucide-react';
5
+ export function CompactPreviewButton({ onClick, disabled }) {
6
+ return (_jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: onClick, disabled: disabled, className: "h-8 gap-1.5 border-indigo-200 px-2.5 text-xs text-indigo-600 hover:bg-indigo-50 hover:text-indigo-700", children: [_jsx(Eye, { className: "h-3.5 w-3.5" }), "Xem tr\u01B0\u1EDBc"] }));
7
+ }
@@ -0,0 +1,6 @@
1
+ export { CompactPreviewBanner } from './CompactPreviewBanner';
2
+ export { CompactExampleToggle } from './CompactExampleToggle';
3
+ export { CompactPreviewButton } from './CompactPreviewButton';
4
+ export { CompactCreatorHeader } from './CompactCreatorHeader';
5
+ export { CompactFieldCard } from './CompactFieldCard';
6
+ export { CompactExplanationToggle } from './CompactExplanationToggle';
@@ -0,0 +1,6 @@
1
+ export { CompactPreviewBanner } from './CompactPreviewBanner';
2
+ export { CompactExampleToggle } from './CompactExampleToggle';
3
+ export { CompactPreviewButton } from './CompactPreviewButton';
4
+ export { CompactCreatorHeader } from './CompactCreatorHeader';
5
+ export { CompactFieldCard } from './CompactFieldCard';
6
+ export { CompactExplanationToggle } from './CompactExplanationToggle';
@@ -101,21 +101,6 @@ export const QUESTION_TYPE_CONFIG = {
101
101
  requiresContent: true,
102
102
  hasDedicatedComponent: true,
103
103
  },
104
- LOOK_PICTURE_CHOOSE_CORRECT_ANSWER: {
105
- label: 'Nhìn tranh, chọn đáp án đúng',
106
- requiresContent: true,
107
- hasDedicatedComponent: true,
108
- },
109
- LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER: {
110
- label: 'Nhìn tranh, điền chỗ trống, chọn đáp án',
111
- requiresContent: true,
112
- hasDedicatedComponent: true,
113
- },
114
- LOOK_PICTURE_FILL_WORD_HINT: {
115
- label: 'Nhìn tranh điền từ gợi ý',
116
- requiresContent: true,
117
- hasDedicatedComponent: true,
118
- },
119
104
  LABEL_THE_PICTURE: {
120
105
  label: 'Label the Picture',
121
106
  requiresContent: true,
@@ -322,11 +307,6 @@ export const QUESTION_TYPE_CONFIG = {
322
307
  requiresContent: true,
323
308
  hasDedicatedComponent: true,
324
309
  },
325
- GN_SPEAKING_INTERVIEW: {
326
- label: 'GN Speaking - Hỏi đáp (Virtual + Real)',
327
- requiresContent: true,
328
- hasDedicatedComponent: true,
329
- },
330
310
  SPEAKING_CUE_CARD: {
331
311
  label: 'IELTS Cue Card (Speaking Part 2)',
332
312
  requiresContent: true,
@@ -378,9 +358,6 @@ export const QUESTION_TYPES_WITH_DEDICATED_COMPONENTS = [
378
358
  'ARRANGE_LETTERS_INTO_WORDS',
379
359
  'WRITE_SHORT_PARAGRAPH',
380
360
  'FILL_MISSING_WORDS_IN_GRID',
381
- 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER',
382
- 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER',
383
- 'LOOK_PICTURE_FILL_WORD_HINT',
384
361
  'LABEL_THE_PICTURE',
385
362
  'READ_AND_COLOR_OBJECTS',
386
363
  'IMAGE_OBJECT_MATCHING',
@@ -418,7 +395,6 @@ export const QUESTION_TYPES_WITH_DEDICATED_COMPONENTS = [
418
395
  'SPONTANEOUS_QA',
419
396
  'SPONTANEOUS_QA_GROUP',
420
397
  'SPEAKING_CONVERSATION',
421
- 'GN_SPEAKING_INTERVIEW',
422
398
  'SPEAKING_CUE_CARD',
423
399
  'WORD_FILL_STRUCTURED_FORM',
424
400
  'CROSSWORD_PUZZLE',
@@ -98,15 +98,6 @@ export function useQuestionInitialization({ initialData, prefilledType, prefille
98
98
  if (answerData.missingLetters)
99
99
  updateFieldRef.current('fillMissingWordsInGridAnswers', answerData.missingLetters);
100
100
  break;
101
- case 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER':
102
- case 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER':
103
- if (answerData.subQuestions)
104
- updateFieldRef.current('lookPictureChooseSubQuestions', answerData.subQuestions);
105
- break;
106
- case 'LOOK_PICTURE_FILL_WORD_HINT':
107
- if (answerData.subQuestions)
108
- updateFieldRef.current('lookPictureFillWordHintSubQuestions', answerData.subQuestions);
109
- break;
110
101
  }
111
102
  }
112
103
  }
@@ -5,7 +5,6 @@ export * from './arrange-letters-into-words.type';
5
5
  export * from './write-short-paragraph.type';
6
6
  export * from './fill-missing-words-in-grid.type';
7
7
  export * from './look-and-choose-answer.type';
8
- export * from './look-picture-fill-word-hint.type';
9
8
  export * from './label-the-picture.type';
10
9
  export * from './read-and-color-objects.type';
11
10
  export * from './fill-in-blank.type';
@@ -5,7 +5,6 @@ export * from './arrange-letters-into-words.type';
5
5
  export * from './write-short-paragraph.type';
6
6
  export * from './fill-missing-words-in-grid.type';
7
7
  export * from './look-and-choose-answer.type';
8
- export * from './look-picture-fill-word-hint.type';
9
8
  export * from './label-the-picture.type';
10
9
  export * from './read-and-color-objects.type';
11
10
  export * from './fill-in-blank.type';
@@ -10,10 +10,6 @@ export interface LookAndChooseData {
10
10
  correctAnswerId?: string;
11
11
  points?: number;
12
12
  }
13
- export interface LookPictureChooseCorrectAnswerData {
14
- subQuestions: LookAndChooseSubQuestion[];
15
- points?: number;
16
- }
17
13
  export interface ValidationRef {
18
14
  triggerValidation: () => Promise<boolean>;
19
15
  getFormData?: () => any;
@@ -27,15 +23,6 @@ export interface LookAndChooseCreatorProps {
27
23
  optionCount?: number | null;
28
24
  validationRef?: React.MutableRefObject<ValidationRef | null>;
29
25
  }
30
- export interface LookPictureChooseCorrectAnswerCreatorProps {
31
- initialData?: LookPictureChooseCorrectAnswerData;
32
- onSave?: (data: LookPictureChooseCorrectAnswerData) => void;
33
- onCancel?: () => void;
34
- onChange?: (data: LookPictureChooseCorrectAnswerData) => void;
35
- onUnsavedChangesChange?: (hasUnsavedChanges: boolean) => void;
36
- optionCount?: number | null;
37
- validationRef?: React.MutableRefObject<ValidationRef | null>;
38
- }
39
26
  export interface LookAndChooseClientProps {
40
27
  questionData: {
41
28
  imageUrl?: string;
@@ -59,17 +59,6 @@ export function buildAnswerPayload(questionType, state) {
59
59
  missingLetters: state.fillMissingWordsInGridAnswers || [],
60
60
  caseSensitive: false,
61
61
  };
62
- case 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER':
63
- // This type uses dedicated component, so answer is built by the component itself
64
- return undefined;
65
- case 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER':
66
- // This type uses dedicated component, so answer is built by the component itself
67
- return undefined;
68
- case 'LOOK_PICTURE_FILL_WORD_HINT':
69
- return {
70
- subQuestions: state.lookPictureFillWordHintSubQuestions || [],
71
- caseSensitive: false,
72
- };
73
62
  case 'READ_PASSAGE_AND_ANSWER_QUESTIONS':
74
63
  // This type uses dedicated component, so answer is built by the component itself
75
64
  return undefined;
@@ -3,11 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { useState, useRef, useCallback, useEffect } from 'react';
4
4
  import { Button } from '../../../components/ui/button';
5
5
  import { Label } from '../../../components/ui/label';
6
- import { Card, CardContent, CardHeader, CardTitle } from '../../../components/ui/card';
7
- import { PointsInput } from '../../../components/ui/points-input';
8
- import { X, Pencil, Eye, Plus, Trash2, MessageSquare, Palette, Lightbulb, Image } from 'lucide-react';
6
+ import { X, Plus, Trash2, MessageSquare, Palette, Image } from 'lucide-react';
7
+ import { CompactCreatorHeader, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, } from '../_shared/components/compact';
9
8
  import { Input } from '../../../components/ui/input';
10
- import { Textarea } from '../../../components/ui/textarea';
11
9
  import { FileUpload } from '../../../components/ui/file-upload';
12
10
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../../components/ui/select';
13
11
  import { ColorRegionNode } from './ColorRegionNode';
@@ -352,68 +350,73 @@ function ColorRegionCreatorContent({ initialData, onSave, onCancel, onChange, on
352
350
  instructions,
353
351
  explanation,
354
352
  };
355
- return (_jsxs("div", { className: "space-y-6", children: [_jsx(Card, { children: _jsx(CardHeader, { children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("div", { children: _jsx(CardTitle, { children: config.previewTitle }) }), _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(ClientComponent, { questionData: questionData, onSubmit: () => { }, isReviewMode: true, explanation: explanation })] }));
353
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(CompactPreviewBanner, { onBack: () => setIsClientMode(false) }), _jsx(ClientComponent, { questionData: questionData, onSubmit: () => { }, isReviewMode: true, explanation: explanation })] }));
356
354
  }
357
355
  // Get available colors (not yet added)
358
356
  const availableColors = COLOR_PALETTE.filter((color) => !colorNodes.some((node) => node.color === color));
359
- return (_jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-blue-100/50", children: [_jsx("div", { className: "h-1.5 bg-gradient-to-r from-pink-500 via-purple-500 to-indigo-500" }), _jsx(CardHeader, { className: "pb-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-pink-500 to-purple-600 shadow-md", children: _jsx(Palette, { className: "h-5 w-5 text-white" }) }), _jsxs("div", { children: [_jsx(CardTitle, { className: "text-xl font-bold text-gray-900", children: config.creatorTitle }), _jsx("p", { className: "text-sm text-gray-500", children: config.creatorSubtitle })] })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setIsClientMode(!isClientMode), 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-6", children: [!isClientMode && (_jsx("div", { className: "rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4", children: _jsx(PointsInput, { value: points, onChange: (e) => setPoints(Number(e.target.value) || 1) }) })), !isClientMode && (_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" }), _jsx("ul", { className: "mt-2 space-y-1.5 text-blue-700", children: config.instructionsTips.map((tip, index) => (_jsxs("li", { className: "flex items-center gap-2", children: [_jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-blue-400" }), tip] }, index))) })] })] }) })), !isClientMode && (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(MessageSquare, { className: "h-4 w-4 text-indigo-500" }), config.instructionsLabel, " ", instructionsRequired && _jsx("span", { className: "text-red-500", children: "*" })] }), _jsxs(Button, { onClick: () => {
360
- setInstructions([...instructions, '']);
361
- form.clearErrors('instructions');
362
- }, className: "gap-2 border-green-200 text-green-600 hover:bg-green-50 hover:text-green-700", size: "sm", variant: "outline", children: [_jsx(Plus, { className: "h-4 w-4" }), "Th\u00EAm c\u00E2u l\u1EC7nh"] })] }), errors.instructions && (_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("span", { className: "text-lg", children: "\u274C" }), _jsx("p", { className: "text-sm text-red-600", children: errors.instructions })] })), _jsx("div", { className: "space-y-3", children: instructions.map((instruction, index) => {
363
- const hasError = errors.instructionItems?.[index];
364
- return (_jsxs("div", { className: `group relative rounded-xl border-2 p-3 transition-all duration-200 ${instruction.trim()
365
- ? 'border-green-200 bg-gradient-to-r from-green-50 to-emerald-50'
366
- : 'border-gray-200 bg-white hover:border-gray-300'}`, children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: `flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg font-bold transition-all ${instruction.trim()
367
- ? 'bg-gradient-to-br from-green-500 to-emerald-600 text-white shadow-md'
368
- : 'bg-gray-100 text-gray-600'}`, children: index + 1 }), _jsx(Input, { value: instruction, onChange: (e) => {
369
- const newInstructions = [...instructions];
370
- newInstructions[index] = e.target.value;
371
- setInstructions(newInstructions);
372
- form.clearErrors('instructions');
373
- }, placeholder: `Ví dụ: ${config.instructionPlaceholder}`, className: `flex-1 border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 ${hasError ? 'border-red-400' : ''}` }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
374
- setInstructions(instructions.filter((_, i) => i !== index));
375
- }, className: "text-gray-400 hover:bg-red-50 hover:text-red-500", children: _jsx(Trash2, { className: "h-4 w-4" }) })] }), hasError && (_jsx("p", { className: "ml-11 mt-2 text-sm text-red-600", children: hasError }))] }, index));
376
- }) }), instructions.length === 0 && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-4", children: [_jsx("span", { className: "text-lg", children: "\u26A0\uFE0F" }), _jsx("p", { className: "text-sm text-amber-800", children: "Ch\u01B0a c\u00F3 h\u01B0\u1EDBng d\u1EABn n\u00E0o. Nh\u1EA5n \"Th\u00EAm c\u00E2u l\u1EC7nh\" \u0111\u1EC3 b\u1EAFt \u0111\u1EA7u." })] }))] })), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(Image, { className: "h-4 w-4 text-indigo-500" }), "\u1EA2nh n\u1EC1n ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(FileUpload, { id: "image-upload", label: "\u1EA2nh n\u1EC1n", accept: "image/*", value: backgroundImageUrl, onChange: (key) => {
377
- setBackgroundImageUrl(key);
378
- setImageLoaded(false);
379
- form.clearErrors();
380
- }, onPresignedUrlChange: (url) => {
381
- setBackgroundPreviewUrl(url);
382
- setImageLoaded(false);
383
- }, disabled: isClientMode, maxSize: 5, placeholder: "Paste URL ho\u1EB7c upload file", required: true, autoUpload: true, prefix: "questions", onFileLoad: () => {
384
- setImageLoaded(false);
385
- } }), errors.backgroundImageUrl && (_jsx("p", { className: "mt-1 text-sm text-red-600", children: errors.backgroundImageUrl }))] }), !isClientMode && (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(Palette, { className: "h-4 w-4 text-purple-500" }), config.addItemLabel || 'Thêm Màu', " ", _jsx("span", { className: "text-red-500", children: "*" })] }), !showAddColorPanel && (_jsxs(Button, { onClick: () => setShowAddColorPanel(true), className: "gap-2 border-purple-200 text-purple-600 hover:bg-purple-50 hover:text-purple-700", size: "sm", variant: "outline", disabled: availableColors.length === 0, children: [_jsx(Plus, { className: "h-4 w-4" }), config.addItemLabel || 'Thêm màu'] }))] }), errors.colorNodes && (_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("span", { className: "text-lg", children: "\u274C" }), _jsx("p", { className: "text-sm text-red-600", children: errors.colorNodes })] })), showAddColorPanel && (_jsxs("div", { className: "flex flex-col gap-3 rounded-xl border-2 border-purple-200 bg-gradient-to-r from-purple-50 to-indigo-50 p-4", children: [showColorLabel && (_jsx(Input, { value: colorLabelValue, onChange: (e) => setColorLabelValue(e.target.value), placeholder: config.colorLabelPlaceholder || 'Nhập label (ví dụ: Tom, Apple...)', className: "h-9 border-gray-200 bg-white" })), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Select, { value: selectedColor, onValueChange: setSelectedColor, children: [_jsx(SelectTrigger, { className: "flex-1 border-gray-200 bg-white", children: _jsx(SelectValue, { placeholder: "Ch\u1ECDn m\u00E0u..." }) }), _jsx(SelectContent, { children: availableColors.map((color) => (_jsx(SelectItem, { value: color, children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-4 w-4 rounded border border-gray-300", style: { backgroundColor: color } }), _jsx("span", { className: "font-mono text-xs", children: color })] }) }, color))) })] }), _jsx(Button, { size: "sm", onClick: addNewColorNode, disabled: !selectedColor ||
386
- availableColors.length === 0 ||
387
- (showColorLabel && !colorLabelValue.trim()), className: "bg-purple-600 hover:bg-purple-700", children: "T\u1EA1o" }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => {
388
- setShowAddColorPanel(false);
389
- setSelectedColor('');
390
- setColorLabelValue('');
391
- }, children: "H\u1EE7y" })] })] })), colorNodes.length === 0 && !showAddColorPanel && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-4", children: [_jsx("span", { className: "text-lg", children: "\u26A0\uFE0F" }), _jsx("p", { className: "text-sm text-amber-800", children: config.emptyItemMessage || 'Chưa có màu nào. Nhấn "Thêm màu" để bắt đầu.' })] }))] })), errors.regionNodes && (_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("span", { className: "text-lg", children: "\u274C" }), _jsx("p", { className: "text-sm text-red-600", children: errors.regionNodes })] }))] })] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-indigo-100/50", children: [_jsx("div", { className: "h-1 bg-gradient-to-r from-indigo-400 to-purple-500" }), _jsx(CardHeader, { className: "pb-3", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-base font-semibold text-gray-800", children: "Workspace \u2014 \u1EA2nh n\u1EC1n" }), _jsx("span", { className: "text-xs text-gray-500", children: "K\u00E9o th\u1EA3 region \u0111\u1EC3 \u0111\u1ECBnh v\u1ECB" })] }) }), _jsxs(CardContent, { className: "p-0", children: [colorNodes.length > 0 && (_jsx("div", { className: "border-b border-gray-100 px-4 py-3 flex flex-wrap gap-2", children: colorNodes.map((node) => (_jsxs("div", { className: "inline-flex items-center gap-1.5 rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-900", children: [_jsx("div", { className: "h-4 w-4 rounded border border-gray-300", style: { backgroundColor: node.color } }), node.label ? (_jsx("span", { className: "text-xs", children: node.label })) : (_jsx("span", { className: "font-mono text-xs", children: node.color })), !isClientMode && (_jsx("button", { onClick: () => removeColorNode(node.id), className: "group rounded p-0.5 transition-all hover:scale-110 hover:bg-red-100", type: "button", children: _jsx(X, { className: "h-3 w-3 text-gray-500 transition-colors group-hover:text-red-600" }) }))] }, node.id))) })), _jsx("div", { ref: workspaceRef, className: "relative w-full overflow-hidden select-none isolate", style: { cursor: draggingId ? 'grabbing' : 'default' }, children: backgroundPreviewUrl ? (_jsxs(_Fragment, { children: [_jsx("img", { src: backgroundPreviewUrl, alt: "Background", className: "block w-full h-auto", draggable: false, onLoad: () => setImageLoaded(true), onError: () => {
392
- form.setError('backgroundImageUrl', { message: 'Không thể load ảnh!' });
393
- setImageLoaded(false);
394
- } }), imageLoaded &&
395
- regionNodes.map((region) => {
396
- const linkedColorNode = colorNodes.find((n) => n.id === region.linkedColorNodeId);
397
- return (_jsx("div", { style: {
398
- position: 'absolute',
399
- left: `${region.x}%`,
400
- top: `${region.y}%`,
401
- width: `${region.width}%`,
402
- height: `${region.height}%`,
403
- cursor: isClientMode ? 'default' : 'grab',
404
- zIndex: draggingId === region.id ? 2 : 1,
405
- }, onMouseDown: (e) => handleRegionMouseDown(region.id, region.x, region.y, e), children: _jsx(ColorRegionNode, { data: {
406
- color: region.color,
407
- x: region.x,
408
- y: region.y,
409
- width: region.width,
410
- height: region.height,
411
- onRemove: () => removeRegion(region.id),
412
- isEditMode: !isClientMode,
413
- isClientMode: isClientMode,
414
- label: linkedColorNode?.label || '',
415
- } }) }, region.id));
416
- })] })) : (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 py-20 text-gray-400", children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-10 w-10 text-gray-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), _jsx("p", { className: "text-sm", children: "Ch\u01B0a c\u00F3 \u1EA3nh n\u1EC1n. H\u00E3y upload \u1EA3nh \u1EDF tr\u00EAn." })] })) })] })] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-gray-100/50", children: [_jsx("div", { className: "h-1 bg-gradient-to-r from-gray-300 to-gray-400" }), _jsx(CardHeader, { className: "pb-3", 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-gray-100", children: _jsx(MessageSquare, { className: "h-3.5 w-3.5 text-gray-600" }) }), _jsx(CardTitle, { className: "text-lg font-semibold text-gray-800", children: "Gi\u1EA3i th\u00EDch" })] }) }), _jsx(CardContent, { children: _jsx(Textarea, { id: "explanation", value: explanation, onChange: (e) => setExplanation(e.target.value), placeholder: "Nh\u1EADp gi\u1EA3i th\u00EDch cho \u0111\u00E1p \u00E1n \u0111\u00FAng...", rows: 3, className: "border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200" }) })] })] }));
357
+ return (_jsxs("div", { className: "space-y-3", children: [_jsxs(CompactFieldCard, { header: _jsx(CompactCreatorHeader, { icon: _jsx(Palette, { className: "h-3.5 w-3.5" }), title: config.creatorTitle, points: {
358
+ value: points,
359
+ onValueChange: setPoints,
360
+ }, preview: {
361
+ onClick: () => setIsClientMode(true),
362
+ } }), children: [!isClientMode && (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(MessageSquare, { className: "h-4 w-4 text-indigo-500" }), config.instructionsLabel, " ", instructionsRequired && _jsx("span", { className: "text-red-500", children: "*" })] }), _jsxs(Button, { onClick: () => {
363
+ setInstructions([...instructions, '']);
364
+ form.clearErrors('instructions');
365
+ }, className: "gap-2 border-green-200 text-green-600 hover:bg-green-50 hover:text-green-700", size: "sm", variant: "outline", children: [_jsx(Plus, { className: "h-4 w-4" }), "Th\u00EAm c\u00E2u l\u1EC7nh"] })] }), errors.instructions && (_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("span", { className: "text-lg", children: "\u274C" }), _jsx("p", { className: "text-sm text-red-600", children: errors.instructions })] })), _jsx("div", { className: "space-y-3", children: instructions.map((instruction, index) => {
366
+ const hasError = errors.instructionItems?.[index];
367
+ return (_jsxs("div", { className: `group relative rounded-xl border-2 p-3 transition-all duration-200 ${instruction.trim()
368
+ ? 'border-green-200 bg-gradient-to-r from-green-50 to-emerald-50'
369
+ : 'border-gray-200 bg-white hover:border-gray-300'}`, children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: `flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg font-bold transition-all ${instruction.trim()
370
+ ? 'bg-gradient-to-br from-green-500 to-emerald-600 text-white shadow-md'
371
+ : 'bg-gray-100 text-gray-600'}`, children: index + 1 }), _jsx(Input, { value: instruction, onChange: (e) => {
372
+ const newInstructions = [...instructions];
373
+ newInstructions[index] = e.target.value;
374
+ setInstructions(newInstructions);
375
+ form.clearErrors('instructions');
376
+ }, placeholder: `Ví dụ: ${config.instructionPlaceholder}`, className: `flex-1 border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 ${hasError ? 'border-red-400' : ''}` }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
377
+ setInstructions(instructions.filter((_, i) => i !== index));
378
+ }, className: "text-gray-400 hover:bg-red-50 hover:text-red-500", children: _jsx(Trash2, { className: "h-4 w-4" }) })] }), hasError && (_jsx("p", { className: "ml-11 mt-2 text-sm text-red-600", children: hasError }))] }, index));
379
+ }) }), instructions.length === 0 && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-4", children: [_jsx("span", { className: "text-lg", children: "\u26A0\uFE0F" }), _jsx("p", { className: "text-sm text-amber-800", children: "Ch\u01B0a c\u00F3 h\u01B0\u1EDBng d\u1EABn n\u00E0o. Nh\u1EA5n \"Th\u00EAm c\u00E2u l\u1EC7nh\" \u0111\u1EC3 b\u1EAFt \u0111\u1EA7u." })] }))] })), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(Image, { className: "h-4 w-4 text-indigo-500" }), "\u1EA2nh n\u1EC1n ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(FileUpload, { id: "image-upload", label: "\u1EA2nh n\u1EC1n", accept: "image/*", value: backgroundImageUrl, onChange: (key) => {
380
+ setBackgroundImageUrl(key);
381
+ setImageLoaded(false);
382
+ form.clearErrors();
383
+ }, onPresignedUrlChange: (url) => {
384
+ setBackgroundPreviewUrl(url);
385
+ setImageLoaded(false);
386
+ }, disabled: isClientMode, maxSize: 5, placeholder: "Paste URL ho\u1EB7c upload file", required: true, autoUpload: true, prefix: "questions", onFileLoad: () => {
387
+ setImageLoaded(false);
388
+ } }), errors.backgroundImageUrl && (_jsx("p", { className: "mt-1 text-sm text-red-600", children: errors.backgroundImageUrl }))] }), !isClientMode && (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(Palette, { className: "h-4 w-4 text-purple-500" }), config.addItemLabel || 'Thêm Màu', " ", _jsx("span", { className: "text-red-500", children: "*" })] }), !showAddColorPanel && (_jsxs(Button, { onClick: () => setShowAddColorPanel(true), className: "gap-2 border-purple-200 text-purple-600 hover:bg-purple-50 hover:text-purple-700", size: "sm", variant: "outline", disabled: availableColors.length === 0, children: [_jsx(Plus, { className: "h-4 w-4" }), config.addItemLabel || 'Thêm màu'] }))] }), errors.colorNodes && (_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("span", { className: "text-lg", children: "\u274C" }), _jsx("p", { className: "text-sm text-red-600", children: errors.colorNodes })] })), showAddColorPanel && (_jsxs("div", { className: "flex flex-col gap-3 rounded-xl border-2 border-purple-200 bg-gradient-to-r from-purple-50 to-indigo-50 p-4", children: [showColorLabel && (_jsx(Input, { value: colorLabelValue, onChange: (e) => setColorLabelValue(e.target.value), placeholder: config.colorLabelPlaceholder || 'Nhập label (ví dụ: Tom, Apple...)', className: "h-9 border-gray-200 bg-white" })), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Select, { value: selectedColor, onValueChange: setSelectedColor, children: [_jsx(SelectTrigger, { className: "flex-1 border-gray-200 bg-white", children: _jsx(SelectValue, { placeholder: "Ch\u1ECDn m\u00E0u..." }) }), _jsx(SelectContent, { children: availableColors.map((color) => (_jsx(SelectItem, { value: color, children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-4 w-4 rounded border border-gray-300", style: { backgroundColor: color } }), _jsx("span", { className: "font-mono text-xs", children: color })] }) }, color))) })] }), _jsx(Button, { size: "sm", onClick: addNewColorNode, disabled: !selectedColor ||
389
+ availableColors.length === 0 ||
390
+ (showColorLabel && !colorLabelValue.trim()), className: "bg-purple-600 hover:bg-purple-700", children: "T\u1EA1o" }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => {
391
+ setShowAddColorPanel(false);
392
+ setSelectedColor('');
393
+ setColorLabelValue('');
394
+ }, children: "H\u1EE7y" })] })] })), colorNodes.length === 0 && !showAddColorPanel && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-4", children: [_jsx("span", { className: "text-lg", children: "\u26A0\uFE0F" }), _jsx("p", { className: "text-sm text-amber-800", children: config.emptyItemMessage || 'Chưa có màu nào. Nhấn "Thêm màu" để bắt đầu.' })] }))] })), errors.regionNodes && (_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("span", { className: "text-lg", children: "\u274C" }), _jsx("p", { className: "text-sm text-red-600", children: errors.regionNodes })] }))] }), _jsxs(CompactFieldCard, { header: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("p", { className: "text-sm font-semibold text-gray-800", children: "Workspace \u2014 \u1EA2nh n\u1EC1n" }), _jsx("span", { className: "text-xs text-gray-500", children: "K\u00E9o th\u1EA3 region \u0111\u1EC3 \u0111\u1ECBnh v\u1ECB" })] }), contentClassName: "p-0 space-y-0 px-0 pb-0", children: [colorNodes.length > 0 && (_jsx("div", { className: "border-b border-gray-100 px-4 py-3 flex flex-wrap gap-2", children: colorNodes.map((node) => (_jsxs("div", { className: "inline-flex items-center gap-1.5 rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-900", children: [_jsx("div", { className: "h-4 w-4 rounded border border-gray-300", style: { backgroundColor: node.color } }), node.label ? (_jsx("span", { className: "text-xs", children: node.label })) : (_jsx("span", { className: "font-mono text-xs", children: node.color })), !isClientMode && (_jsx("button", { onClick: () => removeColorNode(node.id), className: "group rounded p-0.5 transition-all hover:scale-110 hover:bg-red-100", type: "button", children: _jsx(X, { className: "h-3 w-3 text-gray-500 transition-colors group-hover:text-red-600" }) }))] }, node.id))) })), _jsx("div", { ref: workspaceRef, className: "relative w-full overflow-hidden select-none isolate", style: { cursor: draggingId ? 'grabbing' : 'default' }, children: backgroundPreviewUrl ? (_jsxs(_Fragment, { children: [_jsx("img", { src: backgroundPreviewUrl, alt: "Background", className: "block w-full h-auto", draggable: false, onLoad: () => setImageLoaded(true), onError: () => {
395
+ form.setError('backgroundImageUrl', { message: 'Không thể load ảnh!' });
396
+ setImageLoaded(false);
397
+ } }), imageLoaded &&
398
+ regionNodes.map((region) => {
399
+ const linkedColorNode = colorNodes.find((n) => n.id === region.linkedColorNodeId);
400
+ return (_jsx("div", { style: {
401
+ position: 'absolute',
402
+ left: `${region.x}%`,
403
+ top: `${region.y}%`,
404
+ width: `${region.width}%`,
405
+ height: `${region.height}%`,
406
+ cursor: isClientMode ? 'default' : 'grab',
407
+ zIndex: draggingId === region.id ? 2 : 1,
408
+ }, onMouseDown: (e) => handleRegionMouseDown(region.id, region.x, region.y, e), children: _jsx(ColorRegionNode, { data: {
409
+ color: region.color,
410
+ x: region.x,
411
+ y: region.y,
412
+ width: region.width,
413
+ height: region.height,
414
+ onRemove: () => removeRegion(region.id),
415
+ isEditMode: !isClientMode,
416
+ isClientMode: isClientMode,
417
+ label: linkedColorNode?.label || '',
418
+ } }) }, region.id));
419
+ })] })) : (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 py-20 text-gray-400", children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-10 w-10 text-gray-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), _jsx("p", { className: "text-sm", children: "Ch\u01B0a c\u00F3 \u1EA3nh n\u1EC1n. H\u00E3y upload \u1EA3nh \u1EDF tr\u00EAn." })] })) })] }), _jsx(CompactExplanationToggle, { value: explanation, onValueChange: setExplanation, defaultVisible: Boolean(initialData?.explanation) })] }));
417
420
  }
418
421
  export function ColorRegionCreator(props) {
419
422
  return _jsx(ColorRegionCreatorContent, { ...props });
@@ -19,9 +19,6 @@ const truncate = (text, maxLength) => {
19
19
  };
20
20
  // Image-based question types
21
21
  const IMAGE_BASED_TYPES = [
22
- 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER',
23
- 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER',
24
- 'LOOK_PICTURE_FILL_WORD_HINT',
25
22
  'FILL_IN_BLANK',
26
23
  'FILL_IN_BLANK_GROUP',
27
24
  'LABEL_THE_PICTURE',
@@ -54,9 +51,6 @@ const getQuestionTypeIcon = (type) => {
54
51
  // Get question type display name in Vietnamese
55
52
  const getQuestionTypeName = (type) => {
56
53
  const typeMap = {
57
- 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER': 'Nhìn tranh điền chỗ trống',
58
- 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER': 'Nhìn tranh chọn đáp án',
59
- 'LOOK_PICTURE_FILL_WORD_HINT': 'Nhìn tranh điền từ gợi ý',
60
54
  'FILL_MISSING_WORDS_IN_GRID': 'Điền chữ trong bảng',
61
55
  'CHOOSE_THE_CORRECT_ANSWER': 'Chọn đáp án đúng',
62
56
  'LABEL_THE_PICTURE': 'Gắn nhãn hình ảnh',
@@ -90,7 +84,6 @@ export const getContentDisplayText = (content, type) => {
90
84
  }
91
85
  // Handle object content based on question type
92
86
  if (typeof content === 'object') {
93
- // LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER, LOOK_PICTURE_CHOOSE_CORRECT_ANSWER
94
87
  if (content.subQuestions && Array.isArray(content.subQuestions)) {
95
88
  const firstSubQ = content.subQuestions[0];
96
89
  if (firstSubQ?.question) {
@@ -101,7 +94,6 @@ export const getContentDisplayText = (content, type) => {
101
94
  if (content.question) {
102
95
  return content.question;
103
96
  }
104
- // LOOK_PICTURE_FILL_WORD_HINT - show word pattern
105
97
  if (content.word) {
106
98
  return `Điền chữ: ${content.word}`;
107
99
  }
@@ -19,8 +19,6 @@ export function QuestionTypeSelector({ value, onValueChange, disabled, }) {
19
19
  'READ_AND_CHOOSE_APPROPRIATE_WORD',
20
20
  'WRITE_SHORT_PARAGRAPH',
21
21
  'FILL_MISSING_WORDS_IN_GRID',
22
- 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER',
23
- 'LOOK_PICTURE_FILL_WORD_HINT',
24
22
  'LABEL_THE_PICTURE',
25
23
  'READ_AND_COLOR_OBJECTS',
26
24
  'ANSWER_THE_QUESTION',
@@ -3,6 +3,7 @@ export { ColorRegionClient } from './ColorRegionClient';
3
3
  export { ColorRegionCreator } from './ColorRegionCreator';
4
4
  export { ColorRegionNode } from './ColorRegionNode';
5
5
  export { CreatorGuide } from './CreatorGuide';
6
+ export { CompactCreatorHeader, CompactExampleToggle, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, CompactPreviewButton, } from '../_shared/components/compact';
6
7
  export { NameNode } from './NameNode';
7
8
  export { QuestionBankOption } from './QuestionBankOption';
8
9
  export { QuestionBasicInfoForm } from './QuestionBasicInfoForm';
@@ -3,6 +3,7 @@ export { ColorRegionClient } from './ColorRegionClient';
3
3
  export { ColorRegionCreator } from './ColorRegionCreator';
4
4
  export { ColorRegionNode } from './ColorRegionNode';
5
5
  export { CreatorGuide } from './CreatorGuide';
6
+ export { CompactCreatorHeader, CompactExampleToggle, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, CompactPreviewButton, } from '../_shared/components/compact';
6
7
  export { NameNode } from './NameNode';
7
8
  export { QuestionBankOption } from './QuestionBankOption';
8
9
  export { QuestionBasicInfoForm } from './QuestionBasicInfoForm';
@@ -3,9 +3,6 @@ import { fillInBlankRegistration } from '../types/fill-in-blank/register';
3
3
  import { arrangeLettersIntoWordsRegistration } from '../types/arrange-letters-into-words/register';
4
4
  import { writeShortParagraphRegistration } from '../types/write-short-paragraph/register';
5
5
  import { fillMissingWordsInGridRegistration } from '../types/fill-missing-words-in-grid/register';
6
- import { lookPictureChooseCorrectAnswerRegistration } from '../types/look-picture-choose-correct-answer/register';
7
- import { lookPictureFillBlankChooseAnswerRegistration } from '../types/look-picture-fill-blank-choose-answer/register';
8
- import { lookPictureFillWordHintRegistration } from '../types/look-picture-fill-word-hint/register';
9
6
  import { labelThePictureRegistration } from '../types/label-the-picture/register';
10
7
  import { readAndColorObjectsRegistration } from '../types/read-and-color-objects/register';
11
8
  import { imageObjectMatchingRegistration } from '../types/image-object-matching/register';
@@ -44,7 +41,6 @@ import { spontaneousQARegistration } from '../types/spontaneous-qa/register';
44
41
  import { spontaneousQaGroupRegistration } from '../types/spontaneous-qa-group/register';
45
42
  import { readDisplayedContentRegistration } from '../types/read-displayed-content/register';
46
43
  import { speakingConversationRegistration } from '../types/speaking-conversation/register';
47
- import { gnSpeakingInterviewRegistration } from '../types/gn-speaking-interview/register';
48
44
  import { speakingCueCardRegistration } from '../types/speaking-cue-card/register';
49
45
  import { wordFillStructuredFormRegistration } from '../types/word-fill-structured-form/register';
50
46
  import { wordOrderAndMatchGroupRegistration } from '../types/word-order-and-match-group/register';
@@ -68,9 +64,6 @@ export const questionTypeRegistry = {
68
64
  ARRANGE_LETTERS_INTO_WORDS: arrangeLettersIntoWordsRegistration,
69
65
  WRITE_SHORT_PARAGRAPH: writeShortParagraphRegistration,
70
66
  FILL_MISSING_WORDS_IN_GRID: fillMissingWordsInGridRegistration,
71
- LOOK_PICTURE_CHOOSE_CORRECT_ANSWER: lookPictureChooseCorrectAnswerRegistration,
72
- LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER: lookPictureFillBlankChooseAnswerRegistration,
73
- LOOK_PICTURE_FILL_WORD_HINT: lookPictureFillWordHintRegistration,
74
67
  LABEL_THE_PICTURE: labelThePictureRegistration,
75
68
  READ_AND_COLOR_OBJECTS: readAndColorObjectsRegistration,
76
69
  IMAGE_OBJECT_MATCHING: imageObjectMatchingRegistration,
@@ -102,7 +95,6 @@ export const questionTypeRegistry = {
102
95
  SPONTANEOUS_QA_GROUP: spontaneousQaGroupRegistration,
103
96
  READ_DISPLAYED_CONTENT: readDisplayedContentRegistration,
104
97
  SPEAKING_CONVERSATION: speakingConversationRegistration,
105
- GN_SPEAKING_INTERVIEW: gnSpeakingInterviewRegistration,
106
98
  SPEAKING_CUE_CARD: speakingCueCardRegistration,
107
99
  WORD_FILL_STRUCTURED_FORM: wordFillStructuredFormRegistration,
108
100
  CROSSWORD_PUZZLE: crosswordPuzzleRegistration,
@@ -114,8 +114,8 @@ export function ArticlesGroupCard({ groupNumber, articleCount, articles, onArtic
114
114
  const updated = displayArticles.filter((_, i) => i !== index);
115
115
  onArticlesChange(updated);
116
116
  };
117
- return (_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-teal-100/50", children: [_jsx("div", { className: "h-1.5 bg-gradient-to-r from-teal-500 via-emerald-500 to-green-500" }), _jsx(CardHeader, { className: "pb-4", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-teal-500 to-emerald-600 shadow-md", children: _jsx(Layers, { className: "h-5 w-5 text-white" }) }), _jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-lg font-bold text-gray-900", children: "B\u00E0i vi\u1EBFt nh\u00F3m" }), _jsxs("span", { className: "inline-flex items-center rounded-full border border-teal-300 bg-teal-100 px-2.5 py-0.5 text-xs font-semibold text-teal-700", children: ["Nh\u00F3m ", groupNumber] }), _jsxs("span", { className: "inline-flex items-center rounded-full border border-emerald-200 bg-emerald-50 px-2.5 py-0.5 text-xs font-medium text-emerald-600", children: [articles.length || articleCount, " b\u00E0i vi\u1EBFt"] })] }), _jsxs("p", { className: "text-sm text-gray-500", children: ["Nh\u1EADp n\u1ED9i dung t\u1EEBng b\u00E0i vi\u1EBFt \u2014 d\u00F9ng chung cho t\u1EA5t c\u1EA3 c\u00E2u h\u1ECFi trong Nh\u00F3m ", groupNumber, ". B\u1EA1n c\u00F3 th\u1EC3 th\u00EAm ho\u1EB7c x\u00F3a b\u00E0i vi\u1EBFt."] })] })] }) }), _jsxs(CardContent, { className: "space-y-5", children: [_jsxs("div", { className: "space-y-2 pb-2", children: [_jsxs(Label, { htmlFor: `${uploadIdPrefix}-title`, className: "flex items-center gap-2 text-sm font-semibold text-gray-800", children: [_jsx(Type, { className: "h-4 w-4 text-teal-500" }), "Ti\u00EAu \u0111\u1EC1 nh\u00F3m b\u00E0i vi\u1EBFt", ' ', _jsx("span", { className: "text-xs font-normal text-gray-500", children: "(T\u00F9y ch\u1ECDn)" })] }), _jsx(Input, { id: `${uploadIdPrefix}-title`, value: title, onChange: (e) => onTitleChange?.(e.target.value), placeholder: "Nh\u1EADp ti\u00EAu \u0111\u1EC1 chung cho nh\u00F3m b\u00E0i vi\u1EBFt\u2026", readOnly: isReadOnly, className: `border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-200 ${isReadOnly ? 'bg-gray-50 text-gray-500 cursor-not-allowed border-transparent focus:border-transparent focus:ring-0' : ''}` })] }), displayArticles.map((article, index) => {
117
+ return (_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-sm", children: [_jsx(CardHeader, { className: "px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-gray-100", children: _jsx(Layers, { className: "h-3.5 w-3.5 text-gray-600" }) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-sm font-bold text-gray-900", children: "B\u00E0i vi\u1EBFt nh\u00F3m" }), _jsxs("span", { className: "inline-flex items-center rounded-md border border-gray-200 bg-gray-50 px-2 py-0.5 text-xs font-semibold text-gray-600", children: ["Nh\u00F3m ", groupNumber] }), _jsxs("span", { className: "inline-flex items-center rounded-md border border-emerald-200 bg-emerald-50 px-2 py-0.5 text-xs font-medium text-emerald-600", children: [articles.length || articleCount, " b\u00E0i vi\u1EBFt"] })] })] }) }), _jsxs(CardContent, { className: "space-y-2.5 px-3 pb-3", children: [_jsxs("div", { className: "space-y-2 pb-2", children: [_jsxs(Label, { htmlFor: `${uploadIdPrefix}-title`, className: "flex items-center gap-2 text-sm font-semibold text-gray-800", children: [_jsx(Type, { className: "h-4 w-4 text-teal-500" }), "Ti\u00EAu \u0111\u1EC1 nh\u00F3m b\u00E0i vi\u1EBFt", ' ', _jsx("span", { className: "text-xs font-normal text-gray-500", children: "(T\u00F9y ch\u1ECDn)" })] }), _jsx(Input, { id: `${uploadIdPrefix}-title`, value: title, onChange: (e) => onTitleChange?.(e.target.value), placeholder: "Nh\u1EADp ti\u00EAu \u0111\u1EC1 chung cho nh\u00F3m b\u00E0i vi\u1EBFt\u2026", readOnly: isReadOnly, className: `border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-200 ${isReadOnly ? 'bg-gray-50 text-gray-500 cursor-not-allowed border-transparent focus:border-transparent focus:ring-0' : ''}` })] }), displayArticles.map((article, index) => {
118
118
  const letter = String.fromCharCode(65 + index); // A, B, C...
119
- return (_jsxs("div", { className: "rounded-xl border-2 border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4 transition-all hover:border-teal-200 hover:shadow-sm", children: [_jsxs("div", { className: "mb-3 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-teal-500 to-emerald-600 text-sm font-bold text-white shadow-sm", children: letter }), _jsxs("span", { className: "text-sm font-semibold text-gray-700", children: ["B\u00E0i vi\u1EBFt ", index + 1] })] }), displayArticles.length > 1 && !isReadOnly && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => handleDeleteArticle(index), className: "h-8 w-8 p-0 text-red-500 hover:bg-red-50 hover:text-red-600", title: "X\u00F3a b\u00E0i vi\u1EBFt", children: _jsx(Trash2, { className: "h-4 w-4" }) }))] }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { htmlFor: `${uploadIdPrefix}-name-${index}`, className: "flex items-center gap-1.5 text-sm font-medium text-gray-700", children: [_jsx(Type, { className: "h-3.5 w-3.5 text-teal-500" }), "T\u00EAn ng\u01B0\u1EDDi / ti\u00EAu \u0111\u1EC1"] }), _jsx(Input, { id: `${uploadIdPrefix}-name-${index}`, value: article.name, onChange: (e) => handleFieldChange(index, 'name', e.target.value), placeholder: `VD: Ariel, Clive, Vicky...`, readOnly: isReadOnly, className: `border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-200 ${isReadOnly ? 'bg-gray-50 text-gray-500 cursor-not-allowed border-transparent focus:border-transparent focus:ring-0' : ''}` })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { className: "flex items-center gap-1.5 text-sm font-medium text-gray-700", children: [_jsx(FileText, { className: "h-3.5 w-3.5 text-teal-500" }), "N\u1ED9i dung b\u00E0i vi\u1EBFt"] }), _jsx(ArticleEditor, { value: article.content, onChange: (html) => handleFieldChange(index, 'content', html), isReadOnly: isReadOnly })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { className: "flex items-center gap-1.5 text-sm font-medium text-gray-700", children: [_jsx(ImageIcon, { className: "h-3.5 w-3.5 text-teal-500" }), "H\u00ECnh \u1EA3nh", ' ', _jsx("span", { className: "text-xs font-normal text-gray-400", children: "(T\u00F9y ch\u1ECDn)" })] }), !isReadOnly && (_jsx(FileUpload, { id: `${uploadIdPrefix}-image-${index}`, label: "", accept: "image/*", value: article.imageUrl, onChange: (url) => handleFieldChange(index, 'imageUrl', url), maxSize: 5, placeholder: "Upload \u1EA3nh ho\u1EB7c paste URL", autoUpload: true, prefix: "questions" })), article.imageUrl && (_jsx(ArticleImagePreview, { src: article.imageUrl, alt: `Article ${letter} image` }))] })] })] }, index));
119
+ return (_jsxs("div", { className: "rounded-md border border-gray-200 bg-white p-3 transition-all hover:border-gray-300 hover:shadow-sm", children: [_jsxs("div", { className: "mb-3 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-teal-500 to-emerald-600 text-sm font-bold text-white shadow-sm", children: letter }), _jsxs("span", { className: "text-sm font-semibold text-gray-700", children: ["B\u00E0i vi\u1EBFt ", index + 1] })] }), displayArticles.length > 1 && !isReadOnly && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => handleDeleteArticle(index), className: "h-8 w-8 p-0 text-red-500 hover:bg-red-50 hover:text-red-600", title: "X\u00F3a b\u00E0i vi\u1EBFt", children: _jsx(Trash2, { className: "h-4 w-4" }) }))] }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { htmlFor: `${uploadIdPrefix}-name-${index}`, className: "flex items-center gap-1.5 text-sm font-medium text-gray-700", children: [_jsx(Type, { className: "h-3.5 w-3.5 text-teal-500" }), "T\u00EAn ng\u01B0\u1EDDi / ti\u00EAu \u0111\u1EC1"] }), _jsx(Input, { id: `${uploadIdPrefix}-name-${index}`, value: article.name, onChange: (e) => handleFieldChange(index, 'name', e.target.value), placeholder: `VD: Ariel, Clive, Vicky...`, readOnly: isReadOnly, className: `border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-200 ${isReadOnly ? 'bg-gray-50 text-gray-500 cursor-not-allowed border-transparent focus:border-transparent focus:ring-0' : ''}` })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { className: "flex items-center gap-1.5 text-sm font-medium text-gray-700", children: [_jsx(FileText, { className: "h-3.5 w-3.5 text-teal-500" }), "N\u1ED9i dung b\u00E0i vi\u1EBFt"] }), _jsx(ArticleEditor, { value: article.content, onChange: (html) => handleFieldChange(index, 'content', html), isReadOnly: isReadOnly })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { className: "flex items-center gap-1.5 text-sm font-medium text-gray-700", children: [_jsx(ImageIcon, { className: "h-3.5 w-3.5 text-teal-500" }), "H\u00ECnh \u1EA3nh", ' ', _jsx("span", { className: "text-xs font-normal text-gray-400", children: "(T\u00F9y ch\u1ECDn)" })] }), !isReadOnly && (_jsx(FileUpload, { id: `${uploadIdPrefix}-image-${index}`, label: "", accept: "image/*", value: article.imageUrl, onChange: (url) => handleFieldChange(index, 'imageUrl', url), maxSize: 5, placeholder: "Upload \u1EA3nh ho\u1EB7c paste URL", autoUpload: true, prefix: "questions" })), article.imageUrl && (_jsx(ArticleImagePreview, { src: article.imageUrl, alt: `Article ${letter} image` }))] })] })] }, index));
120
120
  }), !isReadOnly && (_jsxs(Button, { type: "button", variant: "outline", className: "w-full border-dashed border-teal-300 bg-teal-50/50 text-teal-700 hover:bg-teal-50 hover:text-teal-800 hover:border-teal-400", onClick: handleAddArticle, children: [_jsx(PlusCircle, { className: "mr-2 h-4 w-4" }), "Th\u00EAm b\u00E0i vi\u1EBFt"] }))] })] }));
121
121
  }
@@ -34,7 +34,7 @@ export function BasicQuestionGroupCard({ groupNumber, title, subtitle, content,
34
34
  // Resolve presigned preview URL for the stored image key
35
35
  const { previewUrl } = usePresignedFileUrl(imageUrl);
36
36
  const displayPreviewUrl = previewUrl || '';
37
- return (_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-purple-100/50", children: [_jsx("div", { className: "h-1.5 bg-gradient-to-r from-purple-500 via-violet-500 to-indigo-500" }), _jsx(CardHeader, { className: "pb-4", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-purple-500 to-violet-600 shadow-md", children: _jsx(Layers, { className: "h-5 w-5 text-white" }) }), _jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-lg font-bold text-gray-900", children: "D\u1EEF li\u1EC7u nh\u00F3m" }), _jsxs("span", { className: "inline-flex items-center rounded-full border border-purple-300 bg-purple-100 px-2.5 py-0.5 text-xs font-semibold text-purple-700", children: ["Nh\u00F3m ", groupNumber] })] }), _jsxs("p", { className: "text-sm text-gray-500", children: ["D\u00F9ng chung cho t\u1EA5t c\u1EA3 c\u00E2u h\u1ECFi trong Nh\u00F3m ", groupNumber] })] })] }) }), _jsxs(CardContent, { className: "space-y-5", children: [showTitle && (_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { htmlFor: `${uploadIdPrefix}-title`, className: "flex items-center gap-2 text-sm font-semibold text-gray-800", children: [_jsx(Type, { className: "h-4 w-4 text-purple-500" }), "Ti\u00EAu \u0111\u1EC1 nh\u00F3m", ' ', _jsx("span", { className: "text-xs font-normal text-gray-500", children: "(T\u00F9y ch\u1ECDn)" })] }), _jsx(Input, { id: `${uploadIdPrefix}-title`, value: title, onChange: (e) => {
37
+ return (_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-sm", children: [_jsx(CardHeader, { className: "px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-gray-100", children: _jsx(Layers, { className: "h-3.5 w-3.5 text-gray-600" }) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-sm font-bold text-gray-900", children: "D\u1EEF li\u1EC7u nh\u00F3m" }), _jsxs("span", { className: "inline-flex items-center rounded-md border border-gray-200 bg-gray-50 px-2 py-0.5 text-xs font-semibold text-gray-600", children: ["Nh\u00F3m ", groupNumber] })] })] }) }), _jsxs(CardContent, { className: "space-y-2.5 px-3 pb-3", children: [showTitle && (_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { htmlFor: `${uploadIdPrefix}-title`, className: "flex items-center gap-2 text-sm font-semibold text-gray-800", children: [_jsx(Type, { className: "h-4 w-4 text-purple-500" }), "Ti\u00EAu \u0111\u1EC1 nh\u00F3m", ' ', _jsx("span", { className: "text-xs font-normal text-gray-500", children: "(T\u00F9y ch\u1ECDn)" })] }), _jsx(Input, { id: `${uploadIdPrefix}-title`, value: title, onChange: (e) => {
38
38
  if (!isReadOnly)
39
39
  onTitleChange(e.target.value);
40
40
  }, readOnly: isReadOnly, placeholder: "Nh\u1EADp ti\u00EAu \u0111\u1EC1 nh\u00F3m c\u00E2u h\u1ECFi\u2026", className: `border-gray-200 bg-white transition-all focus:border-purple-300 focus:ring-purple-200 ${isReadOnly ? 'bg-gray-50 text-gray-500 cursor-not-allowed border-transparent focus:border-transparent focus:ring-0' : ''}` })] })), showSubtitle && (_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { htmlFor: `${uploadIdPrefix}-subtitle`, className: "flex items-center gap-2 text-sm font-semibold text-gray-800", children: [_jsx(Type, { className: "h-4 w-4 text-purple-500" }), "Ph\u1EE5 \u0111\u1EC1 nh\u00F3m", ' ', _jsx("span", { className: "text-xs font-normal text-gray-500", children: "(T\u00F9y ch\u1ECDn)" })] }), _jsx(Input, { id: `${uploadIdPrefix}-subtitle`, value: subtitle, onChange: (e) => {