@tinyweb_dev/oe-exam-sdk 0.1.30 → 0.1.32

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 (80) hide show
  1. package/dist/components/exams/ExamPreviewDialog.d.ts +9 -3
  2. package/dist/components/exams/ExamPreviewDialog.js +23 -5
  3. package/dist/components/exams/ExamPreviewPartContent.d.ts +2 -1
  4. package/dist/components/exams/ExamPreviewPartContent.js +3 -2
  5. package/dist/components/exams/ExamPreviewSidebar.d.ts +3 -1
  6. package/dist/components/exams/ExamPreviewSidebar.js +7 -2
  7. package/dist/components/exams/exam-preview.mode.d.ts +4 -0
  8. package/dist/components/exams/exam-preview.mode.js +5 -0
  9. package/dist/components/exams/index.d.ts +1 -0
  10. package/dist/components/exams/index.js +1 -0
  11. package/dist/components/exams/take/components/QuestionRenderer.js +10 -2
  12. package/dist/components/exams/take/components/question-renderers/MoversCrosswordPuzzleRenderer.d.ts +3 -0
  13. package/dist/components/exams/take/components/question-renderers/MoversCrosswordPuzzleRenderer.js +285 -0
  14. package/dist/components/exams/take/components/question-renderers/index.d.ts +1 -0
  15. package/dist/components/exams/take/components/question-renderers/index.js +1 -0
  16. package/dist/components/exams/take/types.d.ts +30 -0
  17. package/dist/components/exams/take/utils/answer-transformers.js +37 -6
  18. package/dist/components/exams/take/utils/question-transformers.d.ts +28 -1
  19. package/dist/components/exams/take/utils/question-transformers.js +69 -0
  20. package/dist/components/questions/_shared/config/question-types.config.js +12 -0
  21. package/dist/components/questions/_shared/types/answer-the-question-group.type.d.ts +32 -0
  22. package/dist/components/questions/_shared/types/answer-the-question-group.type.js +1 -0
  23. package/dist/components/questions/_shared/types/crossword-puzzle.type.d.ts +16 -0
  24. package/dist/components/questions/_shared/types/crossword-puzzle.type.js +1 -0
  25. package/dist/components/questions/components/QuestionSearchDropdown.js +1 -1
  26. package/dist/components/questions/creator/question-type-registry.js +4 -0
  27. package/dist/components/questions/question-bank/QuestionEditorRenderer.d.ts +2 -1
  28. package/dist/components/questions/question-bank/QuestionEditorRenderer.js +16 -0
  29. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupClient.d.ts +2 -0
  30. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupClient.js +13 -0
  31. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupCreator.d.ts +2 -0
  32. package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupCreator.js +183 -0
  33. package/dist/components/questions/types/answer-the-question-group/index.d.ts +5 -0
  34. package/dist/components/questions/types/answer-the-question-group/index.js +5 -0
  35. package/dist/components/questions/types/answer-the-question-group/map-answer-the-question-group-data.d.ts +4 -0
  36. package/dist/components/questions/types/answer-the-question-group/map-answer-the-question-group-data.js +83 -0
  37. package/dist/components/questions/types/answer-the-question-group/register.d.ts +2 -0
  38. package/dist/components/questions/types/answer-the-question-group/register.js +36 -0
  39. package/dist/components/questions/types/answer-the-question-group/transform.d.ts +2 -0
  40. package/dist/components/questions/types/answer-the-question-group/transform.js +72 -0
  41. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleClient.d.ts +11 -0
  42. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleClient.js +69 -0
  43. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleCreator.d.ts +8 -0
  44. package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleCreator.js +213 -0
  45. package/dist/components/questions/types/crossword-puzzle/index.d.ts +4 -0
  46. package/dist/components/questions/types/crossword-puzzle/index.js +4 -0
  47. package/dist/components/questions/types/crossword-puzzle/register.d.ts +2 -0
  48. package/dist/components/questions/types/crossword-puzzle/register.js +29 -0
  49. package/dist/components/questions/types/crossword-puzzle/transform.d.ts +2 -0
  50. package/dist/components/questions/types/crossword-puzzle/transform.js +75 -0
  51. package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +1 -1
  52. package/dist/components/questions/viewer/QuestionViewer.js +9 -6
  53. package/dist/components/questions/viewer/SpontaneousQaGroupViewer.js +4 -4
  54. package/dist/components/results/ReviewQuestionRenderer.js +1 -0
  55. package/dist/components/results/renderers/ReviewAnswerTheQuestionGroupRenderer.d.ts +19 -0
  56. package/dist/components/results/renderers/ReviewAnswerTheQuestionGroupRenderer.js +27 -0
  57. package/dist/components/results/renderers/review-question-body-dedicated.d.ts +1 -0
  58. package/dist/components/results/renderers/review-question-body-dedicated.js +47 -2
  59. package/dist/components/results/renderers/review-question-body-movers.js +7 -2
  60. package/dist/components/results/review-data.js +20 -4
  61. package/dist/index.d.ts +1 -1
  62. package/dist/index.js +1 -1
  63. package/dist/shared/constants/question-skills.js +4 -0
  64. package/dist/shared/lib/i18n/messages/en/admin.d.ts +5 -0
  65. package/dist/shared/lib/i18n/messages/en/admin.js +5 -0
  66. package/dist/shared/lib/i18n/messages/en.d.ts +5 -0
  67. package/dist/shared/lib/i18n/messages/vi/admin.d.ts +5 -0
  68. package/dist/shared/lib/i18n/messages/vi/admin.js +5 -0
  69. package/dist/shared/lib/i18n/messages/vi.d.ts +5 -0
  70. package/dist/shared/lib/utils/question-reverse-transform.js +93 -0
  71. package/dist/shared/lib/utils/question-transform-validation.js +12 -0
  72. package/dist/shared/lib/utils/question-transform.js +4 -0
  73. package/dist/shared/types/common.types.d.ts +1 -1
  74. package/dist/shared/types/questions/answer-the-question-group.d.ts +39 -0
  75. package/dist/shared/types/questions/answer-the-question-group.js +1 -0
  76. package/dist/shared/types/questions/crossword-puzzle.d.ts +50 -0
  77. package/dist/shared/types/questions/crossword-puzzle.js +10 -0
  78. package/dist/shared/types/questions/index.d.ts +2 -0
  79. package/dist/shared/types/questions/index.js +4 -0
  80. package/package.json +1 -1
@@ -54,11 +54,23 @@ export function validateQuestionForTransform(question) {
54
54
  case 'WRITE_A_SHORT_LETTER':
55
55
  validateWordLimits(answer, errors);
56
56
  break;
57
+ case 'CROSSWORD_PUZZLE':
58
+ validateCrossword(content, answer, errors);
59
+ break;
57
60
  default:
58
61
  break;
59
62
  }
60
63
  return { isValid: errors.length === 0, errors };
61
64
  }
65
+ function validateCrossword(content, answer, errors) {
66
+ const clues = (content?.clues || answer?.clues);
67
+ const hasAcrossOrDown = (Array.isArray(clues?.across) && clues.across.length > 0) ||
68
+ (Array.isArray(clues?.down) && clues.down.length > 0) ||
69
+ (Array.isArray(clues) && clues.length > 0);
70
+ if (!hasAcrossOrDown) {
71
+ errors.push('Cần ít nhất 1 gợi ý (Across hoặc Down) cho bài ô chữ');
72
+ }
73
+ }
62
74
  function validateGrid(content, answer, errors) {
63
75
  if (!Array.isArray(content?.grid))
64
76
  errors.push('Grid is required for FILL_MISSING_WORDS_IN_GRID');
@@ -17,6 +17,7 @@ import { transformFillInBlank } from '../../../components/questions/types/fill-i
17
17
  import { transformWriteCorrectVerbForm } from '../../../components/questions/types/write-correct-verb-form/transform';
18
18
  import { transformChooseCorrectAdjective } from '../../../components/questions/types/choose-correct-adjective/transform';
19
19
  import { transformAnswerTheQuestion } from '../../../components/questions/types/answer-the-question/transform';
20
+ import { transformAnswerTheQuestionGroup } from '../../../components/questions/types/answer-the-question-group/transform';
20
21
  import { transformTrueFalse } from '../../../components/questions/types/true-false/transform';
21
22
  import { transformWordOrdering } from '../../../components/questions/types/word-ordering/transform';
22
23
  import { transformWordFillParagraph } from '../../../components/questions/types/word-fill-paragraph/transform';
@@ -40,6 +41,7 @@ import { transformSpeakingConversation } from '../../../components/questions/typ
40
41
  import { transformSpeakingCueCard } from '../../../components/questions/types/speaking-cue-card/transform';
41
42
  import { transformGNSpeakingInterview } from '../../../components/questions/types/gn-speaking-interview/transform';
42
43
  import { transformWordFillStructuredForm } from '../../../components/questions/types/word-fill-structured-form/transform';
44
+ import { transformCrosswordPuzzle } from '../../../components/questions/types/crossword-puzzle/transform';
43
45
  // ─── Handler map ────────────────────────────────────────────────────────────
44
46
  const questionTransformHandlers = {
45
47
  // Look picture
@@ -63,6 +65,7 @@ const questionTransformHandlers = {
63
65
  WRITE_CORRECT_VERB_FORM: transformWriteCorrectVerbForm,
64
66
  CHOOSE_CORRECT_ADJECTIVE: transformChooseCorrectAdjective,
65
67
  ANSWER_THE_QUESTION: transformAnswerTheQuestion,
68
+ ANSWER_THE_QUESTION_GROUP: transformAnswerTheQuestionGroup,
66
69
  TRUE_FALSE: transformTrueFalse,
67
70
  WORD_ORDERING: transformWordOrdering,
68
71
  WORD_FILL_PARAGRAPH: transformWordFillParagraph,
@@ -86,6 +89,7 @@ const questionTransformHandlers = {
86
89
  SPEAKING_CUE_CARD: transformSpeakingCueCard,
87
90
  GN_SPEAKING_INTERVIEW: transformGNSpeakingInterview,
88
91
  WORD_FILL_STRUCTURED_FORM: transformWordFillStructuredForm,
92
+ CROSSWORD_PUZZLE: transformCrosswordPuzzle,
89
93
  };
90
94
  /**
91
95
  * Transform frontend question format to API format.
@@ -29,7 +29,7 @@ export declare enum StudentSelectionType {
29
29
  }
30
30
  export type ResultStatus = 'PENDING' | 'PARTIAL_GRADED' | 'GRADED';
31
31
  export type StudentStatus = 'NOT_STARTED' | 'IN_PROGRESS' | 'SUBMITTED';
32
- export type QuestionType = 'FILL_IN_BLANK' | 'TRUE_FALSE' | 'MATCHING' | 'ORDERING' | 'LISTENING' | 'COLORING' | 'ESSAY' | 'LISTEN_AND_FILL_IN_THE_BLANK_WITH_IMAGE' | 'LISTEN_AND_TICK_ANSWER' | 'LISTEN_AND_FILL_NAME_NUMBER' | 'LISTENING_FILL_BLANK' | 'LISTENING_COLOR' | 'TICK_TRUE_OR_FALSE' | 'TICK_YES_OR_NO' | 'READING_TICK_CROSS' | 'ARRANGE_LETTERS_INTO_WORDS' | 'READ_PASSAGE_AND_COMPLETE_STORY' | 'CLOZE_TEST_WITH_TICK_BOX' | 'READ_AND_CHOOSE_APPROPRIATE_WORD' | 'WRITE_SHORT_PARAGRAPH' | 'LABEL_THE_PICTURE' | 'READING_LETTER_ARRANGE' | 'READING_PASSAGE_FILL' | 'FILL_BLANK' | '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' | 'SPONTANEOUS_QA_GROUP' | 'WORD_ORDER_AND_MATCH_GROUP' | 'WRITE_A_SHORT_LETTER' | 'WRITE_CORRECT_VERB_FORM' | 'CHOOSE_CORRECT_ADJECTIVE' | 'ANSWER_THE_QUESTION' | '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';
32
+ export type QuestionType = 'FILL_IN_BLANK' | 'TRUE_FALSE' | 'MATCHING' | 'ORDERING' | 'LISTENING' | 'COLORING' | 'ESSAY' | 'LISTEN_AND_FILL_IN_THE_BLANK_WITH_IMAGE' | 'LISTEN_AND_TICK_ANSWER' | 'LISTEN_AND_FILL_NAME_NUMBER' | 'LISTENING_FILL_BLANK' | 'LISTENING_COLOR' | 'TICK_TRUE_OR_FALSE' | 'TICK_YES_OR_NO' | 'READING_TICK_CROSS' | 'ARRANGE_LETTERS_INTO_WORDS' | 'READ_PASSAGE_AND_COMPLETE_STORY' | 'CLOZE_TEST_WITH_TICK_BOX' | 'READ_AND_CHOOSE_APPROPRIATE_WORD' | 'WRITE_SHORT_PARAGRAPH' | 'LABEL_THE_PICTURE' | 'READING_LETTER_ARRANGE' | 'READING_PASSAGE_FILL' | 'FILL_BLANK' | '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' | 'SPONTANEOUS_QA_GROUP' | 'WORD_ORDER_AND_MATCH_GROUP' | 'WRITE_A_SHORT_LETTER' | 'WRITE_CORRECT_VERB_FORM' | 'CHOOSE_CORRECT_ADJECTIVE' | 'ANSWER_THE_QUESTION' | 'ANSWER_THE_QUESTION_GROUP' | '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' | 'CROSSWORD_PUZZLE';
33
33
  export type Level = 'Pre-A1' | 'A1' | 'A2' | 'B1' | 'B2' | 'C1' | 'C2';
34
34
  export type Difficulty = 'EASY' | 'MEDIUM' | 'HARD';
35
35
  export type Skill = 'LISTENING' | 'READING' | 'WRITING' | 'SPEAKING';
@@ -0,0 +1,39 @@
1
+ export declare const ANSWER_THE_QUESTION_GROUP_GRADING_TYPE: "AI";
2
+ export interface AnswerTheQuestionGroupItemContent {
3
+ question: string;
4
+ }
5
+ export interface AnswerTheQuestionGroupItemExpectedAnswer {
6
+ expectedAnswers: string[];
7
+ }
8
+ export interface AnswerTheQuestionGroupItem {
9
+ questionType?: 'ANSWER_THE_QUESTION';
10
+ isExample?: boolean;
11
+ content: AnswerTheQuestionGroupItemContent;
12
+ correctAnswer?: AnswerTheQuestionGroupItemExpectedAnswer;
13
+ points?: number;
14
+ questionNumber?: number;
15
+ }
16
+ export interface AnswerTheQuestionGroupContent {
17
+ meta?: {
18
+ instruction?: string;
19
+ passage?: string;
20
+ gradingType: typeof ANSWER_THE_QUESTION_GROUP_GRADING_TYPE;
21
+ isAiGraded: true;
22
+ };
23
+ items: AnswerTheQuestionGroupItem[];
24
+ }
25
+ export interface AnswerTheQuestionGroupCorrectAnswer {
26
+ answer: AnswerTheQuestionGroupItemExpectedAnswer[];
27
+ }
28
+ export interface AnswerTheQuestionGroupAPIPayload {
29
+ id?: string;
30
+ questionType: 'ANSWER_THE_QUESTION_GROUP';
31
+ content: AnswerTheQuestionGroupContent;
32
+ correctAnswer: AnswerTheQuestionGroupCorrectAnswer;
33
+ points: number;
34
+ explanation?: string;
35
+ questionNumber: number;
36
+ partId?: string;
37
+ partNo?: number;
38
+ }
39
+ export type AnswerTheQuestionGroupLocalStorage = AnswerTheQuestionGroupAPIPayload;
@@ -0,0 +1 @@
1
+ export const ANSWER_THE_QUESTION_GROUP_GRADING_TYPE = 'AI';
@@ -0,0 +1,50 @@
1
+ /**
2
+ * CROSSWORD_PUZZLE Question Type Interfaces
3
+ *
4
+ * This question type displays an interactive crossword grid with Across & Down clues.
5
+ *
6
+ * API format:
7
+ * - content: { title?, gridSize: { rows, cols }, clues: { across, down } }
8
+ * - correctAnswer: { answers: Record<string, string>, caseSensitive?: boolean }
9
+ */
10
+ import { QuestionBankSettings } from './choose-the-correct-answer';
11
+ export interface CrosswordClue {
12
+ number: number;
13
+ clue: string;
14
+ startRow: number;
15
+ startCol: number;
16
+ length: number;
17
+ isExample?: boolean;
18
+ }
19
+ export type CrosswordSubtype = 'STANDARD' | 'HIDDEN_WORD';
20
+ export interface CrosswordPuzzleContent {
21
+ type?: CrosswordSubtype;
22
+ title?: string;
23
+ gridSize: {
24
+ rows: number;
25
+ cols: number;
26
+ };
27
+ markedColumn?: number;
28
+ clues: {
29
+ across: CrosswordClue[];
30
+ down: CrosswordClue[];
31
+ };
32
+ }
33
+ export interface CrosswordPuzzleCorrectAnswer {
34
+ answers: Record<string, string>;
35
+ caseSensitive?: boolean;
36
+ }
37
+ export interface CrosswordPuzzleAPIPayload {
38
+ id?: string;
39
+ questionType: 'CROSSWORD_PUZZLE';
40
+ content: CrosswordPuzzleContent;
41
+ correctAnswer: CrosswordPuzzleCorrectAnswer;
42
+ points: number;
43
+ explanation?: string;
44
+ questionNumber: number;
45
+ partId?: string;
46
+ partNo?: number;
47
+ addToQuestionBank?: boolean;
48
+ questionBank?: QuestionBankSettings;
49
+ }
50
+ export type CrosswordPuzzleLocalStorage = Omit<CrosswordPuzzleAPIPayload, 'addToQuestionBank' | 'questionBank'>;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * CROSSWORD_PUZZLE Question Type Interfaces
3
+ *
4
+ * This question type displays an interactive crossword grid with Across & Down clues.
5
+ *
6
+ * API format:
7
+ * - content: { title?, gridSize: { rows, cols }, clues: { across, down } }
8
+ * - correctAnswer: { answers: Record<string, string>, caseSensitive?: boolean }
9
+ */
10
+ export {};
@@ -16,6 +16,7 @@
16
16
  * - LocalStorage: Same format but WITHOUT addToQuestionBank and questionBank
17
17
  */
18
18
  export * from './choose-the-correct-answer';
19
+ export * from './answer-the-question-group';
19
20
  export * from './choose-the-correct-answer-group';
20
21
  export * from './cross-out-word-group';
21
22
  export * from './write-correct-verb-form';
@@ -29,3 +30,4 @@ export * from './read-displayed-content';
29
30
  export * from './speaking-describe-image';
30
31
  export * from './spontaneous-qa';
31
32
  export * from './word-order-and-match-group';
33
+ export * from './crossword-puzzle';
@@ -17,6 +17,8 @@
17
17
  */
18
18
  // CHOOSE_THE_CORRECT_ANSWER
19
19
  export * from './choose-the-correct-answer';
20
+ // ANSWER_THE_QUESTION_GROUP
21
+ export * from './answer-the-question-group';
20
22
  // CHOOSE_THE_CORRECT_ANSWER_GROUP
21
23
  export * from './choose-the-correct-answer-group';
22
24
  // CROSS_OUT_WORD_GROUP
@@ -44,3 +46,5 @@ export * from './speaking-describe-image';
44
46
  export * from './spontaneous-qa';
45
47
  // WORD_ORDER_AND_MATCH_GROUP
46
48
  export * from './word-order-and-match-group';
49
+ // CROSSWORD_PUZZLE
50
+ export * from './crossword-puzzle';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinyweb_dev/oe-exam-sdk",
3
- "version": "0.1.30",
3
+ "version": "0.1.32",
4
4
  "description": "Reusable OceanEdu question components.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",