@tinyweb_dev/oe-exam-sdk 0.1.26 → 0.1.28

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 (146) hide show
  1. package/README.md +79 -5
  2. package/dist/components/exams/ExamPreviewDialog.d.ts +7 -6
  3. package/dist/components/exams/ExamPreviewDialog.js +1 -1
  4. package/dist/components/exams/index.d.ts +0 -1
  5. package/dist/components/exams/take/components/QuestionRenderer.js +1 -1
  6. package/dist/components/exams/take/components/question-renderers/MoversListenAndWriteRenderer.js +1 -1
  7. package/dist/components/exams/take/components/question-renderers/MoversWordFillStructuredFormRenderer.js +1 -1
  8. package/dist/components/exams/take/exam-taking.utils.d.ts +0 -13
  9. package/dist/components/exams/take/exam-taking.utils.js +1 -1
  10. package/dist/components/exams/take/utils/answer-transformers.js +1 -1
  11. package/dist/components/exams/take/utils/question-transformers.d.ts +7 -17
  12. package/dist/components/exams/take/utils/question-transformers.js +1 -1
  13. package/dist/components/questions/_shared/config/question-types.config.js +1 -1
  14. package/dist/components/questions/_shared/types/choose-the-correct-answer-group.type.d.ts +36 -0
  15. package/dist/components/questions/_shared/types/cross-out-word-group.type.d.ts +40 -0
  16. package/dist/components/questions/_shared/types/index.d.ts +1 -0
  17. package/dist/components/questions/_shared/types/index.js +1 -1
  18. package/dist/components/questions/_shared/types/true-false-group.type.d.ts +31 -0
  19. package/dist/components/questions/_shared/types/true-false-group.type.js +1 -0
  20. package/dist/components/questions/_shared/types/word-fill-structured-form.type.d.ts +11 -17
  21. package/dist/components/questions/creator/question-type-registry.js +1 -1
  22. package/dist/components/questions/index.d.ts +0 -1
  23. package/dist/components/questions/index.js +1 -1
  24. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupClient.d.ts +2 -0
  25. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupClient.js +1 -0
  26. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupCreator.d.ts +2 -0
  27. package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupCreator.js +1 -0
  28. package/dist/components/questions/types/choose-the-correct-answer-group/index.d.ts +3 -0
  29. package/dist/components/questions/types/choose-the-correct-answer-group/index.js +1 -0
  30. package/dist/components/questions/types/choose-the-correct-answer-group/map-choose-the-correct-answer-group-data.d.ts +4 -0
  31. package/dist/components/questions/types/choose-the-correct-answer-group/map-choose-the-correct-answer-group-data.js +1 -0
  32. package/dist/components/questions/types/choose-the-correct-answer-group/register.d.ts +2 -0
  33. package/dist/components/questions/types/choose-the-correct-answer-group/register.js +1 -0
  34. package/dist/components/questions/types/choose-the-correct-answer-group/transform.d.ts +2 -0
  35. package/dist/components/questions/types/choose-the-correct-answer-group/transform.js +1 -0
  36. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupClient.d.ts +2 -0
  37. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupClient.js +1 -0
  38. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupCreator.d.ts +2 -0
  39. package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupCreator.js +1 -0
  40. package/dist/components/questions/types/cross-out-word-group/index.d.ts +5 -0
  41. package/dist/components/questions/types/cross-out-word-group/index.js +1 -0
  42. package/dist/components/questions/types/cross-out-word-group/map-cross-out-word-group-data.d.ts +6 -0
  43. package/dist/components/questions/types/cross-out-word-group/map-cross-out-word-group-data.js +1 -0
  44. package/dist/components/questions/types/cross-out-word-group/register.d.ts +2 -0
  45. package/dist/components/questions/types/cross-out-word-group/register.js +1 -0
  46. package/dist/components/questions/types/cross-out-word-group/transform.d.ts +2 -0
  47. package/dist/components/questions/types/cross-out-word-group/transform.js +1 -0
  48. package/dist/components/questions/types/true-false-group/TrueFalseGroupClient.d.ts +2 -0
  49. package/dist/components/questions/types/true-false-group/TrueFalseGroupClient.js +1 -0
  50. package/dist/components/questions/types/true-false-group/TrueFalseGroupCreator.d.ts +2 -0
  51. package/dist/components/questions/types/true-false-group/TrueFalseGroupCreator.js +1 -0
  52. package/dist/components/questions/types/true-false-group/index.d.ts +5 -0
  53. package/dist/components/questions/types/true-false-group/index.js +1 -0
  54. package/dist/components/questions/types/true-false-group/map-true-false-group-data.d.ts +4 -0
  55. package/dist/components/questions/types/true-false-group/map-true-false-group-data.js +1 -0
  56. package/dist/components/questions/types/true-false-group/register.d.ts +2 -0
  57. package/dist/components/questions/types/true-false-group/register.js +1 -0
  58. package/dist/components/questions/types/true-false-group/transform.d.ts +2 -0
  59. package/dist/components/questions/types/true-false-group/transform.js +1 -0
  60. package/dist/components/questions/types/word-fill-structured-form/index.d.ts +1 -0
  61. package/dist/components/questions/types/word-fill-structured-form/index.js +1 -1
  62. package/dist/components/questions/types/word-fill-structured-form/map-wfsf-question-data.d.ts +7 -0
  63. package/dist/components/questions/types/word-fill-structured-form/map-wfsf-question-data.js +1 -0
  64. package/dist/components/questions/types/word-fill-structured-form/register.js +1 -1
  65. package/dist/components/questions/types/word-fill-structured-form/transform.js +1 -1
  66. package/dist/components/questions/viewer/ChooseTheCorrectAnswerGroupViewer.d.ts +8 -0
  67. package/dist/components/questions/viewer/ChooseTheCorrectAnswerGroupViewer.js +1 -0
  68. package/dist/components/questions/viewer/CrossOutWordGroupViewer.d.ts +7 -0
  69. package/dist/components/questions/viewer/CrossOutWordGroupViewer.js +1 -0
  70. package/dist/components/questions/viewer/QuestionViewer.js +1 -1
  71. package/dist/components/questions/viewer/SpontaneousQaGroupViewer.d.ts +4 -0
  72. package/dist/components/questions/viewer/SpontaneousQaGroupViewer.js +1 -0
  73. package/dist/components/questions/viewer/TrueFalseGroupViewer.d.ts +8 -0
  74. package/dist/components/questions/viewer/TrueFalseGroupViewer.js +1 -0
  75. package/dist/components/questions/viewer/WordFillStructuredFormViewer.d.ts +9 -0
  76. package/dist/components/questions/viewer/WordFillStructuredFormViewer.js +1 -0
  77. package/dist/components/questions/viewer/WordOrderAndMatchGroupViewer.d.ts +4 -0
  78. package/dist/components/questions/viewer/WordOrderAndMatchGroupViewer.js +1 -0
  79. package/dist/components/questions/viewer/index.d.ts +6 -0
  80. package/dist/components/questions/viewer/index.js +1 -1
  81. package/dist/components/results/renderers/review-question-body-dedicated.js +1 -1
  82. package/dist/components/results/review-data.js +1 -1
  83. package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -1
  84. package/dist/index.d.ts +0 -2
  85. package/dist/index.js +1 -1
  86. package/dist/mcp/config.d.ts +12 -0
  87. package/dist/mcp/config.js +1 -0
  88. package/dist/mcp/http-client.d.ts +6 -0
  89. package/dist/mcp/http-client.js +1 -0
  90. package/dist/mcp/index.d.ts +6 -0
  91. package/dist/mcp/index.js +2 -0
  92. package/dist/mcp/tools/_helpers.d.ts +4 -0
  93. package/dist/mcp/tools/_helpers.js +1 -0
  94. package/dist/mcp/tools/exams.d.ts +2 -0
  95. package/dist/mcp/tools/exams.js +1 -0
  96. package/dist/mcp/tools/index.d.ts +2 -0
  97. package/dist/mcp/tools/index.js +1 -0
  98. package/dist/mcp/tools/results.d.ts +2 -0
  99. package/dist/mcp/tools/results.js +1 -0
  100. package/dist/shared/constants/question-skills.js +1 -1
  101. package/dist/shared/lib/i18n/messages/en/admin.d.ts +4 -11
  102. package/dist/shared/lib/i18n/messages/en/admin.js +1 -1
  103. package/dist/shared/lib/i18n/messages/en.d.ts +4 -11
  104. package/dist/shared/lib/i18n/messages/vi/admin.d.ts +4 -11
  105. package/dist/shared/lib/i18n/messages/vi/admin.js +1 -1
  106. package/dist/shared/lib/i18n/messages/vi.d.ts +4 -11
  107. package/dist/shared/lib/utils/question-reverse-transform.js +1 -1
  108. package/dist/shared/lib/utils/question-transform.js +1 -1
  109. package/dist/shared/types/common.types.d.ts +1 -1
  110. package/dist/shared/types/questions/choose-the-correct-answer-group.d.ts +41 -0
  111. package/dist/shared/types/questions/choose-the-correct-answer-group.js +1 -0
  112. package/dist/shared/types/questions/cross-out-word-group.d.ts +41 -0
  113. package/dist/shared/types/questions/cross-out-word-group.js +1 -0
  114. package/dist/shared/types/questions/index.d.ts +2 -0
  115. package/dist/shared/types/questions/index.js +1 -1
  116. package/package.json +166 -169
  117. package/dist/components/exams/ExamPreviewPartContent.d.ts +0 -18
  118. package/dist/components/exams/ExamPreviewPartContent.js +0 -1
  119. package/dist/components/exams/ExamPreviewSidebar.d.ts +0 -17
  120. package/dist/components/exams/ExamPreviewSidebar.js +0 -1
  121. package/dist/components/exams/exam-preview.types.d.ts +0 -34
  122. package/dist/components/exams/exam-preview.types.js +0 -1
  123. package/dist/components/questions/_shared/utils/parseFillBlankStem.d.ts +0 -30
  124. package/dist/components/questions/_shared/utils/parseFillBlankStem.js +0 -1
  125. package/dist/components/questions/question-bank/EditQuestionBankDialog.d.ts +0 -2
  126. package/dist/components/questions/question-bank/EditQuestionBankDialog.js +0 -1
  127. package/dist/components/questions/question-bank/QuestionEditorRenderer.d.ts +0 -23
  128. package/dist/components/questions/question-bank/QuestionEditorRenderer.js +0 -1
  129. package/dist/components/questions/question-bank/difficulty.d.ts +0 -15
  130. package/dist/components/questions/question-bank/difficulty.js +0 -1
  131. package/dist/components/questions/question-bank/editor-adapters/choice-adapters.d.ts +0 -5
  132. package/dist/components/questions/question-bank/editor-adapters/choice-adapters.js +0 -1
  133. package/dist/components/questions/question-bank/editor-adapters/index.d.ts +0 -5
  134. package/dist/components/questions/question-bank/editor-adapters/index.js +0 -1
  135. package/dist/components/questions/question-bank/editor-adapters/media-adapters.d.ts +0 -6
  136. package/dist/components/questions/question-bank/editor-adapters/media-adapters.js +0 -1
  137. package/dist/components/questions/question-bank/editor-adapters/types.d.ts +0 -1
  138. package/dist/components/questions/question-bank/editor-adapters/unsupported-fallback.d.ts +0 -8
  139. package/dist/components/questions/question-bank/editor-adapters/unsupported-fallback.js +0 -1
  140. package/dist/components/questions/question-bank/editor-adapters/writing-adapters.d.ts +0 -5
  141. package/dist/components/questions/question-bank/editor-adapters/writing-adapters.js +0 -1
  142. package/dist/components/questions/question-bank/index.d.ts +0 -4
  143. package/dist/components/questions/question-bank/index.js +0 -1
  144. package/dist/components/questions/question-bank/types.d.ts +0 -59
  145. /package/dist/components/questions/{question-bank/editor-adapters/types.js → _shared/types/choose-the-correct-answer-group.type.js} +0 -0
  146. /package/dist/components/questions/{question-bank/types.js → _shared/types/cross-out-word-group.type.js} +0 -0
@@ -1 +1 @@
1
- export const QUESTION_TYPE_CONFIG={FILL_IN_BLANK:{label:"Điền vào chỗ trống",requiresContent:!0,hasDedicatedComponent:!0},TRUE_FALSE:{label:"Đúng/Sai",requiresContent:!0,hasDedicatedComponent:!0},MATCHING:{label:"Nối",requiresContent:!0,hasDedicatedComponent:!1},ORDERING:{label:"Sắp xếp",requiresContent:!0,hasDedicatedComponent:!1},LISTENING:{label:"Nghe",requiresContent:!0,hasDedicatedComponent:!1},COLORING:{label:"Tô màu",requiresContent:!0,hasDedicatedComponent:!1},ESSAY:{label:"Viết luận",requiresContent:!0,hasDedicatedComponent:!1},LISTEN_AND_FILL_IN_THE_BLANK_WITH_IMAGE:{label:"Nghe - Điền chỗ trống",requiresContent:!0,hasDedicatedComponent:!1},LISTEN_AND_TICK_ANSWER:{label:"Nghe - Tick đáp án",requiresContent:!0,hasDedicatedComponent:!1},LISTEN_AND_FILL_NAME_NUMBER:{label:"Nghe - Điền tên/số",requiresContent:!0,hasDedicatedComponent:!1},TICK_TRUE_OR_FALSE:{label:"Đọc - Tick/Cross",requiresContent:!0,hasDedicatedComponent:!1},TICK_YES_OR_NO:{label:"Đọc - Tick/Cross (Yes/No)",requiresContent:!0,hasDedicatedComponent:!1},READING_TICK_CROSS:{label:"Đọc - Tick/Cross (Reading)",requiresContent:!0,hasDedicatedComponent:!1},ARRANGE_LETTERS_INTO_WORDS:{label:"Đọc - Sắp xếp chữ cái",requiresContent:!0,hasDedicatedComponent:!0},READ_PASSAGE_AND_COMPLETE_STORY:{label:"Đọc - Điền vào đoạn văn",requiresContent:!0,hasDedicatedComponent:!1},READ_PASSAGE_AND_ANSWER_QUESTIONS:{label:"Đọc đoạn văn và trả lời câu hỏi",requiresContent:!0,hasDedicatedComponent:!0},CLOZE_TEST_WITH_TICK_BOX:{label:"Cloze test với tick box",requiresContent:!0,hasDedicatedComponent:!1},READ_AND_CHOOSE_APPROPRIATE_WORD:{label:"Đọc - Chọn từ phù hợp",requiresContent:!0,hasDedicatedComponent:!1},WRITE_SHORT_PARAGRAPH:{label:"Viết - Đoạn văn ngắn",requiresContent:!0,hasDedicatedComponent:!0},FILL_MISSING_WORDS_IN_GRID:{label:"Điền từ còn thiếu vào grid",requiresContent:!0,hasDedicatedComponent:!0},LOOK_PICTURE_CHOOSE_CORRECT_ANSWER:{label:"Nhìn tranh, chọn đáp án đúng",requiresContent:!0,hasDedicatedComponent:!0},LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER:{label:"Nhìn tranh, điền chỗ trống, chọn đáp án",requiresContent:!0,hasDedicatedComponent:!0},LOOK_PICTURE_FILL_WORD_HINT:{label:"Nhìn tranh điền từ gợi ý",requiresContent:!0,hasDedicatedComponent:!0},LABEL_THE_PICTURE:{label:"Label the Picture",requiresContent:!0,hasDedicatedComponent:!0},READ_AND_COLOR_OBJECTS:{label:"Read and Color Objects",requiresContent:!0,hasDedicatedComponent:!0},IMAGE_OBJECT_MATCHING:{label:"Image Object Matching",requiresContent:!0,hasDedicatedComponent:!0},LISTENING_FILL_BLANK:{label:"Nghe - Điền vào chỗ trống",requiresContent:!0,hasDedicatedComponent:!1},LISTENING_COLOR:{label:"Nghe - Tô màu",requiresContent:!0,hasDedicatedComponent:!1},READING_LETTER_ARRANGE:{label:"Đọc - Sắp xếp chữ cái",requiresContent:!0,hasDedicatedComponent:!1},READING_PASSAGE_FILL:{label:"Đọc - Điền vào đoạn văn",requiresContent:!0,hasDedicatedComponent:!1},FILL_BLANK:{label:"Điền vào chỗ trống",requiresContent:!0,hasDedicatedComponent:!1},CHOOSE_THE_CORRECT_ANSWER:{label:"Choose the correct answer",requiresContent:!1,hasDedicatedComponent:!0},WRITE_A_SHORT_LETTER:{label:"Write a Short Letter",requiresContent:!0,hasDedicatedComponent:!0},WRITE_CORRECT_VERB_FORM:{label:"Viết dạng đúng của động từ",requiresContent:!0,hasDedicatedComponent:!0},CHOOSE_CORRECT_ADJECTIVE:{label:"Chọn dạng đúng của tính từ",requiresContent:!0,hasDedicatedComponent:!0},ANSWER_THE_QUESTION:{label:"Nghe - Đọc câu hỏi và viết đáp án",requiresContent:!0,hasDedicatedComponent:!0},WORD_ORDERING:{label:"Sắp xếp từ",requiresContent:!0,hasDedicatedComponent:!0},WORD_FILL_PARAGRAPH:{label:"Điền từ vào đoạn văn",requiresContent:!0,hasDedicatedComponent:!0},MATCH_BY_WRITING_ANSWER:{label:"Ghép đáp án bằng cách viết",requiresContent:!0,hasDedicatedComponent:!0},WRITE_SENTENCES:{label:"Viết câu",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP:{label:"Nghe và chọn trong nhóm đáp án",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE:{label:"Nghe và chọn đối tượng trong cảnh",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_DRAG_OBJECTS_INTO_SCENE:{label:"Nghe và kéo thả đối tượng vào cảnh",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_ANSWER:{label:"Nghe và trả lời (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_IMAGE_GROUP:{label:"Nghe, nhìn nhóm ảnh và trả lời (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_QUESTION_LIST:{label:"Nghe, chọn câu hỏi và trả lời (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_COMPARE_IMAGES:{label:"Nghe và So sánh điểm khác biệt (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_WITH_STORY_IMAGES:{label:"Nghe, nhìn ảnh truyện và kể lại (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_ODD_ONE_OUT:{label:"Nghe, chọn hình khác loại và giải thích (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_INFO_EXCHANGE:{label:"Trao đổi thông tin (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},READ_DISPLAYED_CONTENT:{label:"Đọc nội dung hiển thị (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},SPEAKING_DESCRIBE_IMAGE:{label:"Nhìn tranh mô tả (Speaking Part 2)",requiresContent:!0,hasDedicatedComponent:!0},SPONTANEOUS_QA:{label:"Hỏi đáp tự phát (Speaking Part 3)",requiresContent:!0,hasDedicatedComponent:!0},SPEAKING_CONVERSATION:{label:"Hội thoại Speaking (KFS Speaking)",requiresContent:!0,hasDedicatedComponent:!0},GN_SPEAKING_INTERVIEW:{label:"GN Speaking - Hỏi đáp (Virtual + Real)",requiresContent:!0,hasDedicatedComponent:!0},SPEAKING_CUE_CARD:{label:"IELTS Cue Card (Speaking Part 2)",requiresContent:!0,hasDedicatedComponent:!0},WORD_FILL_STRUCTURED_FORM:{label:"Điền từ vào biểu mẫu có cấu trúc",requiresContent:!0,hasDedicatedComponent:!0}};export const QUESTION_TYPES_WITH_DEDICATED_COMPONENTS=["FILL_IN_BLANK","ARRANGE_LETTERS_INTO_WORDS","WRITE_SHORT_PARAGRAPH","FILL_MISSING_WORDS_IN_GRID","LOOK_PICTURE_CHOOSE_CORRECT_ANSWER","LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER","LOOK_PICTURE_FILL_WORD_HINT","LABEL_THE_PICTURE","READ_AND_COLOR_OBJECTS","IMAGE_OBJECT_MATCHING","READ_PASSAGE_AND_ANSWER_QUESTIONS","CHOOSE_THE_CORRECT_ANSWER","WRITE_A_SHORT_LETTER","WRITE_CORRECT_VERB_FORM","CHOOSE_CORRECT_ADJECTIVE","ANSWER_THE_QUESTION","TRUE_FALSE","WORD_ORDERING","WORD_FILL_PARAGRAPH","MATCH_BY_WRITING_ANSWER","WRITE_SENTENCES","LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP","LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE","LISTEN_AND_DRAG_OBJECTS_INTO_SCENE","LISTEN_AND_SPEAK_ANSWER","LISTEN_AND_SPEAK_IMAGE_GROUP","LISTEN_AND_SPEAK_QUESTION_LIST","LISTEN_AND_SPEAK_COMPARE_IMAGES","LISTEN_AND_SPEAK_WITH_STORY_IMAGES","LISTEN_AND_SPEAK_ODD_ONE_OUT","LISTEN_AND_SPEAK_INFO_EXCHANGE","READ_DISPLAYED_CONTENT","SPEAKING_DESCRIBE_IMAGE","SPONTANEOUS_QA","SPEAKING_CONVERSATION","GN_SPEAKING_INTERVIEW","SPEAKING_CUE_CARD","WORD_FILL_STRUCTURED_FORM"];export function getQuestionTypeLabel(e){return QUESTION_TYPE_CONFIG[e]?.label||e}
1
+ export const QUESTION_TYPE_CONFIG={FILL_IN_BLANK:{label:"Điền vào chỗ trống",requiresContent:!0,hasDedicatedComponent:!0},TRUE_FALSE:{label:"Đúng/Sai",requiresContent:!0,hasDedicatedComponent:!0},MATCHING:{label:"Nối",requiresContent:!0,hasDedicatedComponent:!1},ORDERING:{label:"Sắp xếp",requiresContent:!0,hasDedicatedComponent:!1},LISTENING:{label:"Nghe",requiresContent:!0,hasDedicatedComponent:!1},COLORING:{label:"Tô màu",requiresContent:!0,hasDedicatedComponent:!1},ESSAY:{label:"Viết luận",requiresContent:!0,hasDedicatedComponent:!1},LISTEN_AND_FILL_IN_THE_BLANK_WITH_IMAGE:{label:"Nghe - Điền chỗ trống",requiresContent:!0,hasDedicatedComponent:!1},LISTEN_AND_TICK_ANSWER:{label:"Nghe - Tick đáp án",requiresContent:!0,hasDedicatedComponent:!1},LISTEN_AND_FILL_NAME_NUMBER:{label:"Nghe - Điền tên/số",requiresContent:!0,hasDedicatedComponent:!1},TICK_TRUE_OR_FALSE:{label:"Đọc - Tick/Cross",requiresContent:!0,hasDedicatedComponent:!1},TICK_YES_OR_NO:{label:"Đọc - Tick/Cross (Yes/No)",requiresContent:!0,hasDedicatedComponent:!1},READING_TICK_CROSS:{label:"Đọc - Tick/Cross (Reading)",requiresContent:!0,hasDedicatedComponent:!1},ARRANGE_LETTERS_INTO_WORDS:{label:"Đọc - Sắp xếp chữ cái",requiresContent:!0,hasDedicatedComponent:!0},READ_PASSAGE_AND_COMPLETE_STORY:{label:"Đọc - Điền vào đoạn văn",requiresContent:!0,hasDedicatedComponent:!1},READ_PASSAGE_AND_ANSWER_QUESTIONS:{label:"Đọc đoạn văn và trả lời câu hỏi",requiresContent:!0,hasDedicatedComponent:!0},CLOZE_TEST_WITH_TICK_BOX:{label:"Cloze test với tick box",requiresContent:!0,hasDedicatedComponent:!1},READ_AND_CHOOSE_APPROPRIATE_WORD:{label:"Đọc - Chọn từ phù hợp",requiresContent:!0,hasDedicatedComponent:!1},WRITE_SHORT_PARAGRAPH:{label:"Viết - Đoạn văn ngắn",requiresContent:!0,hasDedicatedComponent:!0},FILL_MISSING_WORDS_IN_GRID:{label:"Điền từ còn thiếu vào grid",requiresContent:!0,hasDedicatedComponent:!0},LOOK_PICTURE_CHOOSE_CORRECT_ANSWER:{label:"Nhìn tranh, chọn đáp án đúng",requiresContent:!0,hasDedicatedComponent:!0},LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER:{label:"Nhìn tranh, điền chỗ trống, chọn đáp án",requiresContent:!0,hasDedicatedComponent:!0},LOOK_PICTURE_FILL_WORD_HINT:{label:"Nhìn tranh điền từ gợi ý",requiresContent:!0,hasDedicatedComponent:!0},LABEL_THE_PICTURE:{label:"Label the Picture",requiresContent:!0,hasDedicatedComponent:!0},READ_AND_COLOR_OBJECTS:{label:"Read and Color Objects",requiresContent:!0,hasDedicatedComponent:!0},IMAGE_OBJECT_MATCHING:{label:"Image Object Matching",requiresContent:!0,hasDedicatedComponent:!0},LISTENING_FILL_BLANK:{label:"Nghe - Điền vào chỗ trống",requiresContent:!0,hasDedicatedComponent:!1},LISTENING_COLOR:{label:"Nghe - Tô màu",requiresContent:!0,hasDedicatedComponent:!1},READING_LETTER_ARRANGE:{label:"Đọc - Sắp xếp chữ cái",requiresContent:!0,hasDedicatedComponent:!1},READING_PASSAGE_FILL:{label:"Đọc - Điền vào đoạn văn",requiresContent:!0,hasDedicatedComponent:!1},FILL_BLANK:{label:"Điền vào chỗ trống",requiresContent:!0,hasDedicatedComponent:!1},CHOOSE_THE_CORRECT_ANSWER:{label:"Choose the correct answer",requiresContent:!1,hasDedicatedComponent:!0},CHOOSE_THE_CORRECT_ANSWER_GROUP:{label:"Choose the correct answer (group)",requiresContent:!0,hasDedicatedComponent:!0},TRUE_FALSE_GROUP:{label:"Đúng/Sai (nhóm)",requiresContent:!0,hasDedicatedComponent:!0},CROSS_OUT_WORD_GROUP:{label:"Cross out word (group)",requiresContent:!0,hasDedicatedComponent:!0},SPONTANEOUS_QA_GROUP:{label:"Hỏi đáp tự phát (nhóm)",requiresContent:!0,hasDedicatedComponent:!1},WORD_ORDER_AND_MATCH_GROUP:{label:"Sắp xếp từ và nối nhãn (nhóm)",requiresContent:!0,hasDedicatedComponent:!1},WRITE_A_SHORT_LETTER:{label:"Write a Short Letter",requiresContent:!0,hasDedicatedComponent:!0},WRITE_CORRECT_VERB_FORM:{label:"Viết dạng đúng của động từ",requiresContent:!0,hasDedicatedComponent:!0},CHOOSE_CORRECT_ADJECTIVE:{label:"Chọn dạng đúng của tính từ",requiresContent:!0,hasDedicatedComponent:!0},ANSWER_THE_QUESTION:{label:"Nghe - Đọc câu hỏi và viết đáp án",requiresContent:!0,hasDedicatedComponent:!0},WORD_ORDERING:{label:"Sắp xếp từ",requiresContent:!0,hasDedicatedComponent:!0},WORD_FILL_PARAGRAPH:{label:"Điền từ vào đoạn văn",requiresContent:!0,hasDedicatedComponent:!0},MATCH_BY_WRITING_ANSWER:{label:"Ghép đáp án bằng cách viết",requiresContent:!0,hasDedicatedComponent:!0},WRITE_SENTENCES:{label:"Viết câu",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP:{label:"Nghe và chọn trong nhóm đáp án",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE:{label:"Nghe và chọn đối tượng trong cảnh",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_DRAG_OBJECTS_INTO_SCENE:{label:"Nghe và kéo thả đối tượng vào cảnh",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_ANSWER:{label:"Nghe và trả lời (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_IMAGE_GROUP:{label:"Nghe, nhìn nhóm ảnh và trả lời (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_QUESTION_LIST:{label:"Nghe, chọn câu hỏi và trả lời (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_COMPARE_IMAGES:{label:"Nghe và So sánh điểm khác biệt (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_WITH_STORY_IMAGES:{label:"Nghe, nhìn ảnh truyện và kể lại (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_ODD_ONE_OUT:{label:"Nghe, chọn hình khác loại và giải thích (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},LISTEN_AND_SPEAK_INFO_EXCHANGE:{label:"Trao đổi thông tin (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},READ_DISPLAYED_CONTENT:{label:"Đọc nội dung hiển thị (Speaking)",requiresContent:!0,hasDedicatedComponent:!0},SPEAKING_DESCRIBE_IMAGE:{label:"Nhìn tranh mô tả (Speaking Part 2)",requiresContent:!0,hasDedicatedComponent:!0},SPONTANEOUS_QA:{label:"Hỏi đáp tự phát (Speaking Part 3)",requiresContent:!0,hasDedicatedComponent:!0},SPEAKING_CONVERSATION:{label:"Hội thoại Speaking (KFS Speaking)",requiresContent:!0,hasDedicatedComponent:!0},GN_SPEAKING_INTERVIEW:{label:"GN Speaking - Hỏi đáp (Virtual + Real)",requiresContent:!0,hasDedicatedComponent:!0},SPEAKING_CUE_CARD:{label:"IELTS Cue Card (Speaking Part 2)",requiresContent:!0,hasDedicatedComponent:!0},WORD_FILL_STRUCTURED_FORM:{label:"Điền từ vào biểu mẫu có cấu trúc",requiresContent:!0,hasDedicatedComponent:!0}};export const QUESTION_TYPES_WITH_DEDICATED_COMPONENTS=["FILL_IN_BLANK","ARRANGE_LETTERS_INTO_WORDS","WRITE_SHORT_PARAGRAPH","FILL_MISSING_WORDS_IN_GRID","LOOK_PICTURE_CHOOSE_CORRECT_ANSWER","LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER","LOOK_PICTURE_FILL_WORD_HINT","LABEL_THE_PICTURE","READ_AND_COLOR_OBJECTS","IMAGE_OBJECT_MATCHING","READ_PASSAGE_AND_ANSWER_QUESTIONS","CHOOSE_THE_CORRECT_ANSWER","CHOOSE_THE_CORRECT_ANSWER_GROUP","TRUE_FALSE_GROUP","CROSS_OUT_WORD_GROUP","WRITE_A_SHORT_LETTER","WRITE_CORRECT_VERB_FORM","CHOOSE_CORRECT_ADJECTIVE","ANSWER_THE_QUESTION","TRUE_FALSE","WORD_ORDERING","WORD_FILL_PARAGRAPH","MATCH_BY_WRITING_ANSWER","WRITE_SENTENCES","LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP","LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE","LISTEN_AND_DRAG_OBJECTS_INTO_SCENE","LISTEN_AND_SPEAK_ANSWER","LISTEN_AND_SPEAK_IMAGE_GROUP","LISTEN_AND_SPEAK_QUESTION_LIST","LISTEN_AND_SPEAK_COMPARE_IMAGES","LISTEN_AND_SPEAK_WITH_STORY_IMAGES","LISTEN_AND_SPEAK_ODD_ONE_OUT","LISTEN_AND_SPEAK_INFO_EXCHANGE","READ_DISPLAYED_CONTENT","SPEAKING_DESCRIBE_IMAGE","SPONTANEOUS_QA","SPEAKING_CONVERSATION","GN_SPEAKING_INTERVIEW","SPEAKING_CUE_CARD","WORD_FILL_STRUCTURED_FORM"];export function getQuestionTypeLabel(e){return QUESTION_TYPE_CONFIG[e]?.label||e}
@@ -0,0 +1,36 @@
1
+ export interface ChooseTheCorrectAnswerGroupOptionData {
2
+ id: string;
3
+ text: string;
4
+ }
5
+ export interface ChooseTheCorrectAnswerGroupItemData {
6
+ question: string;
7
+ optionType: 'text' | 'image';
8
+ options: ChooseTheCorrectAnswerGroupOptionData[];
9
+ correctAnswer: string;
10
+ isExample?: boolean;
11
+ points: number;
12
+ questionNumber: number;
13
+ }
14
+ export interface ChooseTheCorrectAnswerGroupData {
15
+ instruction: string;
16
+ items: ChooseTheCorrectAnswerGroupItemData[];
17
+ explanation?: string;
18
+ points?: number;
19
+ }
20
+ export interface ChooseTheCorrectAnswerGroupCreatorProps {
21
+ initialData?: ChooseTheCorrectAnswerGroupData;
22
+ onSave?: (data: ChooseTheCorrectAnswerGroupData) => void;
23
+ onCancel?: () => void;
24
+ onChange?: (data: ChooseTheCorrectAnswerGroupData) => void;
25
+ externalErrors?: string[];
26
+ onUnsavedChangesChange?: (hasUnsavedChanges: boolean) => void;
27
+ validationRef?: React.MutableRefObject<{
28
+ triggerValidation: () => Promise<boolean>;
29
+ getFormData?: () => ChooseTheCorrectAnswerGroupData;
30
+ } | null>;
31
+ }
32
+ export interface ChooseTheCorrectAnswerGroupClientProps {
33
+ questionData: ChooseTheCorrectAnswerGroupData;
34
+ isReviewMode?: boolean;
35
+ userAnswers?: string[];
36
+ }
@@ -0,0 +1,40 @@
1
+ import type { MutableRefObject } from 'react';
2
+ export type CrossOutWordItemMode = 'CROSS_OUT' | 'CROSS_OUT_AND_REPLACE';
3
+ export interface CrossOutWordGroupItemAnswer {
4
+ type: CrossOutWordItemMode;
5
+ /** Word to cross out. Empty string = line is correct. */
6
+ crossOut: string;
7
+ /** Replacement word. Only for CROSS_OUT_AND_REPLACE. */
8
+ replaceWith?: string;
9
+ }
10
+ export interface CrossOutWordGroupItemData {
11
+ type: CrossOutWordItemMode;
12
+ question: string;
13
+ correctAnswer: CrossOutWordGroupItemAnswer;
14
+ isExample?: boolean;
15
+ points: number;
16
+ questionNumber: number;
17
+ }
18
+ export interface CrossOutWordGroupData {
19
+ instruction: string;
20
+ items: CrossOutWordGroupItemData[];
21
+ explanation?: string;
22
+ points?: number;
23
+ }
24
+ export interface CrossOutWordGroupCreatorProps {
25
+ initialData?: CrossOutWordGroupData;
26
+ onSave?: (data: CrossOutWordGroupData) => void;
27
+ onCancel?: () => void;
28
+ onChange?: (data: CrossOutWordGroupData) => void;
29
+ externalErrors?: string[];
30
+ onUnsavedChangesChange?: (hasUnsavedChanges: boolean) => void;
31
+ validationRef?: MutableRefObject<{
32
+ triggerValidation: () => Promise<boolean>;
33
+ getFormData?: () => CrossOutWordGroupData;
34
+ } | null>;
35
+ }
36
+ export interface CrossOutWordGroupClientProps {
37
+ questionData: CrossOutWordGroupData;
38
+ isReviewMode?: boolean;
39
+ userAnswers?: Array<CrossOutWordGroupItemAnswer | null | undefined>;
40
+ }
@@ -1,3 +1,4 @@
1
+ export * from './choose-the-correct-answer-group.type';
1
2
  export * from './listening-drawline.type';
2
3
  export * from './listen-and-tick-answer.type';
3
4
  export * from './arrange-letters-into-words.type';
@@ -1 +1 @@
1
- export*from"./listening-drawline.type";export*from"./listen-and-tick-answer.type";export*from"./arrange-letters-into-words.type";export*from"./write-short-paragraph.type";export*from"./fill-missing-words-in-grid.type";export*from"./look-and-choose-answer.type";export*from"./look-picture-fill-word-hint.type";export*from"./label-the-picture.type";export*from"./read-and-color-objects.type";export*from"./fill-in-blank.type";export*from"./read-passage-and-answer-questions.type";export*from"./word-fill-structured-form.type";
1
+ export*from"./choose-the-correct-answer-group.type";export*from"./listening-drawline.type";export*from"./listen-and-tick-answer.type";export*from"./arrange-letters-into-words.type";export*from"./write-short-paragraph.type";export*from"./fill-missing-words-in-grid.type";export*from"./look-and-choose-answer.type";export*from"./look-picture-fill-word-hint.type";export*from"./label-the-picture.type";export*from"./read-and-color-objects.type";export*from"./fill-in-blank.type";export*from"./read-passage-and-answer-questions.type";export*from"./word-fill-structured-form.type";
@@ -0,0 +1,31 @@
1
+ import type { MutableRefObject } from 'react';
2
+ export interface TrueFalseGroupItemData {
3
+ question: string;
4
+ correctAnswer: boolean;
5
+ isExample?: boolean;
6
+ points: number;
7
+ questionNumber: number;
8
+ }
9
+ export interface TrueFalseGroupData {
10
+ instruction: string;
11
+ items: TrueFalseGroupItemData[];
12
+ explanation?: string;
13
+ points?: number;
14
+ }
15
+ export interface TrueFalseGroupCreatorProps {
16
+ initialData?: TrueFalseGroupData;
17
+ onSave?: (data: TrueFalseGroupData) => void;
18
+ onCancel?: () => void;
19
+ onChange?: (data: TrueFalseGroupData) => void;
20
+ externalErrors?: string[];
21
+ onUnsavedChangesChange?: (hasUnsavedChanges: boolean) => void;
22
+ validationRef?: MutableRefObject<{
23
+ triggerValidation: () => Promise<boolean>;
24
+ getFormData?: () => TrueFalseGroupData;
25
+ } | null>;
26
+ }
27
+ export interface TrueFalseGroupClientProps {
28
+ questionData: TrueFalseGroupData;
29
+ isReviewMode?: boolean;
30
+ userAnswers?: boolean[];
31
+ }
@@ -1,5 +1,3 @@
1
- /** WFSF blank input width/shape (content.blankStyle). */
2
- export type WfsfBlankStyle = 'letter' | 'word' | 'phrase';
3
1
  /**
4
2
  * WORD_FILL_STRUCTURED_FORM — creator / client contracts.
5
3
  * wordBank + viewMode: plan 0024 (WITH_OPTIONS) + 0025 (WITH_WORD_BANK).
@@ -20,24 +18,20 @@ export interface WordFillStructuredFormData {
20
18
  imageUrl?: string;
21
19
  content: string;
22
20
  answers: Record<string, string>;
23
- /**
24
- * letter = square 1-char box; word = single-word underline; phrase = multi-word.
25
- * Default when omitted: word.
26
- */
27
- blankStyle?: WfsfBlankStyle;
28
- /**
29
- * WITH_OPTIONS (0024): per-blank options.
30
- * WITH_WORD_BANK (0025): shared chip box { word }[] (not 1:1 blanks).
31
- * Pure free-type pages omit these fields.
32
- */
33
- viewMode?: 'WITH_OPTIONS' | 'WITH_WORD_BANK' | 'DEFAULT' | string;
34
- /** OPTIONS: index i ↔ {i}; WORD_BANK: shared list of { word }. */
35
- wordBank?: WfsfWordBankEntry[];
36
21
  points?: number;
37
22
  /** Student rubric / page instruction (shown in client header). */
38
23
  instruction?: string;
39
24
  explanation?: string;
40
25
  caseSensitive?: boolean;
26
+ /** Free-type width hint when not WITH_OPTIONS. */
27
+ blankStyle?: 'letter' | 'word' | 'phrase' | 'translate';
28
+ /** Discriminates wordBank shape (0024 / 0025). */
29
+ viewMode?: WfsfViewMode | null;
30
+ /**
31
+ * WITH_OPTIONS: index i ↔ blank {i}; entry null = free-type.
32
+ * WITH_WORD_BANK: shared list (not 1:1 with blanks).
33
+ */
34
+ wordBank?: WfsfWordBankEntry[];
41
35
  groupTitle?: string;
42
36
  groupSubtitle?: string;
43
37
  groupContent?: string;
@@ -74,7 +68,7 @@ export interface WordFillStructuredFormClientProps {
74
68
  autoFillCorrectAnswers?: boolean;
75
69
  /** Page rubric — prefer over hard-coded type label in header. */
76
70
  instruction?: string;
77
- explanation?: string;
78
- /** Exercise / question number shown above instruction (e.g. Bài 1). */
71
+ /** Optional part/question index for "Bài N" prefix in header. */
79
72
  questionNumber?: number;
73
+ explanation?: string;
80
74
  }
@@ -1 +1 @@
1
- import{fillInBlankRegistration as r}from"../types/fill-in-blank/register";import{arrangeLettersIntoWordsRegistration as e}from"../types/arrange-letters-into-words/register";import{writeShortParagraphRegistration as t}from"../types/write-short-paragraph/register";import{fillMissingWordsInGridRegistration as s}from"../types/fill-missing-words-in-grid/register";import{lookPictureChooseCorrectAnswerRegistration as o}from"../types/look-picture-choose-correct-answer/register";import{lookPictureFillBlankChooseAnswerRegistration as i}from"../types/look-picture-fill-blank-choose-answer/register";import{lookPictureFillWordHintRegistration as _}from"../types/look-picture-fill-word-hint/register";import{labelThePictureRegistration as p}from"../types/label-the-picture/register";import{readAndColorObjectsRegistration as E}from"../types/read-and-color-objects/register";import{imageObjectMatchingRegistration as m}from"../types/image-object-matching/register";import{readPassageAndAnswerQuestionsRegistration as n}from"../types/read-passage-and-answer-questions/register";import{chooseTheCorrectAnswerRegistration as S}from"../types/choose-the-correct-answer/register";import{writeAShortLetterRegistration as a}from"../types/write-a-short-letter/register";import{writeCorrectVerbFormRegistration as A}from"../types/write-correct-verb-form/register";import{chooseCorrectAdjectiveRegistration as N}from"../types/choose-correct-adjective/register";import{answerTheQuestionRegistration as R}from"../types/answer-the-question/register";import{trueFalseRegistration as g}from"../types/true-false/register";import{wordOrderingRegistration as T}from"../types/word-ordering/register";import{wordFillParagraphRegistration as I}from"../types/word-fill-paragraph/register";import{matchByWritingAnswerRegistration as O}from"../types/match-by-writing-answer/register";import{writeSentencesRegistration as f}from"../types/write-sentences/register";import{listenAndChooseFromAnswerGroupRegistration as y}from"../types/listen-and-choose-from-answer-group/register";import{listenAndChooseObjectsInSceneRegistration as c}from"../types/listen-and-choose-objects-in-scene/register";import{listenAndDragObjectsIntoSceneRegistration as C}from"../types/listen-and-drag-objects-into-scene/register";import{listenAndSpeakAnswerRegistration as l}from"../types/listen-and-speak-answer/register";import{listenAndSpeakImageGroupRegistration as L}from"../types/listen-and-speak-image-group/register";import{listenAndSpeakQuestionListRegistration as d}from"../types/listen-and-speak-question-list/register";import{ListenAndSpeakCompareImagesRegistration as D}from"../types/listen-and-speak-compare-images/register";import{listenAndSpeakWithStoryImagesRegistration as P}from"../types/listen-and-speak-with-story-images/register";import{listenAndSpeakOddOneOutRegistration as G}from"../types/listen-and-speak-odd-one-out/register";import{listenAndSpeakInfoExchangeRegistration as w}from"../types/listen-and-speak-info-exchange/register";import{speakingDescribeImageRegistration as W}from"../types/speaking-describe-image/register";import{spontaneousQARegistration as h}from"../types/spontaneous-qa/register";import{readDisplayedContentRegistration as H}from"../types/read-displayed-content/register";import{speakingConversationRegistration as k}from"../types/speaking-conversation/register";import{gnSpeakingInterviewRegistration as u}from"../types/gn-speaking-interview/register";import{speakingCueCardRegistration as K}from"../types/speaking-cue-card/register";import{wordFillStructuredFormRegistration as U}from"../types/word-fill-structured-form/register";export const questionTypeRegistry={CHOOSE_THE_CORRECT_ANSWER:S,FILL_IN_BLANK:r,ARRANGE_LETTERS_INTO_WORDS:e,WRITE_SHORT_PARAGRAPH:t,FILL_MISSING_WORDS_IN_GRID:s,LOOK_PICTURE_CHOOSE_CORRECT_ANSWER:o,LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER:i,LOOK_PICTURE_FILL_WORD_HINT:_,LABEL_THE_PICTURE:p,READ_AND_COLOR_OBJECTS:E,IMAGE_OBJECT_MATCHING:m,READ_PASSAGE_AND_ANSWER_QUESTIONS:n,WRITE_A_SHORT_LETTER:a,WRITE_CORRECT_VERB_FORM:A,CHOOSE_CORRECT_ADJECTIVE:N,ANSWER_THE_QUESTION:R,TRUE_FALSE:g,WORD_ORDERING:T,WORD_FILL_PARAGRAPH:I,MATCH_BY_WRITING_ANSWER:O,WRITE_SENTENCES:f,LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP:y,LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE:c,LISTEN_AND_DRAG_OBJECTS_INTO_SCENE:C,LISTEN_AND_SPEAK_ANSWER:l,LISTEN_AND_SPEAK_IMAGE_GROUP:L,LISTEN_AND_SPEAK_QUESTION_LIST:d,LISTEN_AND_SPEAK_COMPARE_IMAGES:D,LISTEN_AND_SPEAK_WITH_STORY_IMAGES:P,LISTEN_AND_SPEAK_ODD_ONE_OUT:G,LISTEN_AND_SPEAK_INFO_EXCHANGE:w,SPEAKING_DESCRIBE_IMAGE:W,SPONTANEOUS_QA:h,READ_DISPLAYED_CONTENT:H,SPEAKING_CONVERSATION:k,GN_SPEAKING_INTERVIEW:u,SPEAKING_CUE_CARD:K,WORD_FILL_STRUCTURED_FORM:U};
1
+ import{fillInBlankRegistration as r}from"../types/fill-in-blank/register";import{arrangeLettersIntoWordsRegistration as e}from"../types/arrange-letters-into-words/register";import{writeShortParagraphRegistration as t}from"../types/write-short-paragraph/register";import{fillMissingWordsInGridRegistration as s}from"../types/fill-missing-words-in-grid/register";import{lookPictureChooseCorrectAnswerRegistration as o}from"../types/look-picture-choose-correct-answer/register";import{lookPictureFillBlankChooseAnswerRegistration as i}from"../types/look-picture-fill-blank-choose-answer/register";import{lookPictureFillWordHintRegistration as _}from"../types/look-picture-fill-word-hint/register";import{labelThePictureRegistration as p}from"../types/label-the-picture/register";import{readAndColorObjectsRegistration as E}from"../types/read-and-color-objects/register";import{imageObjectMatchingRegistration as m}from"../types/image-object-matching/register";import{readPassageAndAnswerQuestionsRegistration as R}from"../types/read-passage-and-answer-questions/register";import{chooseTheCorrectAnswerRegistration as S}from"../types/choose-the-correct-answer/register";import{chooseTheCorrectAnswerGroupRegistration as g}from"../types/choose-the-correct-answer-group/register";import{trueFalseGroupRegistration as n}from"../types/true-false-group/register";import{crossOutWordGroupRegistration as a}from"../types/cross-out-word-group/register";import{writeAShortLetterRegistration as A}from"../types/write-a-short-letter/register";import{writeCorrectVerbFormRegistration as O}from"../types/write-correct-verb-form/register";import{chooseCorrectAdjectiveRegistration as N}from"../types/choose-correct-adjective/register";import{answerTheQuestionRegistration as T}from"../types/answer-the-question/register";import{trueFalseRegistration as I}from"../types/true-false/register";import{wordOrderingRegistration as f}from"../types/word-ordering/register";import{wordFillParagraphRegistration as y}from"../types/word-fill-paragraph/register";import{matchByWritingAnswerRegistration as c}from"../types/match-by-writing-answer/register";import{writeSentencesRegistration as C}from"../types/write-sentences/register";import{listenAndChooseFromAnswerGroupRegistration as l}from"../types/listen-and-choose-from-answer-group/register";import{listenAndChooseObjectsInSceneRegistration as L}from"../types/listen-and-choose-objects-in-scene/register";import{listenAndDragObjectsIntoSceneRegistration as d}from"../types/listen-and-drag-objects-into-scene/register";import{listenAndSpeakAnswerRegistration as D}from"../types/listen-and-speak-answer/register";import{listenAndSpeakImageGroupRegistration as P}from"../types/listen-and-speak-image-group/register";import{listenAndSpeakQuestionListRegistration as G}from"../types/listen-and-speak-question-list/register";import{ListenAndSpeakCompareImagesRegistration as w}from"../types/listen-and-speak-compare-images/register";import{listenAndSpeakWithStoryImagesRegistration as W}from"../types/listen-and-speak-with-story-images/register";import{listenAndSpeakOddOneOutRegistration as u}from"../types/listen-and-speak-odd-one-out/register";import{listenAndSpeakInfoExchangeRegistration as h}from"../types/listen-and-speak-info-exchange/register";import{speakingDescribeImageRegistration as H}from"../types/speaking-describe-image/register";import{spontaneousQARegistration as U}from"../types/spontaneous-qa/register";import{readDisplayedContentRegistration as k}from"../types/read-displayed-content/register";import{speakingConversationRegistration as K}from"../types/speaking-conversation/register";import{gnSpeakingInterviewRegistration as F}from"../types/gn-speaking-interview/register";import{speakingCueCardRegistration as M}from"../types/speaking-cue-card/register";import{wordFillStructuredFormRegistration as b}from"../types/word-fill-structured-form/register";export const questionTypeRegistry={CHOOSE_THE_CORRECT_ANSWER:S,CHOOSE_THE_CORRECT_ANSWER_GROUP:g,TRUE_FALSE_GROUP:n,CROSS_OUT_WORD_GROUP:a,FILL_IN_BLANK:r,ARRANGE_LETTERS_INTO_WORDS:e,WRITE_SHORT_PARAGRAPH:t,FILL_MISSING_WORDS_IN_GRID:s,LOOK_PICTURE_CHOOSE_CORRECT_ANSWER:o,LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER:i,LOOK_PICTURE_FILL_WORD_HINT:_,LABEL_THE_PICTURE:p,READ_AND_COLOR_OBJECTS:E,IMAGE_OBJECT_MATCHING:m,READ_PASSAGE_AND_ANSWER_QUESTIONS:R,WRITE_A_SHORT_LETTER:A,WRITE_CORRECT_VERB_FORM:O,CHOOSE_CORRECT_ADJECTIVE:N,ANSWER_THE_QUESTION:T,TRUE_FALSE:I,WORD_ORDERING:f,WORD_FILL_PARAGRAPH:y,MATCH_BY_WRITING_ANSWER:c,WRITE_SENTENCES:C,LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP:l,LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE:L,LISTEN_AND_DRAG_OBJECTS_INTO_SCENE:d,LISTEN_AND_SPEAK_ANSWER:D,LISTEN_AND_SPEAK_IMAGE_GROUP:P,LISTEN_AND_SPEAK_QUESTION_LIST:G,LISTEN_AND_SPEAK_COMPARE_IMAGES:w,LISTEN_AND_SPEAK_WITH_STORY_IMAGES:W,LISTEN_AND_SPEAK_ODD_ONE_OUT:u,LISTEN_AND_SPEAK_INFO_EXCHANGE:h,SPEAKING_DESCRIBE_IMAGE:H,SPONTANEOUS_QA:U,READ_DISPLAYED_CONTENT:k,SPEAKING_CONVERSATION:K,GN_SPEAKING_INTERVIEW:F,SPEAKING_CUE_CARD:M,WORD_FILL_STRUCTURED_FORM:b};
@@ -8,4 +8,3 @@ export * from './groups/DocumentGroupCard';
8
8
  export * from './groups/MatchAnswerGroupCard';
9
9
  export * from './viewer';
10
10
  export * from './_shared';
11
- export * from './question-bank';
@@ -1 +1 @@
1
- export*from"./creator";export*from"./creator/dedicated-component-router";export*from"./creator/question-type-registry";export*from"./components";export*from"./groups/ArticlesGroupCard";export*from"./groups/BasicQuestionGroupCard";export*from"./groups/DocumentGroupCard";export*from"./groups/MatchAnswerGroupCard";export*from"./viewer";export*from"./_shared";export*from"./question-bank";
1
+ export*from"./creator";export*from"./creator/dedicated-component-router";export*from"./creator/question-type-registry";export*from"./components";export*from"./groups/ArticlesGroupCard";export*from"./groups/BasicQuestionGroupCard";export*from"./groups/DocumentGroupCard";export*from"./groups/MatchAnswerGroupCard";export*from"./viewer";export*from"./_shared";
@@ -0,0 +1,2 @@
1
+ import type { ChooseTheCorrectAnswerGroupClientProps } from '../../_shared/types/choose-the-correct-answer-group.type';
2
+ export declare function ChooseTheCorrectAnswerGroupClient({ questionData, isReviewMode, userAnswers, }: ChooseTheCorrectAnswerGroupClientProps): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{Check as t,CircleHelp as s,Lightbulb as i,Star as a}from"lucide-react";import{cn as n}from"../../../../shared/lib/utils";const d=["A","B","C","D","E","F"];export function ChooseTheCorrectAnswerGroupClient({questionData:l,isReviewMode:o=!1,userAnswers:c=[]}){const m=l.items||[];return r("div",{className:"space-y-4",children:[l.instruction&&e("div",{className:"rounded-xl border border-indigo-100 bg-indigo-50 px-4 py-3 text-sm font-medium text-indigo-800",children:l.instruction}),m.map((i,l)=>{const m=c[l];return r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("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:[r("div",{className:"flex items-center gap-2",children:[e("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:e(s,{className:"h-3.5 w-3.5"})}),r("span",{className:"text-sm font-medium text-gray-700",children:["Câu ",i.questionNumber||l+1]}),i.isExample&&r("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:[e(a,{className:"h-3 w-3"}),"Example"]})]}),r("span",{className:"text-xs text-gray-500",children:[i.points||0," điểm"]})]}),r("div",{className:"space-y-3 p-4",children:[e("p",{className:"text-sm font-semibold leading-relaxed text-gray-800",children:i.question||"Câu hỏi chưa được nhập"}),e("div",{className:"space-y-2",children:i.options.map((s,a)=>{const l=s.id===i.correctAnswer,c=s.id===m;return r("div",{className:n("flex items-center gap-3 rounded-lg border-2 px-3 py-2.5 text-sm",o&&l?"border-green-400 bg-green-50":c?"border-blue-400 bg-blue-50":"border-gray-200 bg-white"),children:[e("span",{className:n("flex h-7 w-7 items-center justify-center rounded-md text-xs font-bold",o&&l?"bg-green-500 text-white":"bg-gray-100 text-gray-600"),children:d[a]||a+1}),e("span",{className:"flex-1 text-gray-800",children:s.text||`Đáp án ${d[a]}`}),o&&l&&e(t,{className:"h-4 w-4 text-green-600"})]},s.id||a)})})]})]},`${i.questionNumber}-${l}`)}),o&&l.explanation&&r("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:[e(i,{className:"mt-0.5 h-4 w-4 flex-shrink-0"}),l.explanation]})]})}
@@ -0,0 +1,2 @@
1
+ import type { ChooseTheCorrectAnswerGroupCreatorProps } from '../../_shared/types/choose-the-correct-answer-group.type';
2
+ export declare function ChooseTheCorrectAnswerGroupCreator({ initialData, onChange, externalErrors, onUnsavedChangesChange, validationRef, }: ChooseTheCorrectAnswerGroupCreatorProps): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useEffect as n,useRef as r,useState as i}from"react";import{Button as o}from"../../../../components/ui/button";import{Label as s}from"../../../../components/ui/label";import{Input as a}from"../../../../components/ui/input";import{Textarea as c}from"../../../../components/ui/textarea";import{PointsInput as l}from"../../../../components/ui/points-input";import{Card as p,CardContent as m,CardHeader as u,CardTitle as h}from"../../../../components/ui/card";import{Switch as d}from"../../../../components/ui/switch";import{useDebouncedCallback as g}from"../../../../shared/lib/hooks";import{Eye as x,Pencil as f,Plus as v,Star as y,Trash2 as b}from"lucide-react";import{ChooseTheCorrectAnswerGroupClient as N}from"./ChooseTheCorrectAnswerGroupClient";const C=["A","B","C","D","E","F"];function w(e){return{question:"",optionType:"text",options:[{id:"opt-1",text:""},{id:"opt-2",text:""},{id:"opt-3",text:""}],correctAnswer:"opt-1",isExample:!1,points:1,questionNumber:e}}function A(e){return e.reduce((e,t)=>t.isExample?e:e+("number"==typeof t.points?t.points:1),0)}function q(e,t){const n=Number.parseInt(e.replace(/[^0-9]/g,""),10);return Number.isNaN(n)?t?0:1:t?Math.max(0,n):Math.max(1,n)}export function ChooseTheCorrectAnswerGroupCreator({initialData:E,onChange:k,externalErrors:j,onUnsavedChangesChange:T,validationRef:$}){const[D,F]=i(E?.instruction||"Choose the correct answer."),[G,M]=i(()=>{return e=E?.items,Array.isArray(e)&&0!==e.length?e.map((e,t)=>({question:e.question||"",optionType:"image"===e.optionType?"image":"text",options:Array.isArray(e.options)&&e.options.length>=2?e.options.map((e,t)=>({id:e.id||`opt-${t+1}`,text:e.text||""})):w(t+1).options,correctAnswer:e.correctAnswer||"opt-1",isExample:!0===e.isExample,points:e.isExample?0:"number"==typeof e.points?e.points:1,questionNumber:e.questionNumber||t+1})):[w(1)];var e}),[V,O]=i(E?.explanation||""),[R,Z]=i(!1),[z,B]=i([]),H=r(k),I=r("");n(()=>{H.current=k},[k]);const J=(e=D,t=G,n=V)=>({instruction:e,items:t,explanation:n,points:A(t)}),S=g(e=>{H.current?.(e)},300);n(()=>{const e=J(),t=JSON.stringify(e);t!==I.current&&(I.current=t,T?.(!0),S(e))},[D,G,V,S,T]);n(()=>{$&&($.current={triggerValidation:async()=>{const e=(()=>{const e=[];return D.trim()||e.push("Vui lòng nhập hướng dẫn."),G.length<1&&e.push("Cần ít nhất một câu hỏi."),G.forEach((t,n)=>{t.question.trim()||e.push(`Câu ${n+1}: nội dung câu hỏi là bắt buộc.`),t.options.filter(e=>""!==e.text.trim()).length<2&&e.push(`Câu ${n+1}: cần ít nhất 2 đáp án.`),t.options.some(e=>e.id===t.correctAnswer&&""!==e.text.trim())||e.push(`Câu ${n+1}: hãy chọn đáp án đúng.`)}),e})();return B(e),0===e.length},getFormData:()=>J()})});const U=(e,t)=>{M(n=>n.map((n,r)=>r===e?{...n,...t}:n))};if(R)return t("div",{className:"space-y-4",children:[e("div",{className:"flex justify-end",children:t(o,{type:"button",variant:"outline",onClick:()=>Z(!1),children:[e(f,{className:"mr-2 h-4 w-4"}),"Chỉnh sửa"]})}),e(N,{questionData:J(),isReviewMode:!0})]});const X=[...z,...j||[]];return t("div",{className:"space-y-4",children:[e("div",{className:"flex justify-end",children:t(o,{type:"button",variant:"outline",onClick:()=>Z(!0),children:[e(x,{className:"mr-2 h-4 w-4"}),"Xem trước"]})}),t(p,{children:[e(u,{children:e(h,{children:"Nhóm chọn đáp án đúng"})}),t(m,{className:"space-y-4",children:[t("div",{className:"space-y-2",children:[e(s,{htmlFor:"group-instruction",children:"Hướng dẫn"}),e(a,{id:"group-instruction",value:D,onChange:e=>F(e.target.value),placeholder:"Choose the correct answer."})]}),t("div",{className:"rounded-xl border border-gray-200 bg-gray-50 p-4",children:[e(l,{value:A(G),allowZero:!0,readOnly:!0}),e("p",{className:"mt-2 text-xs text-gray-500",children:"Tổng điểm được cộng từ các câu không phải example."})]})]})]}),G.map((n,r)=>t(p,{children:[t(u,{className:"flex flex-row items-center justify-between space-y-0",children:[t(h,{className:"text-base",children:["Câu ",r+1]}),e(o,{type:"button",variant:"ghost",size:"sm",onClick:()=>{return e=r,void M(t=>t.length<=1?t:t.filter((t,n)=>n!==e).map((e,t)=>({...e,questionNumber:t+1})));var e},disabled:G.length<=1,children:e(b,{className:"h-4 w-4"})})]}),t(m,{className:"space-y-4",children:[t("div",{className:"flex items-center justify-between rounded-lg border border-amber-100 bg-amber-50 px-3 py-2",children:[t("div",{className:"flex items-center gap-2 text-sm font-medium text-amber-800",children:[e(y,{className:"h-4 w-4"}),"Câu ví dụ"]}),e(d,{checked:!0===n.isExample,onCheckedChange:e=>U(r,{isExample:e,points:e?0:n.points||1})})]}),t("div",{className:"space-y-2",children:[e(s,{children:"Câu hỏi"}),e(c,{value:n.question,onChange:e=>U(r,{question:e.target.value}),rows:2,placeholder:"A place for someone to stay or live is called"})]}),e("div",{className:"space-y-2",children:n.options.map((i,o)=>t("div",{className:"flex items-center gap-2",children:[e("input",{type:"radio",name:`correct-${r}`,checked:n.correctAnswer===i.id,onChange:()=>U(r,{correctAnswer:i.id})}),e("span",{className:"w-6 text-sm font-semibold text-gray-600",children:C[o]||o+1}),e(a,{value:i.text,onChange:e=>((e,t,n)=>{M(r=>r.map((r,i)=>{if(i!==e)return r;const o=r.options.map((e,r)=>r===t?{...e,text:n}:e);return{...r,options:o}}))})(r,o,e.target.value),placeholder:`Đáp án ${C[o]}`})]},i.id))}),!n.isExample&&e(l,{value:n.points,allowZero:!0,onChange:e=>U(r,{points:q(e.target.value,!0)})})]})]},`item-${r}`)),t(o,{type:"button",variant:"outline",onClick:()=>{M(e=>[...e,w(e.length+1)])},children:[e(v,{className:"mr-2 h-4 w-4"}),"Thêm câu hỏi"]}),t(p,{children:[e(u,{children:e(h,{className:"text-base",children:"Giải thích"})}),e(m,{children:e(c,{id:"explanation",value:V,onChange:e=>O(e.target.value),placeholder:"VD: Câu trả lời đúng là... vì...",rows:3})})]}),X.length>0&&e("div",{className:"rounded-xl border border-red-200 bg-red-50 p-4 text-sm text-red-700",children:X.map(t=>e("p",{children:t},t))})]})}
@@ -0,0 +1,3 @@
1
+ export * from './ChooseTheCorrectAnswerGroupCreator';
2
+ export * from './ChooseTheCorrectAnswerGroupClient';
3
+ export * from './map-choose-the-correct-answer-group-data';
@@ -0,0 +1 @@
1
+ export*from"./ChooseTheCorrectAnswerGroupCreator";export*from"./ChooseTheCorrectAnswerGroupClient";export*from"./map-choose-the-correct-answer-group-data";
@@ -0,0 +1,4 @@
1
+ import type { ChooseTheCorrectAnswerGroupData, ChooseTheCorrectAnswerGroupItemData } from '../../_shared/types/choose-the-correct-answer-group.type';
2
+ export declare function createEmptyChooseAnswerGroupItem(questionNumber: number): ChooseTheCorrectAnswerGroupItemData;
3
+ export declare function mapChooseAnswerGroupItem(item: unknown, index: number, fallbackAnswer?: string): ChooseTheCorrectAnswerGroupItemData;
4
+ export declare function mapQuestionToChooseAnswerGroupData(question: Record<string, unknown> | null | undefined): ChooseTheCorrectAnswerGroupData;
@@ -0,0 +1 @@
1
+ function t(t){return function(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}(t)?t:{}}function e(t,e=""){return"string"==typeof t?t:e}export function createEmptyChooseAnswerGroupItem(t){return{question:"",optionType:"text",options:[{id:"opt-1",text:""},{id:"opt-2",text:""},{id:"opt-3",text:""}],correctAnswer:"opt-1",isExample:!1,points:1,questionNumber:t}}export function mapChooseAnswerGroupItem(o,n,r){const i=t(o),s=t(i.content),p=t(i.correctAnswer),a=Array.isArray(s.options)?s.options:[],u=a.length>=2?a.map((o,n)=>{const r=t(o);return{id:e(r.id,`opt-${n+1}`),text:e(r.text)}}):[{id:"opt-1",text:""},{id:"opt-2",text:""},{id:"opt-3",text:""}],c=!0===i.isExample;return{question:e(s.question)||e(i.question),optionType:"image"===e(s.optionType)?"image":"text",options:u,correctAnswer:e(p.answer)||r||u[0]?.id||"opt-1",isExample:c,points:c?0:"number"==typeof i.points?i.points:1,questionNumber:"number"==typeof i.questionNumber?i.questionNumber:n+1}}export function mapQuestionToChooseAnswerGroupData(o){const n=t(o),r=t(n.content),i=t(n.answer),s=t(n.correctAnswer??n.correct_answer??i.correctAnswer),p=String(n.explanation||i.explanation||""),a=Array.isArray(s.answer)?s.answer.map(t=>"string"==typeof t?t:void 0):[];if(Array.isArray(r.items)){const o=r.items.map((t,e)=>mapChooseAnswerGroupItem(t,e,a[e]));return{instruction:e(t(r.meta).instruction)||"Choose the correct answer.",items:o,explanation:p,points:o.reduce((t,e)=>e.isExample?t:t+(e.points||0),0)}}return Array.isArray(i.items)?{instruction:e(i.instruction,"Choose the correct answer."),items:i.items.map((t,e)=>mapChooseAnswerGroupItem(t,e,a[e])),explanation:p,points:"number"==typeof i.points?i.points:void 0}:{instruction:"Choose the correct answer.",items:[createEmptyChooseAnswerGroupItem(1)],explanation:p,points:1}}
@@ -0,0 +1,2 @@
1
+ import type { QuestionTypeRegistration } from '../../creator/question-type-registry';
2
+ export declare const chooseTheCorrectAnswerGroupRegistration: QuestionTypeRegistration;
@@ -0,0 +1 @@
1
+ import{ChooseTheCorrectAnswerGroupCreator as t}from"./ChooseTheCorrectAnswerGroupCreator";import{mapQuestionToChooseAnswerGroupData as e}from"./map-choose-the-correct-answer-group-data";export const chooseTheCorrectAnswerGroupRegistration={component:t,transformInitialData:t=>e(t),getExtraProps:t=>({onUnsavedChangesChange:t.onUnsavedChangesChange,validationRef:t.validationRef}),wrapOnSave:(t,e)=>{const n=t;return{type:e.questionType,content:e.state.content,points:n.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:n,explanation:n.explanation||""}},wrapOnChange:(t,e)=>{const n=t;return{type:e.questionType,content:e.state.content,points:n.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:n,explanation:n.explanation||""}}};
@@ -0,0 +1,2 @@
1
+ import type { TransformHandler } from '../../../../shared/lib/utils/question-transform-types';
2
+ export declare const transformChooseTheCorrectAnswerGroup: TransformHandler;
@@ -0,0 +1 @@
1
+ function t(t,e){return t?.id&&""!==t.id.trim()?t.id:`opt-${e+1}`}function e(t){return t.reduce((t,e)=>{if(e.isExample)return t;return t+("number"==typeof e.points?e.points:1)},0)}export const transformChooseTheCorrectAnswerGroup=n=>{const r=n.answer,o=Array.isArray(r?.items)?r.items:[];if(0===o.length)return{apiContent:{items:[]},apiCorrectAnswer:{answer:[]}};const s=o.map((e,n)=>{const r=(e.options||[]).map((e,n)=>({id:t(e,n),text:e.text||""})),o=e.correctAnswer||r[0]?.id||"opt-1";return{questionType:"CHOOSE_THE_CORRECT_ANSWER",...e.isExample?{isExample:!0}:{},content:{question:e.question||"",options:r,optionType:e.optionType||"text"},correctAnswer:{answer:o},points:e.isExample?0:"number"==typeof e.points?e.points:1,questionNumber:e.questionNumber||n+1}});return{apiContent:{meta:{instruction:r?.instruction||"Choose the correct answer."},items:s},apiCorrectAnswer:{answer:s.map(t=>t.correctAnswer.answer)},totalPoints:e(o)}};
@@ -0,0 +1,2 @@
1
+ import type { CrossOutWordGroupClientProps } from '../../_shared/types/cross-out-word-group.type';
2
+ export declare function CrossOutWordGroupClient({ questionData, isReviewMode, userAnswers, }: CrossOutWordGroupClientProps): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{CircleHelp as r,Lightbulb as s,Star as i}from"lucide-react";import{cn as a}from"../../../../shared/lib/utils";function n(e){return e?"CROSS_OUT_AND_REPLACE"===e.type?`gạch "${e.crossOut}" → "${e.replaceWith||""}"`:e.crossOut?`gạch "${e.crossOut}"`:"câu đúng (không gạch)":"—"}export function CrossOutWordGroupClient({questionData:d,isReviewMode:l=!1,userAnswers:o=[]}){const c=d.items||[];return t("div",{className:"space-y-4",children:[d.instruction&&e("div",{className:"rounded-xl border border-indigo-100 bg-indigo-50 px-4 py-3 text-sm font-medium text-indigo-800",children:d.instruction}),c.map((s,d)=>{const c=o[d],m="CROSS_OUT_AND_REPLACE"===s.type;return t("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[t("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:[t("div",{className:"flex items-center gap-2",children:[e("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:e(r,{className:"h-3.5 w-3.5"})}),t("span",{className:"text-sm font-medium text-gray-700",children:["Câu ",s.questionNumber||d+1]}),s.isExample&&t("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:[e(i,{className:"h-3 w-3"}),"Example"]}),e("span",{className:a("rounded-full px-2 py-0.5 text-xs font-semibold",m?"bg-violet-100 text-violet-700":"bg-sky-100 text-sky-700"),children:m?"Gạch + thay":"Chỉ gạch"})]}),t("span",{className:"text-xs text-gray-500",children:[s.points||0," điểm"]})]}),t("div",{className:"space-y-3 p-4",children:[e("p",{className:"text-sm font-semibold leading-relaxed text-gray-800",children:s.question||"Câu hỏi chưa được nhập"}),t("div",{className:"rounded-lg border border-gray-100 bg-gray-50 px-3 py-2 text-sm text-gray-700",children:[e("span",{className:"font-medium text-gray-500",children:"Đáp án: "}),n(s.correctAnswer)]}),l&&t("div",{className:"rounded-lg border border-blue-100 bg-blue-50 px-3 py-2 text-sm text-blue-800",children:[e("span",{className:"font-medium",children:"Học sinh: "}),n(c)]})]})]},`${s.questionNumber}-${d}`)}),l&&d.explanation&&t("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:[e(s,{className:"mt-0.5 h-4 w-4 flex-shrink-0"}),d.explanation]})]})}
@@ -0,0 +1,2 @@
1
+ import type { CrossOutWordGroupCreatorProps } from '../../_shared/types/cross-out-word-group.type';
2
+ export declare function CrossOutWordGroupCreator({ initialData, onChange, externalErrors, onUnsavedChangesChange, validationRef, }: CrossOutWordGroupCreatorProps): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useEffect as r,useRef as n,useState as c}from"react";import{Button as s}from"../../../../components/ui/button";import{Label as i}from"../../../../components/ui/label";import{Input as a}from"../../../../components/ui/input";import{Textarea as o}from"../../../../components/ui/textarea";import{PointsInput as l}from"../../../../components/ui/points-input";import{Card as h,CardContent as m,CardHeader as u,CardTitle as d}from"../../../../components/ui/card";import{Switch as p}from"../../../../components/ui/switch";import{Select as g,SelectContent as x,SelectItem as N,SelectTrigger as C,SelectValue as f}from"../../../../components/ui/select";import{useDebouncedCallback as O}from"../../../../shared/lib/hooks";import{Eye as v,Pencil as b,Plus as y,Star as w,Trash2 as S}from"lucide-react";import{CrossOutWordGroupClient as A}from"./CrossOutWordGroupClient";function _(e,t=!1){if(""===e)return t?0:1;const r=parseInt(e.replace(/[^0-9]/g,""),10);if(Number.isNaN(r))return t?0:1;const n=t?0:1;return Math.max(n,r)}const E="Cross out the extra or incorrect word. If the word is incorrect, write the correct word. If the line is correct, leave it blank.";function R(e,t="",r=""){return"CROSS_OUT_AND_REPLACE"===e?{type:e,crossOut:t,replaceWith:r}:{type:"CROSS_OUT",crossOut:t}}function T(e){return{type:"CROSS_OUT",question:"",correctAnswer:R("CROSS_OUT"),isExample:!1,points:1,questionNumber:e}}function U(e){return e.reduce((e,t)=>t.isExample?e:e+("number"==typeof t.points?t.points:1),0)}export function CrossOutWordGroupCreator({initialData:D,onChange:q,externalErrors:W,onUnsavedChangesChange:$,validationRef:k}){const[L,P]=c(D?.instruction||E),[j,F]=c(()=>{return e=D?.items,Array.isArray(e)&&0!==e.length?e.map((e,t)=>{const r="CROSS_OUT_AND_REPLACE"===e.type||"CROSS_OUT_AND_REPLACE"===e.correctAnswer?.type?"CROSS_OUT_AND_REPLACE":"CROSS_OUT",n=R(r,e.correctAnswer?.crossOut||"",e.correctAnswer?.replaceWith||"");return{type:r,question:e.question||"",correctAnswer:n,isExample:!0===e.isExample,points:e.isExample?0:"number"==typeof e.points?e.points:1,questionNumber:e.questionNumber||t+1}}):[T(1)];var e}),[V,G]=c(D?.explanation||""),[I,z]=c(!1),[H,M]=c([]),X=n(q),J=n("");r(()=>{X.current=q},[q]);const Z=(e=L,t=j,r=V)=>({instruction:e,items:t,explanation:r,points:U(t)}),B=O(e=>{X.current?.(e)},300);r(()=>{const e=Z(),t=JSON.stringify(e);t!==J.current&&(J.current=t,B(e),$?.(!0))},[L,j,V,B,$]);r(()=>{k&&(k.current={triggerValidation:async()=>(()=>{const e=[];return L.trim()||e.push("Hướng dẫn (Instruction) không được để trống."),0===j.length&&e.push("Cần ít nhất một câu hỏi trong nhóm."),j.forEach((t,r)=>{t.question.trim()||e.push(`Câu ${r+1}: Nội dung câu không được để trống.`),"CROSS_OUT_AND_REPLACE"===t.type&&(t.correctAnswer.crossOut.trim()||e.push(`Câu ${r+1}: Cần nhập từ cần gạch (crossOut).`),t.correctAnswer.replaceWith?.trim()||e.push(`Câu ${r+1}: Cần nhập từ thay thế (replaceWith).`))}),M(e),0===e.length})(),getFormData:()=>Z()})},[k,L,j,V]);const K=(e,t)=>{F(r=>{const n=[...r],c=n[e];return c?(n[e]={...c,...t},n):r})},Q=(e,t)=>{F(r=>{const n=[...r],c=n[e];if(!c)return r;const s=c.type;return n[e]={...c,correctAnswer:R(s,void 0!==t.crossOut?t.crossOut:c.correctAnswer.crossOut,void 0!==t.replaceWith?t.replaceWith:c.correctAnswer.replaceWith||"")},n})},Y=Z(),ee=W&&W.length>0?W:H;return t("div",{className:"space-y-6",children:[t("div",{className:"flex items-center justify-between",children:[t("div",{children:[e("h3",{className:"text-lg font-medium text-gray-900",children:"Tạo câu hỏi Gạch từ / Sửa từ (Nhóm)"}),e("p",{className:"text-sm text-gray-500",children:"Mix 2 dạng: chỉ gạch từ thừa, hoặc gạch từ sai rồi thay bằng từ đúng"})]}),t(s,{type:"button",variant:"outline",size:"sm",onClick:()=>z(e=>!e),className:"gap-2",children:[e(I?b:v,{className:"h-4 w-4"}),I?"Chế độ chỉnh sửa":"Xem trước học sinh"]})]}),ee.length>0&&t("div",{className:"rounded-lg border border-red-200 bg-red-50 p-4",children:[e("h3",{className:"text-sm font-medium text-red-800",children:"Cần sửa các lỗi sau:"}),e("ul",{className:"mt-2 list-disc space-y-1 pl-5 text-sm text-red-700",children:ee.map((t,r)=>e("li",{children:t},r))})]}),I?t(h,{children:[e(u,{children:e(d,{className:"text-base font-semibold",children:"Xem trước hiển thị học sinh"})}),e(m,{children:e(A,{questionData:Y})})]}):t("div",{className:"space-y-6",children:[t(h,{children:[e(u,{children:e(d,{className:"text-base font-semibold",children:"Hướng dẫn chung (Instruction)"})}),t(m,{children:[e(i,{htmlFor:"instruction",children:"Hướng dẫn bài làm"}),e(a,{id:"instruction",value:L,onChange:e=>P(e.target.value),placeholder:E,className:"mt-1"})]})]}),t(h,{children:[t(u,{className:"flex flex-row items-center justify-between",children:[t(d,{className:"text-base font-semibold",children:["Danh sách câu (",j.length,")"]}),t(s,{type:"button",variant:"outline",size:"sm",onClick:()=>{F(e=>[...e,T(e.length+1)])},className:"gap-2",children:[e(y,{className:"h-4 w-4"}),"Thêm câu"]})]}),e(m,{className:"space-y-4",children:j.map((r,n)=>t("div",{className:"space-y-4 rounded-lg border border-gray-200 bg-gray-50/50 p-4",children:[t("div",{className:"flex flex-wrap items-center justify-between gap-4",children:[t("div",{className:"flex items-center gap-2",children:[e("span",{className:"flex h-7 w-7 items-center justify-center rounded-full bg-blue-100 text-xs font-semibold text-blue-700",children:r.questionNumber||n+1}),t("span",{className:"text-sm font-medium text-gray-700",children:["Câu ",n+1]})]}),t("div",{className:"flex flex-wrap items-center gap-4",children:[e("div",{className:"w-52",children:t(g,{value:r.type,onValueChange:e=>((e,t)=>{F(r=>{const n=[...r],c=n[e];return c?(n[e]={...c,type:t,correctAnswer:R(t,c.correctAnswer.crossOut,c.correctAnswer.replaceWith||"")},n):r})})(n,e),children:[e(C,{children:e(f,{placeholder:"Loại câu"})}),t(x,{children:[e(N,{value:"CROSS_OUT",children:"Chỉ gạch (CROSS_OUT)"}),e(N,{value:"CROSS_OUT_AND_REPLACE",children:"Gạch + thay (CROSS_OUT_AND_REPLACE)"})]})]})}),t("div",{className:"flex items-center gap-2",children:[e(p,{id:`example-${n}`,checked:r.isExample||!1,onCheckedChange:e=>K(n,{isExample:e,points:e?0:1})}),t(i,{htmlFor:`example-${n}`,className:"flex cursor-pointer items-center gap-1 text-xs",children:[e(w,{className:"h-3 w-3 text-amber-500"}),"Example"]})]}),!r.isExample&&e("div",{className:"w-24",children:e(l,{value:r.points,allowZero:!0,onChange:e=>K(n,{points:_(e.target.value,!0)})})}),j.length>1&&e(s,{type:"button",variant:"ghost",size:"sm",onClick:()=>(e=>{F(t=>t.length<=1?t:t.filter((t,r)=>r!==e).map((e,t)=>({...e,questionNumber:t+1})))})(n),className:"text-red-500 hover:bg-red-50 hover:text-red-600",children:e(S,{className:"h-4 w-4"})})]})]}),t("div",{children:[e(i,{htmlFor:`question-${n}`,children:"Nội dung câu"}),e(o,{id:`question-${n}`,value:r.question,onChange:e=>K(n,{question:e.target.value}),placeholder:"Nhập câu gốc...",className:"mt-1 bg-white",rows:2})]}),t("div",{className:"grid gap-4 md:grid-cols-2",children:[t("div",{children:[t(i,{htmlFor:`crossout-${n}`,children:["Từ cần gạch (crossOut)","CROSS_OUT"===r.type&&e("span",{className:"ml-1 text-xs font-normal text-gray-500",children:"— để trống nếu câu đúng"})]}),e(a,{id:`crossout-${n}`,value:r.correctAnswer.crossOut,onChange:e=>Q(n,{crossOut:e.target.value}),placeholder:"CROSS_OUT"===r.type?"VD: to (hoặc trống)":"VD: have",className:"mt-1 bg-white"})]}),"CROSS_OUT_AND_REPLACE"===r.type&&t("div",{children:[e(i,{htmlFor:`replace-${n}`,children:"Từ thay thế (replaceWith)"}),e(a,{id:`replace-${n}`,value:r.correctAnswer.replaceWith||"",onChange:e=>Q(n,{replaceWith:e.target.value}),placeholder:"VD: has",className:"mt-1 bg-white"})]})]})]},n))})]}),t(h,{children:[e(u,{children:e(d,{className:"text-base",children:"Giải thích"})}),e(m,{children:e(o,{id:"explanation",value:V,onChange:e=>G(e.target.value),placeholder:"VD: Câu trả lời đúng là... vì...",rows:3})})]})]})]})}
@@ -0,0 +1,5 @@
1
+ export * from './CrossOutWordGroupCreator';
2
+ export * from './CrossOutWordGroupClient';
3
+ export * from './transform';
4
+ export * from './register';
5
+ export * from './map-cross-out-word-group-data';
@@ -0,0 +1 @@
1
+ export*from"./CrossOutWordGroupCreator";export*from"./CrossOutWordGroupClient";export*from"./transform";export*from"./register";export*from"./map-cross-out-word-group-data";
@@ -0,0 +1,6 @@
1
+ import type { CrossOutWordGroupData, CrossOutWordGroupItemAnswer, CrossOutWordGroupItemData, CrossOutWordItemMode } from '../../_shared/types/cross-out-word-group.type';
2
+ export declare const DEFAULT_CROSS_OUT_INSTRUCTION = "Cross out the extra or incorrect word. If the word is incorrect, write the correct word. If the line is correct, leave it blank.";
3
+ export declare function createCrossOutAnswer(type: CrossOutWordItemMode, crossOut?: string, replaceWith?: string): CrossOutWordGroupItemAnswer;
4
+ export declare function createEmptyCrossOutItem(questionNumber: number): CrossOutWordGroupItemData;
5
+ export declare function mapCrossOutWordGroupItem(item: unknown, index: number, fallbackAnswer?: CrossOutWordGroupItemAnswer): CrossOutWordGroupItemData;
6
+ export declare function mapQuestionToCrossOutWordGroupData(question: Record<string, unknown> | null | undefined): CrossOutWordGroupData;
@@ -0,0 +1 @@
1
+ export const DEFAULT_CROSS_OUT_INSTRUCTION="Cross out the extra or incorrect word. If the word is incorrect, write the correct word. If the line is correct, leave it blank.";function t(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function r(r){return t(r)?r:{}}function e(t,r=""){return"string"==typeof t?t:r}function n(t){return"CROSS_OUT_AND_REPLACE"===t?"CROSS_OUT_AND_REPLACE":"CROSS_OUT"}export function createCrossOutAnswer(t,r="",e=""){return"CROSS_OUT_AND_REPLACE"===t?{type:t,crossOut:r,replaceWith:e}:{type:"CROSS_OUT",crossOut:r}}export function createEmptyCrossOutItem(t){return{type:"CROSS_OUT",question:"",correctAnswer:createCrossOutAnswer("CROSS_OUT"),isExample:!1,points:1,questionNumber:t}}export function mapCrossOutWordGroupItem(o,s,i){const u=r(o),c=r(u.content),p=r(u.correctAnswer),a=t(p.answer)?p.answer:t(i)?i:{},O=n(c.type||a.type),m=!0===u.isExample;return{type:O,question:e(c.question)||e(u.question),correctAnswer:createCrossOutAnswer(O,e(a.crossOut),e(a.replaceWith)),isExample:m,points:m?0:"number"==typeof u.points?u.points:1,questionNumber:"number"==typeof u.questionNumber?u.questionNumber:s+1}}export function mapQuestionToCrossOutWordGroupData(o){const s=r(o),i=r(s.content),u=r(s.answer),c=r(s.correctAnswer??s.correct_answer??u.correctAnswer),p=String(s.explanation||u.explanation||""),a=Array.isArray(c.answer)?c.answer.map(r=>{if(t(r))return createCrossOutAnswer(n(r.type),e(r.crossOut),e(r.replaceWith))}):[];if(Array.isArray(i.items)){const t=i.items.map((t,r)=>mapCrossOutWordGroupItem(t,r,a[r]));return{instruction:e(r(i.meta).instruction)||DEFAULT_CROSS_OUT_INSTRUCTION,items:t,explanation:p,points:t.reduce((t,r)=>r.isExample?t:t+(r.points||0),0)}}return Array.isArray(u.items)?{instruction:e(u.instruction,DEFAULT_CROSS_OUT_INSTRUCTION),items:u.items.map((t,r)=>mapCrossOutWordGroupItem(t,r,a[r])),explanation:p,points:"number"==typeof u.points?u.points:void 0}:{instruction:DEFAULT_CROSS_OUT_INSTRUCTION,items:[createEmptyCrossOutItem(1)],explanation:p,points:1}}
@@ -0,0 +1,2 @@
1
+ import type { QuestionTypeRegistration } from '../../creator/question-type-registry';
2
+ export declare const crossOutWordGroupRegistration: QuestionTypeRegistration;
@@ -0,0 +1 @@
1
+ import{CrossOutWordGroupCreator as t}from"./CrossOutWordGroupCreator";import{mapQuestionToCrossOutWordGroupData as e}from"./map-cross-out-word-group-data";export const crossOutWordGroupRegistration={component:t,transformInitialData:t=>e(t),getExtraProps:t=>({onUnsavedChangesChange:t.onUnsavedChangesChange,validationRef:t.validationRef}),wrapOnSave:(t,e)=>{const n=t;return{type:e.questionType,content:e.state.content,points:n.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:n,explanation:n.explanation||""}},wrapOnChange:(t,e)=>{const n=t;return{type:e.questionType,content:e.state.content,points:n.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:n,explanation:n.explanation||""}}};
@@ -0,0 +1,2 @@
1
+ import type { TransformHandler } from '../../../../shared/lib/utils/question-transform-types';
2
+ export declare const transformCrossOutWordGroup: TransformHandler;
@@ -0,0 +1 @@
1
+ function t(t){return t.reduce((t,r)=>{if(r.isExample)return t;return t+("number"==typeof r.points?r.points:1)},0)}function r(t){return"CROSS_OUT_AND_REPLACE"===t?"CROSS_OUT_AND_REPLACE":"CROSS_OUT"}export const transformCrossOutWordGroup=e=>{const n=e.answer,o=Array.isArray(n?.items)?n.items:[];if(0===o.length)return{apiContent:{items:[]},apiCorrectAnswer:{answer:[]}};const s=o.map((t,e)=>{const n=r(t.type||t.correctAnswer?.type),o=function(t,e){const n=r(t?.type||e),o={type:n,crossOut:"string"==typeof t?.crossOut?t.crossOut.trim():""};return"CROSS_OUT_AND_REPLACE"===n&&(o.replaceWith="string"==typeof t?.replaceWith?t.replaceWith.trim():""),o}(t.correctAnswer,n);return{questionType:"CROSS_OUT_WORD",...t.isExample?{isExample:!0}:{},content:{type:n,question:t.question||""},correctAnswer:{answer:o},points:t.isExample?0:"number"==typeof t.points?t.points:1,questionNumber:t.questionNumber||e+1}});return{apiContent:{meta:{instruction:n?.instruction||"Cross out the extra or incorrect word. If the word is incorrect, write the correct word."},items:s},apiCorrectAnswer:{answer:s.map(t=>t.correctAnswer.answer)},totalPoints:t(o)}};
@@ -0,0 +1,2 @@
1
+ import type { TrueFalseGroupClientProps } from '../../_shared/types/true-false-group.type';
2
+ export declare function TrueFalseGroupClient({ questionData, isReviewMode, userAnswers, }: TrueFalseGroupClientProps): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{Check as t,CircleHelp as s,Lightbulb as a,Star as i,X as l}from"lucide-react";import{cn as n}from"../../../../shared/lib/utils";export function TrueFalseGroupClient({questionData:d,isReviewMode:o=!1,userAnswers:m=[]}){const c=d.items||[];return r("div",{className:"space-y-4",children:[d.instruction&&e("div",{className:"rounded-xl border border-indigo-100 bg-indigo-50 px-4 py-3 text-sm font-medium text-indigo-800",children:d.instruction}),c.map((a,d)=>{const c=m[d],x=a.correctAnswer;return r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("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:[r("div",{className:"flex items-center gap-2",children:[e("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:e(s,{className:"h-3.5 w-3.5"})}),r("span",{className:"text-sm font-medium text-gray-700",children:["Câu ",a.questionNumber||d+1]}),a.isExample&&r("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:[e(i,{className:"h-3 w-3"}),"Example"]})]}),r("span",{className:"text-xs text-gray-500",children:[a.points||0," điểm"]})]}),r("div",{className:"space-y-3 p-4",children:[e("p",{className:"text-sm font-semibold leading-relaxed text-gray-800",children:a.question||"Câu hỏi chưa được nhập"}),e("div",{className:"flex items-center gap-3",children:[{value:!0,label:"True"},{value:!1,label:"False"}].map(s=>{const a=s.value===x,i=s.value===c;return r("div",{className:n("flex flex-1 items-center justify-center gap-2 rounded-lg border-2 px-4 py-2 text-sm font-semibold transition-colors",o&&a?"border-green-500 bg-green-50 text-green-700":o&&i&&!a?"border-red-500 bg-red-50 text-red-700":i?"border-blue-500 bg-blue-50 text-blue-700":"border-gray-200 bg-white text-gray-700"),children:[s.value?e(t,{className:"h-4 w-4"}):e(l,{className:"h-4 w-4"}),e("span",{children:s.label})]},String(s.value))})})]})]},`${a.questionNumber}-${d}`)}),o&&d.explanation&&r("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:[e(a,{className:"mt-0.5 h-4 w-4 flex-shrink-0"}),d.explanation]})]})}
@@ -0,0 +1,2 @@
1
+ import type { TrueFalseGroupCreatorProps } from '../../_shared/types/true-false-group.type';
2
+ export declare function TrueFalseGroupCreator({ initialData, onChange, externalErrors, onUnsavedChangesChange, validationRef, }: TrueFalseGroupCreatorProps): import("react").JSX.Element;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useEffect as n,useRef as r,useState as i}from"react";import{Button as s}from"../../../../components/ui/button";import{Label as a}from"../../../../components/ui/label";import{Input as c}from"../../../../components/ui/input";import{Textarea as l}from"../../../../components/ui/textarea";import{PointsInput as o}from"../../../../components/ui/points-input";import{Card as m,CardContent as h,CardHeader as u,CardTitle as d}from"../../../../components/ui/card";import{Switch as p}from"../../../../components/ui/switch";import{useDebouncedCallback as g}from"../../../../shared/lib/hooks";import{Eye as x,Pencil as N,Plus as f,Star as b,Trash2 as v}from"lucide-react";import{TrueFalseGroupClient as y}from"./TrueFalseGroupClient";function w(e,t=!1){if(""===e)return t?0:1;const n=parseInt(e.replace(/[^0-9]/g,""),10);if(Number.isNaN(n))return t?0:1;const r=t?0:1;return Math.max(r,n)}function C(e){return{question:"",correctAnswer:!0,isExample:!1,points:1,questionNumber:e}}function q(e){return e.reduce((e,t)=>t.isExample?e:e+("number"==typeof t.points?t.points:1),0)}export function TrueFalseGroupCreator({initialData:k,onChange:E,externalErrors:T,onUnsavedChangesChange:A,validationRef:F}){const[j,D]=i(k?.instruction||"Tick True or False."),[z,$]=i(()=>{return e=k?.items,Array.isArray(e)&&0!==e.length?e.map((e,t)=>({question:e.question||"",correctAnswer:"boolean"!=typeof e.correctAnswer||e.correctAnswer,isExample:!0===e.isExample,points:e.isExample?0:"number"==typeof e.points?e.points:1,questionNumber:e.questionNumber||t+1})):[C(1)];var e}),[G,H]=i(k?.explanation||""),[I,V]=i(!1),[S,X]=i([]),J=r(E),M=r("");n(()=>{J.current=E},[E]);const O=(e=j,t=z,n=G)=>({instruction:e,items:t,explanation:n,points:q(t)}),R=g(e=>{J.current?.(e)},300);n(()=>{const e=O(),t=JSON.stringify(e);t!==M.current&&(M.current=t,R(e),A?.(!0))},[j,z,G,R,A]);n(()=>{F&&(F.current={triggerValidation:async()=>(()=>{const e=[];return j.trim()||e.push("Hướng dẫn (Instruction) không được để trống."),0===z.length&&e.push("Cần ít nhất một câu hỏi trong nhóm."),z.forEach((t,n)=>{t.question.trim()||e.push(`Câu ${n+1}: Nội dung câu hỏi không được để trống.`)}),X(e),0===e.length})(),getFormData:()=>O()})},[F,j,z,G]);const U=(e,t)=>{$(n=>{const r=[...n],i=r[e];return i?(r[e]={...i,...t},r):n})},Z=O(),B=T&&T.length>0?T:S;return t("div",{className:"space-y-6",children:[t("div",{className:"flex items-center justify-between",children:[t("div",{children:[e("h3",{className:"text-lg font-medium text-gray-900",children:"Tạo câu hỏi Đúng / Sai (Nhóm)"}),e("p",{className:"text-sm text-gray-500",children:"Thêm danh sách các câu hỏi True/False trong 1 nhóm"})]}),t(s,{type:"button",variant:"outline",size:"sm",onClick:()=>V(e=>!e),className:"gap-2",children:[e(I?N:x,{className:"h-4 w-4"}),I?"Chế độ chỉnh sửa":"Xem trước học sinh"]})]}),B.length>0&&e("div",{className:"rounded-lg bg-red-50 p-4 border border-red-200",children:e("div",{className:"flex",children:t("div",{className:"ml-3",children:[e("h3",{className:"text-sm font-medium text-red-800",children:"Cần sửa các lỗi sau:"}),e("div",{className:"mt-2 text-sm text-red-700",children:e("ul",{className:"list-disc space-y-1 pl-5",children:B.map((t,n)=>e("li",{children:t},n))})})]})})}),I?t(m,{children:[e(u,{children:e(d,{className:"text-base font-semibold",children:"Xem trước hiển thị học sinh"})}),e(h,{children:e(y,{questionData:Z})})]}):t("div",{className:"space-y-6",children:[t(m,{children:[e(u,{children:e(d,{className:"text-base font-semibold",children:"Hướng dẫn chung (Instruction)"})}),e(h,{className:"space-y-4",children:t("div",{children:[e(a,{htmlFor:"instruction",children:"Hướng dẫn bài làm"}),e(c,{id:"instruction",value:j,onChange:e=>D(e.target.value),placeholder:"VD: Tick True or False.",className:"mt-1"})]})})]}),t(m,{children:[t(u,{className:"flex flex-row items-center justify-between",children:[t(d,{className:"text-base font-semibold",children:["Danh sách câu hỏi (",z.length,")"]}),t(s,{type:"button",variant:"outline",size:"sm",onClick:()=>{$(e=>[...e,C(e.length+1)])},className:"gap-2",children:[e(f,{className:"h-4 w-4"}),"Thêm câu hỏi"]})]}),e(h,{className:"space-y-4",children:z.map((n,r)=>t("div",{className:"space-y-4 rounded-lg border border-gray-200 bg-gray-50/50 p-4 transition-colors hover:border-gray-300",children:[t("div",{className:"flex items-center justify-between gap-4",children:[t("div",{className:"flex items-center gap-2",children:[e("span",{className:"flex h-7 w-7 items-center justify-center rounded-full bg-blue-100 text-xs font-semibold text-blue-700",children:n.questionNumber||r+1}),t("span",{className:"text-sm font-medium text-gray-700",children:["Câu hỏi ",r+1]})]}),t("div",{className:"flex items-center gap-4",children:[t("div",{className:"flex items-center gap-2",children:[e(p,{id:`example-${r}`,checked:n.isExample||!1,onCheckedChange:e=>U(r,{isExample:e,points:e?0:1})}),t(a,{htmlFor:`example-${r}`,className:"flex items-center gap-1 text-xs cursor-pointer",children:[e(b,{className:"h-3 w-3 text-amber-500"}),"Câu mẫu (Example)"]})]}),!n.isExample&&e("div",{className:"w-24",children:e(o,{value:n.points,allowZero:!0,onChange:e=>U(r,{points:w(e.target.value,!0)})})}),z.length>1&&e(s,{type:"button",variant:"ghost",size:"sm",onClick:()=>(e=>{$(t=>t.length<=1?t:t.filter((t,n)=>n!==e).map((e,t)=>({...e,questionNumber:t+1})))})(r),className:"text-red-500 hover:bg-red-50 hover:text-red-600",children:e(v,{className:"h-4 w-4"})})]})]}),t("div",{children:[e(a,{htmlFor:`question-${r}`,children:"Nội dung câu hỏi"}),e(l,{id:`question-${r}`,value:n.question,onChange:e=>U(r,{question:e.target.value}),placeholder:"Nhập nội dung câu hỏi...",className:"mt-1 bg-white",rows:2})]}),t("div",{children:[e(a,{className:"mb-2 block text-xs font-medium text-gray-700",children:"Đáp án đúng"}),t("div",{className:"flex items-center gap-4",children:[e(s,{type:"button",variant:!0===n.correctAnswer?"default":"outline",size:"sm",onClick:()=>U(r,{correctAnswer:!0}),className:"w-24",children:"True"}),e(s,{type:"button",variant:!1===n.correctAnswer?"default":"outline",size:"sm",onClick:()=>U(r,{correctAnswer:!1}),className:"w-24",children:"False"})]})]})]},r))})]}),t(m,{children:[e(u,{children:e(d,{className:"text-base",children:"Giải thích"})}),e(h,{children:e(l,{id:"explanation",value:G,onChange:e=>H(e.target.value),placeholder:"VD: Câu trả lời đúng là... vì...",rows:3})})]})]})]})}
@@ -0,0 +1,5 @@
1
+ export * from './TrueFalseGroupCreator';
2
+ export * from './TrueFalseGroupClient';
3
+ export * from './transform';
4
+ export * from './register';
5
+ export * from './map-true-false-group-data';
@@ -0,0 +1 @@
1
+ export*from"./TrueFalseGroupCreator";export*from"./TrueFalseGroupClient";export*from"./transform";export*from"./register";export*from"./map-true-false-group-data";
@@ -0,0 +1,4 @@
1
+ import type { TrueFalseGroupData, TrueFalseGroupItemData } from '../../_shared/types/true-false-group.type';
2
+ export declare function createEmptyTrueFalseGroupItem(questionNumber: number): TrueFalseGroupItemData;
3
+ export declare function mapTrueFalseGroupItem(item: unknown, index: number, fallbackAnswer?: boolean): TrueFalseGroupItemData;
4
+ export declare function mapQuestionToTrueFalseGroupData(question: Record<string, unknown> | null | undefined): TrueFalseGroupData;
@@ -0,0 +1 @@
1
+ function e(e){return function(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}(e)?e:{}}function t(e,t=""){return"string"==typeof e?e:t}export function createEmptyTrueFalseGroupItem(e){return{question:"",correctAnswer:!0,isExample:!1,points:1,questionNumber:e}}export function mapTrueFalseGroupItem(r,n,o){const i=e(r),s=e(i.content),a=e(i.correctAnswer),u=!0===i.isExample,p="boolean"==typeof a.answer?a.answer:"boolean"!=typeof o||o;return{question:t(s.question)||t(i.question),correctAnswer:p,isExample:u,points:u?0:"number"==typeof i.points?i.points:1,questionNumber:"number"==typeof i.questionNumber?i.questionNumber:n+1}}export function mapQuestionToTrueFalseGroupData(r){const n=e(r),o=e(n.content),i=e(n.answer),s=e(n.correctAnswer??n.correct_answer??i.correctAnswer),a=String(n.explanation||i.explanation||""),u=Array.isArray(s.answer)?s.answer.map(e=>"boolean"==typeof e?e:void 0):[];if(Array.isArray(o.items)){const r=o.items.map((e,t)=>mapTrueFalseGroupItem(e,t,u[t]));return{instruction:t(e(o.meta).instruction)||"Tick True or False.",items:r,explanation:a,points:r.reduce((e,t)=>t.isExample?e:e+(t.points||0),0)}}return Array.isArray(i.items)?{instruction:t(i.instruction,"Tick True or False."),items:i.items.map((e,t)=>mapTrueFalseGroupItem(e,t,u[t])),explanation:a,points:"number"==typeof i.points?i.points:void 0}:{instruction:"Tick True or False.",items:[createEmptyTrueFalseGroupItem(1)],explanation:a,points:1}}
@@ -0,0 +1,2 @@
1
+ import type { QuestionTypeRegistration } from '../../creator/question-type-registry';
2
+ export declare const trueFalseGroupRegistration: QuestionTypeRegistration;
@@ -0,0 +1 @@
1
+ import{TrueFalseGroupCreator as t}from"./TrueFalseGroupCreator";import{mapQuestionToTrueFalseGroupData as e}from"./map-true-false-group-data";export const trueFalseGroupRegistration={component:t,transformInitialData:t=>e(t),getExtraProps:t=>({onUnsavedChangesChange:t.onUnsavedChangesChange,validationRef:t.validationRef}),wrapOnSave:(t,e)=>{const n=t;return{type:e.questionType,content:e.state.content,points:n.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:n,explanation:n.explanation||""}},wrapOnChange:(t,e)=>{const n=t;return{type:e.questionType,content:e.state.content,points:n.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:n,explanation:n.explanation||""}}};
@@ -0,0 +1,2 @@
1
+ import type { TransformHandler } from '../../../../shared/lib/utils/question-transform-types';
2
+ export declare const transformTrueFalseGroup: TransformHandler;
@@ -0,0 +1 @@
1
+ function e(e){return e.reduce((e,r)=>{if(r.isExample)return e;return e+("number"==typeof r.points?r.points:1)},0)}export const transformTrueFalseGroup=r=>{const t=r.answer,n=Array.isArray(t?.items)?t.items:[];if(0===n.length)return{apiContent:{items:[]},apiCorrectAnswer:{answer:[]}};const s=n.map((e,r)=>{const t=!("boolean"==typeof e.correctAnswer)||e.correctAnswer;return{questionType:"TRUE_FALSE",...e.isExample?{isExample:!0}:{},content:{question:e.question||""},correctAnswer:{answer:t},points:e.isExample?0:"number"==typeof e.points?e.points:1,questionNumber:e.questionNumber||r+1}});return{apiContent:{meta:{instruction:t?.instruction||"Tick True or False."},items:s},apiCorrectAnswer:{answer:s.map(e=>e.correctAnswer.answer)},totalPoints:e(n)}};
@@ -1,2 +1,3 @@
1
1
  export { WordFillStructuredFormCreator } from './WordFillStructuredFormCreator';
2
2
  export { WordFillStructuredFormClient } from './WordFillStructuredFormClient';
3
+ export { mapQuestionToWfsfData } from './map-wfsf-question-data';
@@ -1 +1 @@
1
- export{WordFillStructuredFormCreator}from"./WordFillStructuredFormCreator";export{WordFillStructuredFormClient}from"./WordFillStructuredFormClient";
1
+ export{WordFillStructuredFormCreator}from"./WordFillStructuredFormCreator";export{WordFillStructuredFormClient}from"./WordFillStructuredFormClient";export{mapQuestionToWfsfData}from"./map-wfsf-question-data";
@@ -0,0 +1,7 @@
1
+ import type { WordFillStructuredFormData } from '../../_shared/types/word-fill-structured-form.type';
2
+ export declare function extractWfsfBlankKeys(html: string): string[];
3
+ /**
4
+ * Map preview / exam / creator payloads onto WordFillStructuredFormClient data.
5
+ * School preview puts answers on `answer` + `correctAnswer`; creator uses `answer`.
6
+ */
7
+ export declare function mapQuestionToWfsfData(question: Record<string, unknown> | null | undefined): WordFillStructuredFormData;
@@ -0,0 +1 @@
1
+ import{detectWfsfBankMode as t,normalizeOptionsWordBank as n,normalizeSharedWordBank as e}from"./wfsf-word-bank.utils";function r(t){return t&&"object"==typeof t&&!Array.isArray(t)?t:{}}function o(t){const n=r(t),e={};for(const[t,r]of Object.entries(n))"string"==typeof r&&(e[t]=r);return e}function i(t){if("letter"===t||"word"===t||"phrase"===t||"translate"===t)return t}export function extractWfsfBlankKeys(t){const n=new Set,e=/\{([\w\d]+)\}/g;let r;for(;null!==(r=e.exec(t));)n.add(r[1]);return Array.from(n).sort((t,n)=>{const e=parseInt(t,10),r=parseInt(n,10);return Number.isNaN(e)||Number.isNaN(r)?t.localeCompare(n):e-r})}export function mapQuestionToWfsfData(a){const s=r(a),l=r(s.content),c=r(s.answer),u=r(s.correctAnswer??s.correct_answer??c.correctAnswer??c),p=s.total_points?parseFloat(String(s.total_points)):c.points??s.points??1,g=Number.isFinite(Number(p))?Number(p):1,f=String(c.instruction||s.instruction||s.explanation||""),S=String(c.explanation||""),w=function(t,n){const e=t.content||n.content||"";if("string"==typeof e&&e)return e;const r=t.blocks||n.blocks;return r?.length?r.map(t=>(t.heading?`<h3>${t.heading}</h3>`:"")+(t.content||"")).join(""):"string"==typeof e?e:""}(l,c),m=l.wordBank??c.wordBank,b=l.viewMode??c.viewMode,d=t(b,m),y=extractWfsfBlankKeys(String(w||"")),k="FREE_TYPE"===d?void 0:d,N="WITH_WORD_BANK"===d?e(m):"WITH_OPTIONS"===d?n(m,y):void 0,v=r(r(s.questionGroup).payload);return{title:String(l.title||c.title||""),imageUrl:String(l.imageUrl||c.imageUrl||""),content:w,answers:o(u.answers||c.answers),caseSensitive:Boolean(u.caseSensitive??c.caseSensitive??!1),blankStyle:i(l.blankStyle??c.blankStyle),viewMode:k,wordBank:N,instruction:f,explanation:S,points:g,groupTitle:String(v.title||c.groupTitle||""),groupSubtitle:String(v.subtitle||c.groupSubtitle||""),groupContent:String(v.content||c.groupContent||""),groupImageUrl:String(v.imageUrl||c.groupImageUrl||"")}}
@@ -1 +1 @@
1
- import{WordFillStructuredFormCreator as t}from"./WordFillStructuredFormCreator";import{detectWfsfBankMode as e,normalizeOptionsWordBank as n,normalizeSharedWordBank as o}from"./wfsf-word-bank.utils";export const wordFillStructuredFormRegistration={component:t,transformInitialData:t=>{const i=t?.content||{},a=t?.answer||{},r=t?.correctAnswer||a?.correctAnswer||{},s=t?.total_points?parseFloat(t.total_points):a?.points||t?.points||1,l=String(a?.instruction||t?.instruction||t?.explanation||""),p=String(a?.explanation||"");let u=i?.content||a?.content||"";const c=i?.blocks||a?.blocks;!u&&c?.length&&(u=c.map(t=>(t.heading?`<h3>${t.heading}</h3>`:"")+(t.content||"")).join(""));const g=i?.wordBank??a?.wordBank,d=e(i?.viewMode??a?.viewMode,g),w=function(t){const e=new Set,n=/\{([\w\d]+)\}/g;let o;for(;null!==(o=n.exec(t));)e.add(o[1]);return Array.from(e).sort((t,e)=>{const n=parseInt(t,10),o=parseInt(e,10);return Number.isNaN(n)||Number.isNaN(o)?t.localeCompare(e):n-o})}(String(u||""));let f=g,m="FREE_TYPE"===d?void 0:d;"WITH_WORD_BANK"===d?(f=o(g),m="WITH_WORD_BANK"):"WITH_OPTIONS"===d?(f=n(g,w),m="WITH_OPTIONS"):f=void 0;const v=t?.questionGroup?.payload;return{title:i?.title||a?.title||"",imageUrl:i?.imageUrl||a?.imageUrl||"",content:u,answers:r?.answers||a?.answers||{},caseSensitive:r?.caseSensitive??a?.caseSensitive??!1,blankStyle:i?.blankStyle??a?.blankStyle,viewMode:m,wordBank:f,instruction:l,explanation:p,points:s,groupTitle:v?.title||a?.groupTitle||"",groupSubtitle:v?.subtitle||a?.groupSubtitle||"",groupContent:v?.content||a?.groupContent||"",groupImageUrl:v?.imageUrl||a?.groupImageUrl||""}},getExtraProps:t=>({onUnsavedChangesChange:t.onUnsavedChangesChange,validationRef:t.validationRef,groupConfig:t.groupConfig,groupType:t.groupType,groups:t.groups,questionIndexInPart:t.questionIndexInPart,partId:t.partId,viewMode:t.viewMode}),wrapOnSave:(t,e)=>({type:e.questionType,content:e.state.content,points:t?.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:t,explanation:t?.explanation||""}),wrapOnChange:(t,e)=>({type:e.questionType,content:e.state.content,points:t?.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:t,explanation:t?.explanation||""})};
1
+ import{WordFillStructuredFormCreator as t}from"./WordFillStructuredFormCreator";import{mapQuestionToWfsfData as e}from"./map-wfsf-question-data";export const wordFillStructuredFormRegistration={component:t,transformInitialData:t=>e(t),getExtraProps:t=>({onUnsavedChangesChange:t.onUnsavedChangesChange,validationRef:t.validationRef,groupConfig:t.groupConfig,groupType:t.groupType,groups:t.groups,questionIndexInPart:t.questionIndexInPart,partId:t.partId,viewMode:t.viewMode}),wrapOnSave:(t,e)=>({type:e.questionType,content:e.state.content,points:t?.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:t,explanation:t?.explanation||""}),wrapOnChange:(t,e)=>({type:e.questionType,content:e.state.content,points:t?.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,answer:t,explanation:t?.explanation||""})};
@@ -1 +1 @@
1
- export const transformWordFillStructuredForm=e=>{const r=e.answer;if(!r?.content||!r?.answers)return{apiContent:{},apiCorrectAnswer:{}};const t=!!(r.groupTitle||r.groupSubtitle||r.groupContent||r.groupImageUrl),n={title:r.title||"",imageUrl:r.imageUrl||"",content:r.content};r.blankStyle&&(n.blankStyle=r.blankStyle),r.viewMode&&(n.viewMode=r.viewMode),Array.isArray(r.wordBank)&&r.wordBank.length>0&&(n.wordBank=r.wordBank),"letter"!==r.blankStyle&&"word"!==r.blankStyle&&"phrase"!==r.blankStyle||(n.blankStyle=r.blankStyle),"WITH_OPTIONS"!==r.viewMode&&"WITH_WORD_BANK"!==r.viewMode||(n.viewMode=r.viewMode),Array.isArray(r.wordBank)&&(n.wordBank=r.wordBank);return{apiContent:n,apiCorrectAnswer:{answers:r.answers,caseSensitive:r.caseSensitive??!1},basicGroupData:t?{title:r.groupTitle||"",subtitle:r.groupSubtitle||"",content:r.groupContent||"",imageUrl:r.groupImageUrl||""}:void 0,groupNumber:r.groupNumber||1}};
1
+ export const transformWordFillStructuredForm=e=>{const t=e.answer;if(!t?.content||!t?.answers)return{apiContent:{},apiCorrectAnswer:{}};const r=!!(t.groupTitle||t.groupSubtitle||t.groupContent||t.groupImageUrl),n={title:t.title||"",imageUrl:t.imageUrl||"",content:t.content};"letter"!==t.blankStyle&&"word"!==t.blankStyle&&"phrase"!==t.blankStyle&&"translate"!==t.blankStyle||(n.blankStyle=t.blankStyle),"WITH_OPTIONS"!==t.viewMode&&"WITH_WORD_BANK"!==t.viewMode||(n.viewMode=t.viewMode),Array.isArray(t.wordBank)&&(n.wordBank=t.wordBank);return{apiContent:n,apiCorrectAnswer:{answers:t.answers,caseSensitive:t.caseSensitive??!1},basicGroupData:r?{title:t.groupTitle||"",subtitle:t.groupSubtitle||"",content:t.groupContent||"",imageUrl:t.groupImageUrl||""}:void 0,groupNumber:t.groupNumber||1}};
@@ -0,0 +1,8 @@
1
+ import type { Question } from '../../../shared/types/entities/question.types';
2
+ type ChooseTheCorrectAnswerGroupViewerProps = {
3
+ question: Question;
4
+ isReviewMode?: boolean;
5
+ userAnswer?: string[];
6
+ };
7
+ export declare function ChooseTheCorrectAnswerGroupViewer({ question, isReviewMode, userAnswer, }: ChooseTheCorrectAnswerGroupViewerProps): import("react").JSX.Element;
8
+ export {};
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e}from"react/jsx-runtime";import{ChooseTheCorrectAnswerGroupClient as r}from"../types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupClient";import{mapQuestionToChooseAnswerGroupData as o}from"../types/choose-the-correct-answer-group/map-choose-the-correct-answer-group-data";export function ChooseTheCorrectAnswerGroupViewer({question:s,isReviewMode:t=!1,userAnswer:c}){const n=o(s),i=t&&!c?n.items.map(e=>e.correctAnswer):c;return e(r,{questionData:n,isReviewMode:t,userAnswers:i})}
@@ -0,0 +1,7 @@
1
+ import type { Question } from '../../../shared/types/entities/question.types';
2
+ type CrossOutWordGroupViewerProps = {
3
+ question: Question;
4
+ isReviewMode?: boolean;
5
+ };
6
+ export declare function CrossOutWordGroupViewer({ question, isReviewMode, }: CrossOutWordGroupViewerProps): import("react").JSX.Element;
7
+ export {};