@tinyweb_dev/oe-exam-sdk 0.2.4 → 0.2.6
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.
- package/dist/components/exams/take/ExamTakingPageContainer.js +6 -0
- package/dist/components/exams/take/components/QuestionRenderer.js +19 -3
- package/dist/components/exams/take/components/question-renderers/ChooseBestAnswerImages.d.ts +10 -0
- package/dist/components/exams/take/components/question-renderers/ChooseBestAnswerImages.js +38 -0
- package/dist/components/exams/take/components/question-renderers/MoversChooseBestAnswerRenderer.js +5 -11
- package/dist/components/exams/take/components/question-renderers/MoversFillInBlankGroupRenderer.d.ts +22 -0
- package/dist/components/exams/take/components/question-renderers/MoversFillInBlankGroupRenderer.js +60 -0
- package/dist/components/exams/take/components/question-renderers/MoversMatchWordToPictureRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/question-renderers/MoversMatchWordToPictureRenderer.js +75 -0
- package/dist/components/exams/take/components/question-renderers/MoversMatchingWithLinesGroupRenderer.d.ts +13 -0
- package/dist/components/exams/take/components/question-renderers/MoversMatchingWithLinesGroupRenderer.js +31 -0
- package/dist/components/exams/take/components/question-renderers/MoversTrueFalseCorrectGroupRenderer.d.ts +18 -0
- package/dist/components/exams/take/components/question-renderers/MoversTrueFalseCorrectGroupRenderer.js +92 -0
- package/dist/components/exams/take/components/question-renderers/MoversWritingRenderer.d.ts +2 -1
- package/dist/components/exams/take/components/question-renderers/MoversWritingRenderer.js +2 -2
- package/dist/components/exams/take/components/question-renderers/index.d.ts +4 -0
- package/dist/components/exams/take/components/question-renderers/index.js +4 -0
- package/dist/components/exams/take/exam-taking.utils.d.ts +1 -0
- package/dist/components/exams/take/exam-taking.utils.js +9 -1
- package/dist/components/exams/take/types.d.ts +3 -2
- package/dist/components/exams/take/utils/answer-transformers.js +28 -0
- package/dist/components/exams/take/utils/question-transformers.d.ts +73 -1
- package/dist/components/exams/take/utils/question-transformers.js +188 -0
- package/dist/components/questions/_shared/config/question-types.config.js +24 -0
- package/dist/components/questions/_shared/types/choose-the-correct-answer-group.type.d.ts +9 -0
- package/dist/components/questions/_shared/types/choose-the-correct-answer-group.type.js +49 -1
- package/dist/components/questions/_shared/types/fill-in-blank-group.type.d.ts +50 -0
- package/dist/components/questions/_shared/types/fill-in-blank-group.type.js +2 -0
- package/dist/components/questions/_shared/types/index.d.ts +4 -0
- package/dist/components/questions/_shared/types/index.js +4 -0
- package/dist/components/questions/_shared/types/match-word-to-picture.type.d.ts +62 -0
- package/dist/components/questions/_shared/types/match-word-to-picture.type.js +1 -0
- package/dist/components/questions/_shared/types/matching-with-lines-group.type.d.ts +40 -0
- package/dist/components/questions/_shared/types/matching-with-lines-group.type.js +1 -0
- package/dist/components/questions/_shared/types/true-false-correct-group.type.d.ts +42 -0
- package/dist/components/questions/_shared/types/true-false-correct-group.type.js +2 -0
- package/dist/components/questions/_shared/types/write-a-short-letter.type.d.ts +4 -0
- package/dist/components/questions/components/QuestionSearchDropdown.js +6 -0
- package/dist/components/questions/components/QuestionTypeSelector.js +3 -0
- package/dist/components/questions/creator/question-type-registry.js +8 -0
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseAnswerGroupImageUpload.d.ts +13 -0
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseAnswerGroupImageUpload.js +32 -0
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupClient.d.ts +1 -1
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupClient.js +42 -6
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupCreator.js +40 -20
- package/dist/components/questions/types/choose-the-correct-answer-group/map-choose-the-correct-answer-group-data.d.ts +1 -1
- package/dist/components/questions/types/choose-the-correct-answer-group/map-choose-the-correct-answer-group-data.js +5 -0
- package/dist/components/questions/types/choose-the-correct-answer-group/transform.js +4 -0
- package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupClient.d.ts +2 -0
- package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupClient.js +64 -0
- package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupCreator.d.ts +2 -0
- package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupCreator.js +158 -0
- package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupMediaField.d.ts +7 -0
- package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupMediaField.js +30 -0
- package/dist/components/questions/types/fill-in-blank-group/blank-utils.d.ts +20 -0
- package/dist/components/questions/types/fill-in-blank-group/blank-utils.js +99 -0
- package/dist/components/questions/types/fill-in-blank-group/index.d.ts +5 -0
- package/dist/components/questions/types/fill-in-blank-group/index.js +5 -0
- package/dist/components/questions/types/fill-in-blank-group/map-fill-in-blank-group-data.d.ts +4 -0
- package/dist/components/questions/types/fill-in-blank-group/map-fill-in-blank-group-data.js +102 -0
- package/dist/components/questions/types/fill-in-blank-group/register.d.ts +3 -0
- package/dist/components/questions/types/fill-in-blank-group/register.js +37 -0
- package/dist/components/questions/types/fill-in-blank-group/transform.d.ts +2 -0
- package/dist/components/questions/types/fill-in-blank-group/transform.js +68 -0
- package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureClient.d.ts +2 -0
- package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureClient.js +31 -0
- package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureCreator.d.ts +2 -0
- package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureCreator.js +267 -0
- package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureGroupClient.d.ts +2 -0
- package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureGroupClient.js +65 -0
- package/dist/components/questions/types/match-word-to-picture/WordBankEditor.d.ts +8 -0
- package/dist/components/questions/types/match-word-to-picture/WordBankEditor.js +15 -0
- package/dist/components/questions/types/match-word-to-picture/index.d.ts +6 -0
- package/dist/components/questions/types/match-word-to-picture/index.js +6 -0
- package/dist/components/questions/types/match-word-to-picture/map-match-word-to-picture-data.d.ts +2 -0
- package/dist/components/questions/types/match-word-to-picture/map-match-word-to-picture-data.js +53 -0
- package/dist/components/questions/types/match-word-to-picture/map-match-word-to-picture-group-data.d.ts +4 -0
- package/dist/components/questions/types/match-word-to-picture/map-match-word-to-picture-group-data.js +75 -0
- package/dist/components/questions/types/match-word-to-picture/register.d.ts +2 -0
- package/dist/components/questions/types/match-word-to-picture/register.js +55 -0
- package/dist/components/questions/types/match-word-to-picture/transform.d.ts +11 -0
- package/dist/components/questions/types/match-word-to-picture/transform.js +43 -0
- package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesBoard.d.ts +20 -0
- package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesBoard.js +109 -0
- package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesGroupClient.d.ts +2 -0
- package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesGroupClient.js +30 -0
- package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesGroupCreator.d.ts +2 -0
- package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesGroupCreator.js +180 -0
- package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesImageField.d.ts +6 -0
- package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesImageField.js +26 -0
- package/dist/components/questions/types/matching-with-lines-group/index.d.ts +4 -0
- package/dist/components/questions/types/matching-with-lines-group/index.js +4 -0
- package/dist/components/questions/types/matching-with-lines-group/map-matching-with-lines-group-data.d.ts +8 -0
- package/dist/components/questions/types/matching-with-lines-group/map-matching-with-lines-group-data.js +104 -0
- package/dist/components/questions/types/matching-with-lines-group/register.d.ts +3 -0
- package/dist/components/questions/types/matching-with-lines-group/register.js +37 -0
- package/dist/components/questions/types/matching-with-lines-group/transform.d.ts +2 -0
- package/dist/components/questions/types/matching-with-lines-group/transform.js +44 -0
- package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupClient.d.ts +2 -0
- package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupClient.js +25 -0
- package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupCreator.d.ts +2 -0
- package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupCreator.js +144 -0
- package/dist/components/questions/types/true-false-correct-group/index.d.ts +5 -0
- package/dist/components/questions/types/true-false-correct-group/index.js +5 -0
- package/dist/components/questions/types/true-false-correct-group/map-true-false-correct-group-data.d.ts +4 -0
- package/dist/components/questions/types/true-false-correct-group/map-true-false-correct-group-data.js +79 -0
- package/dist/components/questions/types/true-false-correct-group/register.d.ts +2 -0
- package/dist/components/questions/types/true-false-correct-group/register.js +36 -0
- package/dist/components/questions/types/true-false-correct-group/transform.d.ts +2 -0
- package/dist/components/questions/types/true-false-correct-group/transform.js +49 -0
- package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +11 -1
- package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +8 -2
- package/dist/components/questions/types/write-a-short-letter/register.js +4 -0
- package/dist/components/questions/types/write-a-short-letter/transform.js +4 -0
- package/dist/components/questions/viewer/ChooseTheCorrectAnswerGroupViewer.d.ts +2 -1
- package/dist/components/questions/viewer/ChooseTheCorrectAnswerGroupViewer.js +2 -2
- package/dist/components/questions/viewer/FillInBlankGroupViewer.d.ts +10 -0
- package/dist/components/questions/viewer/FillInBlankGroupViewer.js +14 -0
- package/dist/components/questions/viewer/MatchWordToPictureGroupViewer.d.ts +9 -0
- package/dist/components/questions/viewer/MatchWordToPictureGroupViewer.js +11 -0
- package/dist/components/questions/viewer/MatchWordToPictureViewer.d.ts +9 -0
- package/dist/components/questions/viewer/MatchWordToPictureViewer.js +8 -0
- package/dist/components/questions/viewer/MatchingWithLinesGroupViewer.d.ts +7 -0
- package/dist/components/questions/viewer/MatchingWithLinesGroupViewer.js +48 -0
- package/dist/components/questions/viewer/QuestionViewer.js +24 -3
- package/dist/components/questions/viewer/TrueFalseCorrectGroupViewer.d.ts +9 -0
- package/dist/components/questions/viewer/TrueFalseCorrectGroupViewer.js +14 -0
- package/dist/components/questions/viewer/index.d.ts +5 -0
- package/dist/components/questions/viewer/index.js +5 -0
- package/dist/components/results/renderers/ReviewChooseBestAnswerRenderer.js +4 -9
- package/dist/components/results/renderers/review-question-body-movers.js +74 -3
- package/dist/components/results/review-data.js +59 -0
- package/dist/components/themes/english-certification/EcWritingTask.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/shared/constants/question-skills.js +8 -0
- package/dist/shared/lib/hooks/usePresignedFileUrl.d.ts +3 -1
- package/dist/shared/lib/hooks/usePresignedFileUrl.js +30 -12
- package/dist/shared/lib/utils/question-reverse-transform.js +142 -0
- package/dist/shared/lib/utils/question-transform.js +8 -0
- package/dist/shared/types/common.types.d.ts +1 -1
- package/dist/shared/types/questions/choose-the-correct-answer-group.d.ts +1 -0
- package/dist/shared/types/questions/fill-in-blank-group.d.ts +45 -0
- package/dist/shared/types/questions/fill-in-blank-group.js +1 -0
- package/dist/shared/types/questions/index.d.ts +4 -0
- package/dist/shared/types/questions/index.js +8 -0
- package/dist/shared/types/questions/match-word-to-picture.d.ts +35 -0
- package/dist/shared/types/questions/match-word-to-picture.js +5 -0
- package/dist/shared/types/questions/matching-with-lines-group.d.ts +39 -0
- package/dist/shared/types/questions/matching-with-lines-group.js +1 -0
- package/dist/shared/types/questions/true-false-correct-group.d.ts +39 -0
- package/dist/shared/types/questions/true-false-correct-group.js +1 -0
- package/package.json +7 -2
|
@@ -10,14 +10,18 @@ export { MoversLabelThePictureRenderer } from './MoversLabelThePictureRenderer';
|
|
|
10
10
|
export { MoversFillWordHintRenderer } from './MoversFillWordHintRenderer';
|
|
11
11
|
export { MoversGridFillRenderer } from './MoversGridFillRenderer';
|
|
12
12
|
export { MoversTrueFalseRenderer } from './MoversTrueFalseRenderer';
|
|
13
|
+
export { MoversTrueFalseCorrectGroupRenderer } from './MoversTrueFalseCorrectGroupRenderer';
|
|
14
|
+
export { MoversFillInBlankGroupRenderer } from './MoversFillInBlankGroupRenderer';
|
|
13
15
|
export { MoversCrossOutWordGroupRenderer } from './MoversCrossOutWordGroupRenderer';
|
|
14
16
|
export { MoversAnswerTheQuestionRenderer } from './MoversAnswerTheQuestionRenderer';
|
|
15
17
|
export { MoversWriteSentencesRenderer } from './MoversWriteSentencesRenderer';
|
|
16
18
|
export { MoversWordOrderingRenderer } from './MoversWordOrderingRenderer';
|
|
17
19
|
export { MoversWordFillParagraphRenderer } from './MoversWordFillParagraphRenderer';
|
|
18
20
|
export { MoversMatchByWritingAnswerRenderer } from './MoversMatchByWritingAnswerRenderer';
|
|
21
|
+
export { MoversMatchWordToPictureRenderer } from './MoversMatchWordToPictureRenderer';
|
|
19
22
|
export { MoversWordFillStructuredFormRenderer } from './MoversWordFillStructuredFormRenderer';
|
|
20
23
|
export { MoversWordOrderAndMatchGroupRenderer } from './MoversWordOrderAndMatchGroupRenderer';
|
|
24
|
+
export { MoversMatchingWithLinesGroupRenderer } from './MoversMatchingWithLinesGroupRenderer';
|
|
21
25
|
export { MoversCrosswordPuzzleRenderer } from './MoversCrosswordPuzzleRenderer';
|
|
22
26
|
export { FindWordsInMatrixRenderer } from './FindWordsInMatrixRenderer';
|
|
23
27
|
export { ArticlesViewer } from './ArticlesViewer';
|
|
@@ -14,14 +14,18 @@ export { MoversFillWordHintRenderer } from './MoversFillWordHintRenderer';
|
|
|
14
14
|
export { MoversGridFillRenderer } from './MoversGridFillRenderer';
|
|
15
15
|
// Starters & Movers renderers
|
|
16
16
|
export { MoversTrueFalseRenderer } from './MoversTrueFalseRenderer';
|
|
17
|
+
export { MoversTrueFalseCorrectGroupRenderer } from './MoversTrueFalseCorrectGroupRenderer';
|
|
18
|
+
export { MoversFillInBlankGroupRenderer } from './MoversFillInBlankGroupRenderer';
|
|
17
19
|
export { MoversCrossOutWordGroupRenderer } from './MoversCrossOutWordGroupRenderer';
|
|
18
20
|
export { MoversAnswerTheQuestionRenderer } from './MoversAnswerTheQuestionRenderer';
|
|
19
21
|
export { MoversWriteSentencesRenderer } from './MoversWriteSentencesRenderer';
|
|
20
22
|
export { MoversWordOrderingRenderer } from './MoversWordOrderingRenderer';
|
|
21
23
|
export { MoversWordFillParagraphRenderer } from './MoversWordFillParagraphRenderer';
|
|
22
24
|
export { MoversMatchByWritingAnswerRenderer } from './MoversMatchByWritingAnswerRenderer';
|
|
25
|
+
export { MoversMatchWordToPictureRenderer } from './MoversMatchWordToPictureRenderer';
|
|
23
26
|
export { MoversWordFillStructuredFormRenderer } from './MoversWordFillStructuredFormRenderer';
|
|
24
27
|
export { MoversWordOrderAndMatchGroupRenderer } from './MoversWordOrderAndMatchGroupRenderer';
|
|
28
|
+
export { MoversMatchingWithLinesGroupRenderer } from './MoversMatchingWithLinesGroupRenderer';
|
|
25
29
|
export { MoversCrosswordPuzzleRenderer } from './MoversCrosswordPuzzleRenderer';
|
|
26
30
|
export { FindWordsInMatrixRenderer } from './FindWordsInMatrixRenderer';
|
|
27
31
|
export { ArticlesViewer } from './ArticlesViewer';
|
|
@@ -113,6 +113,7 @@ export declare function transformWriteShortLetter(question: ExamTakingQuestion |
|
|
|
113
113
|
minWords: number | undefined;
|
|
114
114
|
maxWords: number | undefined;
|
|
115
115
|
guideImages: string[];
|
|
116
|
+
passage: string | undefined;
|
|
116
117
|
};
|
|
117
118
|
export declare function transformWordFillStructuredForm(questions: ExamTakingQuestion[]): {
|
|
118
119
|
instruction: string;
|
|
@@ -61,7 +61,7 @@ export function transformWordFillParagraph(questions) {
|
|
|
61
61
|
*/
|
|
62
62
|
export function transformWriteShortLetter(question) {
|
|
63
63
|
if (!question) {
|
|
64
|
-
return { prompt: '', requirements: [], minWords: undefined, maxWords: undefined, guideImages: [] };
|
|
64
|
+
return { prompt: '', requirements: [], minWords: undefined, maxWords: undefined, guideImages: [], passage: undefined };
|
|
65
65
|
}
|
|
66
66
|
const content = asRecord(question.content);
|
|
67
67
|
const instructions = asRecord(content.instructions);
|
|
@@ -72,6 +72,12 @@ export function transformWriteShortLetter(question) {
|
|
|
72
72
|
const guideImages = readStringArray(question.content, 'guideImages');
|
|
73
73
|
const minWords = readNumber(question.content, 'minWords');
|
|
74
74
|
const maxWords = readNumber(question.content, 'maxWords');
|
|
75
|
+
const passageRaw = content.passage ?? content.passages;
|
|
76
|
+
const passage = typeof passageRaw === 'string' && passageRaw.trim()
|
|
77
|
+
? passageRaw
|
|
78
|
+
: Array.isArray(passageRaw)
|
|
79
|
+
? passageRaw.filter((item) => typeof item === 'string' && item.trim().length > 0).join('\n\n') || undefined
|
|
80
|
+
: undefined;
|
|
75
81
|
// New structure: use instructions.mainInstruction as prompt, informations as requirements
|
|
76
82
|
if (mainInstruction || informations.length) {
|
|
77
83
|
return {
|
|
@@ -80,6 +86,7 @@ export function transformWriteShortLetter(question) {
|
|
|
80
86
|
minWords,
|
|
81
87
|
maxWords,
|
|
82
88
|
guideImages,
|
|
89
|
+
passage,
|
|
83
90
|
};
|
|
84
91
|
}
|
|
85
92
|
// Legacy structure: build prompt from contexts array
|
|
@@ -99,6 +106,7 @@ export function transformWriteShortLetter(question) {
|
|
|
99
106
|
minWords,
|
|
100
107
|
maxWords,
|
|
101
108
|
guideImages,
|
|
109
|
+
passage,
|
|
102
110
|
};
|
|
103
111
|
}
|
|
104
112
|
export function transformWordFillStructuredForm(questions) {
|
|
@@ -115,6 +115,7 @@ export interface ChooseBestAnswerOption {
|
|
|
115
115
|
id: string;
|
|
116
116
|
label: string;
|
|
117
117
|
text: string;
|
|
118
|
+
imageUrl?: string;
|
|
118
119
|
}
|
|
119
120
|
export interface ChooseBestAnswerQuestion {
|
|
120
121
|
id: string;
|
|
@@ -123,7 +124,7 @@ export interface ChooseBestAnswerQuestion {
|
|
|
123
124
|
options: ChooseBestAnswerOption[];
|
|
124
125
|
correctOptionId?: string;
|
|
125
126
|
correctOptionIds?: string[];
|
|
126
|
-
imageUrl?: string;
|
|
127
|
+
imageUrl?: string | string[];
|
|
127
128
|
audioUrl?: string;
|
|
128
129
|
optionType?: 'text' | 'image';
|
|
129
130
|
multipleAnswers?: boolean;
|
|
@@ -135,7 +136,7 @@ export interface ChooseBestAnswerExample {
|
|
|
135
136
|
options: ChooseBestAnswerOption[];
|
|
136
137
|
correctOptionId: string;
|
|
137
138
|
optionType?: 'text' | 'image';
|
|
138
|
-
imageUrl?: string;
|
|
139
|
+
imageUrl?: string | string[];
|
|
139
140
|
audioUrl?: string;
|
|
140
141
|
}
|
|
141
142
|
export interface MoversChooseBestAnswerRendererProps {
|
|
@@ -87,6 +87,9 @@ function findParentQuestion(subQuestionId, parts) {
|
|
|
87
87
|
if (part.questionType === 'CHOOSE_THE_CORRECT_ANSWER_GROUP' ||
|
|
88
88
|
part.questionType === 'CROSS_OUT_WORD_GROUP' ||
|
|
89
89
|
part.questionType === 'TRUE_FALSE_GROUP' ||
|
|
90
|
+
part.questionType === 'TRUE_FALSE_CORRECT_GROUP' ||
|
|
91
|
+
part.questionType === 'FILL_IN_BLANK_GROUP' ||
|
|
92
|
+
part.questionType === 'MATCHING_WITH_LINES_GROUP' ||
|
|
90
93
|
part.questionType === 'WORD_ORDER_AND_MATCH_GROUP' ||
|
|
91
94
|
part.questionType === 'SPONTANEOUS_QA_GROUP' ||
|
|
92
95
|
part.questionType === 'ANSWER_THE_QUESTION_GROUP') {
|
|
@@ -369,6 +372,31 @@ export function transformAnswersForSubmission(answers, parts) {
|
|
|
369
372
|
if (parentType === 'CROSS_OUT_WORD_GROUP') {
|
|
370
373
|
return normalizeCrossOutWordGroupAnswer(raw);
|
|
371
374
|
}
|
|
375
|
+
if (parentType === 'TRUE_FALSE_CORRECT_GROUP') {
|
|
376
|
+
if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
|
|
377
|
+
const obj = raw;
|
|
378
|
+
const isTrue = obj.isTrue === true ? true : obj.isTrue === false ? false : null;
|
|
379
|
+
return {
|
|
380
|
+
isTrue,
|
|
381
|
+
correction: typeof obj.correction === 'string' ? obj.correction : '',
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
return { isTrue: null, correction: '' };
|
|
385
|
+
}
|
|
386
|
+
if (parentType === 'FILL_IN_BLANK_GROUP') {
|
|
387
|
+
if (raw && typeof raw === 'object' && !Array.isArray(raw) && Array.isArray(raw.answers)) {
|
|
388
|
+
return {
|
|
389
|
+
answers: raw.answers.map((value) => String(value ?? '')),
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
if (Array.isArray(raw)) {
|
|
393
|
+
return { answers: raw.map((value) => String(value ?? '')) };
|
|
394
|
+
}
|
|
395
|
+
if (typeof raw === 'string') {
|
|
396
|
+
return { answers: [raw] };
|
|
397
|
+
}
|
|
398
|
+
return { answers: [] };
|
|
399
|
+
}
|
|
372
400
|
if (parentType === 'WORD_ORDER_AND_MATCH_GROUP') {
|
|
373
401
|
if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
|
|
374
402
|
const obj = raw;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Each transformer handles specific question type data structure.
|
|
6
6
|
*/
|
|
7
7
|
import type { FillBlankQuestion, ChooseBestAnswerQuestion, PictureChooseSubQuestion, PictureFillBlankSubQuestion, ReadingPassageQuestion, LabelThePictureLabel, FillWordHintSubQuestion, ColoringHintItem, ColoringRegion } from '../types';
|
|
8
|
-
export type QuestionType = 'FILL_IN_BLANK' | 'WRITE_CORRECT_VERB_FORM' | 'CHOOSE_THE_CORRECT_ANSWER' | 'CHOOSE_THE_CORRECT_ANSWER_GROUP' | 'CHOOSE_CORRECT_ADJECTIVE' | 'WRITE_A_SHORT_LETTER' | 'READ_AND_COLOR_OBJECTS' | 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER' | 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER' | 'READ_PASSAGE_AND_ANSWER_QUESTIONS' | 'LABEL_THE_PICTURE' | 'LOOK_PICTURE_FILL_WORD_HINT' | 'FILL_MISSING_WORDS_IN_GRID' | 'IMAGE_OBJECT_MATCHING' | 'ANSWER_THE_QUESTION' | 'ANSWER_THE_QUESTION_GROUP' | 'TRUE_FALSE' | 'TRUE_FALSE_GROUP' | 'CROSS_OUT_WORD_GROUP' | 'WORD_ORDERING' | 'WORD_FILL_PARAGRAPH' | 'MATCH_BY_WRITING_ANSWER' | 'WRITE_SENTENCES' | 'WORD_FILL_STRUCTURED_FORM' | 'CROSSWORD_PUZZLE' | 'FIND_WORDS_IN_MATRIX' | 'WORD_ORDER_AND_MATCH_GROUP' | 'LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE' | 'LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP' | 'LISTEN_AND_DRAG_OBJECTS_INTO_SCENE' | 'LISTEN_AND_SPEAK_ANSWER' | 'LISTEN_AND_SPEAK_COMPARE_IMAGES' | 'LISTEN_AND_SPEAK_WITH_STORY_IMAGES' | 'LISTEN_AND_SPEAK_IMAGE_GROUP' | 'LISTEN_AND_SPEAK_ODD_ONE_OUT' | 'LISTEN_AND_SPEAK_QUESTION_LIST' | 'LISTEN_AND_SPEAK_INFO_EXCHANGE' | 'READ_DISPLAYED_CONTENT' | 'SPEAKING_DESCRIBE_IMAGE' | 'SPONTANEOUS_QA' | 'SPONTANEOUS_QA_GROUP' | 'SPEAKING_CONVERSATION' | 'GN_SPEAKING_INTERVIEW' | 'SPEAKING_CUE_CARD';
|
|
8
|
+
export type QuestionType = 'FILL_IN_BLANK' | 'WRITE_CORRECT_VERB_FORM' | 'CHOOSE_THE_CORRECT_ANSWER' | 'CHOOSE_THE_CORRECT_ANSWER_GROUP' | 'CHOOSE_CORRECT_ADJECTIVE' | 'WRITE_A_SHORT_LETTER' | 'READ_AND_COLOR_OBJECTS' | 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER' | 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER' | 'READ_PASSAGE_AND_ANSWER_QUESTIONS' | 'LABEL_THE_PICTURE' | 'LOOK_PICTURE_FILL_WORD_HINT' | 'FILL_MISSING_WORDS_IN_GRID' | 'IMAGE_OBJECT_MATCHING' | 'ANSWER_THE_QUESTION' | 'ANSWER_THE_QUESTION_GROUP' | 'TRUE_FALSE' | 'TRUE_FALSE_GROUP' | 'TRUE_FALSE_CORRECT_GROUP' | 'FILL_IN_BLANK_GROUP' | 'MATCHING_WITH_LINES_GROUP' | 'CROSS_OUT_WORD_GROUP' | 'WORD_ORDERING' | 'WORD_FILL_PARAGRAPH' | 'MATCH_BY_WRITING_ANSWER' | 'MATCH_WORD_TO_PICTURE' | 'WRITE_SENTENCES' | 'WORD_FILL_STRUCTURED_FORM' | 'CROSSWORD_PUZZLE' | 'FIND_WORDS_IN_MATRIX' | 'WORD_ORDER_AND_MATCH_GROUP' | 'LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE' | 'LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP' | 'LISTEN_AND_DRAG_OBJECTS_INTO_SCENE' | 'LISTEN_AND_SPEAK_ANSWER' | 'LISTEN_AND_SPEAK_COMPARE_IMAGES' | 'LISTEN_AND_SPEAK_WITH_STORY_IMAGES' | 'LISTEN_AND_SPEAK_IMAGE_GROUP' | 'LISTEN_AND_SPEAK_ODD_ONE_OUT' | 'LISTEN_AND_SPEAK_QUESTION_LIST' | 'LISTEN_AND_SPEAK_INFO_EXCHANGE' | 'READ_DISPLAYED_CONTENT' | 'SPEAKING_DESCRIBE_IMAGE' | 'SPONTANEOUS_QA' | 'SPONTANEOUS_QA_GROUP' | 'SPEAKING_CONVERSATION' | 'GN_SPEAKING_INTERVIEW' | 'SPEAKING_CUE_CARD';
|
|
9
9
|
export interface ApiQuestion {
|
|
10
10
|
id: string;
|
|
11
11
|
content: any;
|
|
@@ -184,6 +184,7 @@ export declare function transformWriteShortLetter(question: ApiQuestion): {
|
|
|
184
184
|
minWords?: number;
|
|
185
185
|
maxWords?: number;
|
|
186
186
|
guideImages?: string[];
|
|
187
|
+
passage?: string;
|
|
187
188
|
};
|
|
188
189
|
export declare function transformColorObjects(questions: ApiQuestion[]): {
|
|
189
190
|
instruction: string;
|
|
@@ -269,6 +270,46 @@ export declare function transformTrueFalseGroup(questions: ApiQuestion[]): {
|
|
|
269
270
|
imageUrl?: string;
|
|
270
271
|
groupContent?: string;
|
|
271
272
|
};
|
|
273
|
+
export interface TrueFalseCorrectItemAnswer {
|
|
274
|
+
isTrue: boolean | null;
|
|
275
|
+
correction: string;
|
|
276
|
+
}
|
|
277
|
+
export interface TrueFalseCorrectGroupQuestion {
|
|
278
|
+
id: string;
|
|
279
|
+
questionNumber: number;
|
|
280
|
+
question: string;
|
|
281
|
+
isExample: boolean;
|
|
282
|
+
exampleCorrectAnswer?: TrueFalseCorrectItemAnswer;
|
|
283
|
+
}
|
|
284
|
+
export declare function transformTrueFalseCorrectGroup(questions: ApiQuestion[]): {
|
|
285
|
+
questions: TrueFalseCorrectGroupQuestion[];
|
|
286
|
+
instruction: string;
|
|
287
|
+
};
|
|
288
|
+
export interface FillInBlankGroupItemAnswer {
|
|
289
|
+
answers: string[][];
|
|
290
|
+
caseSensitive?: boolean;
|
|
291
|
+
}
|
|
292
|
+
export interface FillInBlankGroupStudentItemAnswer {
|
|
293
|
+
answers: string[];
|
|
294
|
+
}
|
|
295
|
+
export interface FillInBlankGroupQuestion {
|
|
296
|
+
id: string;
|
|
297
|
+
questionNumber: number;
|
|
298
|
+
question: string;
|
|
299
|
+
imageUrl?: string;
|
|
300
|
+
audioUrl?: string;
|
|
301
|
+
isExample: boolean;
|
|
302
|
+
blankCount: number;
|
|
303
|
+
exampleAnswers?: string[];
|
|
304
|
+
}
|
|
305
|
+
export declare function transformFillInBlankGroup(questions: ApiQuestion[]): {
|
|
306
|
+
questions: FillInBlankGroupQuestion[];
|
|
307
|
+
instruction: string;
|
|
308
|
+
audioUrl?: string;
|
|
309
|
+
imageUrl?: string;
|
|
310
|
+
showHints?: boolean;
|
|
311
|
+
hints?: string[];
|
|
312
|
+
};
|
|
272
313
|
export interface WordOrderingQuestion {
|
|
273
314
|
id: string;
|
|
274
315
|
questionNumber: number;
|
|
@@ -321,6 +362,18 @@ export declare function transformMatchByWritingAnswer(questions: ApiQuestion[]):
|
|
|
321
362
|
askerName?: string;
|
|
322
363
|
answererName?: string;
|
|
323
364
|
};
|
|
365
|
+
export interface MatchWordToPictureQuestion {
|
|
366
|
+
id: string;
|
|
367
|
+
questionNumber: number;
|
|
368
|
+
imageUrl?: string;
|
|
369
|
+
isExample: boolean;
|
|
370
|
+
exampleAnswer?: string;
|
|
371
|
+
}
|
|
372
|
+
export declare function transformMatchWordToPicture(questions: ApiQuestion[]): {
|
|
373
|
+
questions: MatchWordToPictureQuestion[];
|
|
374
|
+
wordBank: string[];
|
|
375
|
+
instruction: string;
|
|
376
|
+
};
|
|
324
377
|
export declare function transformWriteSentences(questions: ApiQuestion[]): {
|
|
325
378
|
questions: Array<{
|
|
326
379
|
id: string;
|
|
@@ -477,3 +530,22 @@ export interface FindWordsInMatrixPartData {
|
|
|
477
530
|
explanation?: string;
|
|
478
531
|
}
|
|
479
532
|
export declare function transformFindWordsInMatrix(questions: ApiQuestion[]): FindWordsInMatrixPartData;
|
|
533
|
+
export interface MatchingWithLinesGroupQuestionItem {
|
|
534
|
+
id: string;
|
|
535
|
+
questionNumber: number;
|
|
536
|
+
imageUrl: string;
|
|
537
|
+
correctRightId: string;
|
|
538
|
+
isExample: boolean;
|
|
539
|
+
points: number;
|
|
540
|
+
}
|
|
541
|
+
export interface MatchingWithLinesGroupPartData {
|
|
542
|
+
questions: MatchingWithLinesGroupQuestionItem[];
|
|
543
|
+
rightItems: Array<{
|
|
544
|
+
id: string;
|
|
545
|
+
text: string;
|
|
546
|
+
}>;
|
|
547
|
+
title?: string;
|
|
548
|
+
instruction: string;
|
|
549
|
+
explanation?: string;
|
|
550
|
+
}
|
|
551
|
+
export declare function transformMatchingWithLinesGroup(questions: ApiQuestion[]): MatchingWithLinesGroupPartData;
|
|
@@ -428,23 +428,43 @@ export function transformChooseTheCorrectAnswerGroup(questions) {
|
|
|
428
428
|
...(isObj && opt.imageUrl ? { imageUrl: opt.imageUrl } : {}),
|
|
429
429
|
};
|
|
430
430
|
});
|
|
431
|
+
const toQuestionImageUrl = (value) => {
|
|
432
|
+
if (typeof value === 'string') {
|
|
433
|
+
const trimmed = value.trim();
|
|
434
|
+
return trimmed !== '' ? trimmed : undefined;
|
|
435
|
+
}
|
|
436
|
+
if (!Array.isArray(value)) {
|
|
437
|
+
return undefined;
|
|
438
|
+
}
|
|
439
|
+
const urls = value
|
|
440
|
+
.filter((url) => typeof url === 'string')
|
|
441
|
+
.map((url) => url.trim())
|
|
442
|
+
.filter((url) => url !== '');
|
|
443
|
+
if (urls.length === 0) {
|
|
444
|
+
return undefined;
|
|
445
|
+
}
|
|
446
|
+
return urls.length === 1 ? urls[0] : urls;
|
|
447
|
+
};
|
|
431
448
|
let example;
|
|
432
449
|
if (exampleItem) {
|
|
433
450
|
const exampleIndex = items.indexOf(exampleItem);
|
|
434
451
|
const exOptions = mapOptions(exampleItem.content?.options, `${parent.id}-ex`);
|
|
435
452
|
const exCorrect = exampleItem.correctAnswer?.answer || parentCorrect[exampleIndex] || exOptions[0]?.id || '';
|
|
453
|
+
const exampleImageUrl = toQuestionImageUrl(exampleItem.content?.imageUrl);
|
|
436
454
|
example = {
|
|
437
455
|
questionNumber: exampleItem.questionNumber || exampleIndex + 1,
|
|
438
456
|
questionText: exampleItem.content?.question || '',
|
|
439
457
|
options: exOptions,
|
|
440
458
|
correctOptionId: exCorrect,
|
|
441
459
|
optionType: (exampleItem.content?.optionType || 'text'),
|
|
460
|
+
...(exampleImageUrl !== undefined ? { imageUrl: exampleImageUrl } : {}),
|
|
442
461
|
};
|
|
443
462
|
}
|
|
444
463
|
const transformed = regularItems.map((item) => {
|
|
445
464
|
const itemIndex = items.indexOf(item);
|
|
446
465
|
const options = mapOptions(item.content?.options, `${parent.id}-item-${itemIndex}`);
|
|
447
466
|
const correctId = item.correctAnswer?.answer || parentCorrect[itemIndex] || '';
|
|
467
|
+
const itemImageUrl = toQuestionImageUrl(item.content?.imageUrl);
|
|
448
468
|
return {
|
|
449
469
|
id: `${parent.id}-item-${itemIndex}`,
|
|
450
470
|
questionNumber: item.questionNumber || itemIndex + 1,
|
|
@@ -453,6 +473,7 @@ export function transformChooseTheCorrectAnswerGroup(questions) {
|
|
|
453
473
|
correctOptionId: correctId,
|
|
454
474
|
correctOptionIds: correctId ? [correctId] : [],
|
|
455
475
|
optionType: (item.content?.optionType || 'text'),
|
|
476
|
+
...(itemImageUrl !== undefined ? { imageUrl: itemImageUrl } : {}),
|
|
456
477
|
};
|
|
457
478
|
});
|
|
458
479
|
return {
|
|
@@ -486,8 +507,19 @@ export function transformChooseCorrectAdjective(questions) {
|
|
|
486
507
|
instruction: 'CHOOSE THE CORRECT ADJECTIVE',
|
|
487
508
|
};
|
|
488
509
|
}
|
|
510
|
+
function extractWriteLetterPassage(content) {
|
|
511
|
+
const raw = content?.passage ?? content?.passages;
|
|
512
|
+
if (typeof raw === 'string' && raw.trim())
|
|
513
|
+
return raw;
|
|
514
|
+
if (Array.isArray(raw)) {
|
|
515
|
+
const parts = raw.filter((item) => typeof item === 'string' && item.trim().length > 0);
|
|
516
|
+
return parts.length ? parts.join('\n\n') : undefined;
|
|
517
|
+
}
|
|
518
|
+
return undefined;
|
|
519
|
+
}
|
|
489
520
|
export function transformWriteShortLetter(question) {
|
|
490
521
|
const content = question.content;
|
|
522
|
+
const passage = extractWriteLetterPassage(content);
|
|
491
523
|
// New structure: use instructions.mainInstruction as prompt, informations as requirements
|
|
492
524
|
if (content.instructions?.mainInstruction || content.informations?.length) {
|
|
493
525
|
return {
|
|
@@ -496,6 +528,7 @@ export function transformWriteShortLetter(question) {
|
|
|
496
528
|
minWords: content.minWords,
|
|
497
529
|
maxWords: content.maxWords,
|
|
498
530
|
guideImages: content.guideImages,
|
|
531
|
+
passage,
|
|
499
532
|
};
|
|
500
533
|
}
|
|
501
534
|
// Legacy structure: build prompt from contexts array
|
|
@@ -508,6 +541,7 @@ export function transformWriteShortLetter(question) {
|
|
|
508
541
|
minWords: content.minWords,
|
|
509
542
|
maxWords: content.maxWords,
|
|
510
543
|
guideImages: content.guideImages,
|
|
544
|
+
passage,
|
|
511
545
|
};
|
|
512
546
|
}
|
|
513
547
|
export function transformColorObjects(questions) {
|
|
@@ -889,6 +923,102 @@ export function transformTrueFalseGroup(questions) {
|
|
|
889
923
|
instruction: content?.meta?.instruction || 'READ AND CHOOSE TRUE OR FALSE',
|
|
890
924
|
};
|
|
891
925
|
}
|
|
926
|
+
function parseTrueFalseCorrectAnswer(raw) {
|
|
927
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
928
|
+
return undefined;
|
|
929
|
+
}
|
|
930
|
+
const obj = raw;
|
|
931
|
+
if (typeof obj.isTrue !== 'boolean') {
|
|
932
|
+
return undefined;
|
|
933
|
+
}
|
|
934
|
+
return {
|
|
935
|
+
isTrue: obj.isTrue,
|
|
936
|
+
correction: obj.isTrue ? '' : (typeof obj.correction === 'string' ? obj.correction : ''),
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
export function transformTrueFalseCorrectGroup(questions) {
|
|
940
|
+
const parent = questions[0];
|
|
941
|
+
const content = parent?.content;
|
|
942
|
+
const items = Array.isArray(content?.items) ? content.items : [];
|
|
943
|
+
const parentCorrect = Array.isArray(parent?.correct_answer?.answer)
|
|
944
|
+
? parent.correct_answer.answer
|
|
945
|
+
: [];
|
|
946
|
+
const transformed = items.map((item, index) => {
|
|
947
|
+
const isExample = item.isExample === true;
|
|
948
|
+
const exampleCorrectAnswer = isExample
|
|
949
|
+
? parseTrueFalseCorrectAnswer(item.correctAnswer?.answer ?? parentCorrect[index])
|
|
950
|
+
: undefined;
|
|
951
|
+
return {
|
|
952
|
+
id: `${parent.id}-item-${index}`,
|
|
953
|
+
questionNumber: item.questionNumber || index + 1,
|
|
954
|
+
question: item.content?.question || '',
|
|
955
|
+
isExample,
|
|
956
|
+
exampleCorrectAnswer,
|
|
957
|
+
};
|
|
958
|
+
});
|
|
959
|
+
return {
|
|
960
|
+
questions: transformed,
|
|
961
|
+
instruction: content?.meta?.instruction
|
|
962
|
+
|| 'Tick (✓) the true and cross (✗) the false sentences. Correct the false sentences.',
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
function parseFillInBlankGroupAnswer(raw) {
|
|
966
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
967
|
+
return undefined;
|
|
968
|
+
}
|
|
969
|
+
const obj = raw;
|
|
970
|
+
if (!Array.isArray(obj.answers)) {
|
|
971
|
+
return undefined;
|
|
972
|
+
}
|
|
973
|
+
return {
|
|
974
|
+
answers: obj.answers.map((blank) => (Array.isArray(blank)
|
|
975
|
+
? blank.map((alt) => String(alt ?? '').trim()).filter(Boolean)
|
|
976
|
+
: [String(blank ?? '').trim()].filter(Boolean))),
|
|
977
|
+
caseSensitive: obj.caseSensitive === true,
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
function blankCountFromMatches(matches) {
|
|
981
|
+
const indices = matches.map((match) => Number.parseInt(match[1], 10));
|
|
982
|
+
return Math.max(...indices, 0) + 1;
|
|
983
|
+
}
|
|
984
|
+
export function transformFillInBlankGroup(questions) {
|
|
985
|
+
const parent = questions[0];
|
|
986
|
+
const content = parent?.content;
|
|
987
|
+
const items = Array.isArray(content?.items) ? content.items : [];
|
|
988
|
+
const parentCorrect = Array.isArray(parent?.correct_answer?.answer)
|
|
989
|
+
? parent.correct_answer.answer
|
|
990
|
+
: [];
|
|
991
|
+
const groupAudioUrl = content?.meta?.audioUrl?.trim() || '';
|
|
992
|
+
const transformed = items.map((item, index) => {
|
|
993
|
+
const parsed = parseFillInBlankGroupAnswer(item.correctAnswer ?? parentCorrect[index]);
|
|
994
|
+
const question = item.content?.question || '{0}';
|
|
995
|
+
const blankMatches = [...question.matchAll(/\{(\d+)\}/g)];
|
|
996
|
+
const blankCount = blankMatches.length > 0 ? blankCountFromMatches(blankMatches) : 1;
|
|
997
|
+
const isExample = item.isExample === true;
|
|
998
|
+
return {
|
|
999
|
+
id: `${parent.id}-item-${index}`,
|
|
1000
|
+
questionNumber: item.questionNumber || index + 1,
|
|
1001
|
+
question,
|
|
1002
|
+
imageUrl: item.content?.imageUrl,
|
|
1003
|
+
audioUrl: groupAudioUrl ? undefined : item.content?.audioUrl,
|
|
1004
|
+
isExample,
|
|
1005
|
+
blankCount,
|
|
1006
|
+
exampleAnswers: isExample
|
|
1007
|
+
? Array.from({ length: blankCount }, (_, slot) => parsed?.answers?.[slot]?.[0] || '')
|
|
1008
|
+
: undefined,
|
|
1009
|
+
};
|
|
1010
|
+
});
|
|
1011
|
+
return {
|
|
1012
|
+
questions: transformed,
|
|
1013
|
+
instruction: content?.meta?.instruction || 'Complete the sentences.',
|
|
1014
|
+
audioUrl: groupAudioUrl || undefined,
|
|
1015
|
+
imageUrl: content?.meta?.imageUrl,
|
|
1016
|
+
showHints: content?.meta?.showHints === true,
|
|
1017
|
+
hints: Array.isArray(content?.meta?.hints)
|
|
1018
|
+
? content.meta.hints.map((hint) => String(hint ?? '').trim()).filter(Boolean)
|
|
1019
|
+
: [],
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
892
1022
|
export function transformWordOrdering(questions) {
|
|
893
1023
|
const transformed = questions.map((q) => {
|
|
894
1024
|
const content = q.content;
|
|
@@ -993,6 +1123,31 @@ export function transformMatchByWritingAnswer(questions) {
|
|
|
993
1123
|
answererName: firstConversationQ?.answererName,
|
|
994
1124
|
};
|
|
995
1125
|
}
|
|
1126
|
+
export function transformMatchWordToPicture(questions) {
|
|
1127
|
+
const groupPayload = questions[0]?.questionGroup?.payload;
|
|
1128
|
+
const wordBank = Array.isArray(groupPayload?.wordBank)
|
|
1129
|
+
? groupPayload.wordBank.filter((word) => typeof word === 'string' && word.trim().length > 0)
|
|
1130
|
+
: [];
|
|
1131
|
+
const instruction = typeof groupPayload?.instruction === 'string' && groupPayload.instruction.trim()
|
|
1132
|
+
? groupPayload.instruction.trim()
|
|
1133
|
+
: 'Look and complete.';
|
|
1134
|
+
const transformed = questions.map((q) => {
|
|
1135
|
+
const content = q.content;
|
|
1136
|
+
const isExample = q.is_example || content.isExample || false;
|
|
1137
|
+
return {
|
|
1138
|
+
id: q.id,
|
|
1139
|
+
questionNumber: q.question_number,
|
|
1140
|
+
imageUrl: content.imageUrl,
|
|
1141
|
+
isExample,
|
|
1142
|
+
exampleAnswer: isExample ? q.correct_answer?.answer : undefined,
|
|
1143
|
+
};
|
|
1144
|
+
});
|
|
1145
|
+
return {
|
|
1146
|
+
questions: transformed,
|
|
1147
|
+
wordBank,
|
|
1148
|
+
instruction,
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
996
1151
|
export function transformWriteSentences(questions) {
|
|
997
1152
|
const firstQuestion = questions[0];
|
|
998
1153
|
const content = firstQuestion?.content;
|
|
@@ -1228,3 +1383,36 @@ export function transformFindWordsInMatrix(questions) {
|
|
|
1228
1383
|
explanation: question?.explanation,
|
|
1229
1384
|
};
|
|
1230
1385
|
}
|
|
1386
|
+
export function transformMatchingWithLinesGroup(questions) {
|
|
1387
|
+
const parent = questions[0];
|
|
1388
|
+
const content = (parent?.content || {});
|
|
1389
|
+
const items = Array.isArray(content.items) ? content.items : [];
|
|
1390
|
+
const parentCorrect = Array.isArray(parent?.correct_answer?.answer)
|
|
1391
|
+
? parent.correct_answer.answer
|
|
1392
|
+
: [];
|
|
1393
|
+
const rightItems = Array.isArray(content.rightItems)
|
|
1394
|
+
? content.rightItems.map((item, index) => ({
|
|
1395
|
+
id: typeof item?.id === 'string' ? item.id : `r${index + 1}`,
|
|
1396
|
+
text: typeof item?.text === 'string' ? item.text : '',
|
|
1397
|
+
}))
|
|
1398
|
+
: [];
|
|
1399
|
+
return {
|
|
1400
|
+
questions: items.map((item, index) => {
|
|
1401
|
+
const isExample = item.isExample === true;
|
|
1402
|
+
const fromItem = typeof item.correctAnswer?.answer === 'string' ? item.correctAnswer.answer : '';
|
|
1403
|
+
const fromParent = typeof parentCorrect[index] === 'string' ? parentCorrect[index] : '';
|
|
1404
|
+
return {
|
|
1405
|
+
id: `${parent?.id || 'q'}-item-${index}`,
|
|
1406
|
+
questionNumber: item.questionNumber || index + 1,
|
|
1407
|
+
imageUrl: item.content?.imageUrl || '',
|
|
1408
|
+
correctRightId: fromItem || fromParent,
|
|
1409
|
+
isExample,
|
|
1410
|
+
points: isExample ? 0 : (typeof item.points === 'number' ? item.points : 1),
|
|
1411
|
+
};
|
|
1412
|
+
}),
|
|
1413
|
+
rightItems,
|
|
1414
|
+
title: content.meta?.title || '',
|
|
1415
|
+
instruction: content.meta?.instruction || 'Look and match.',
|
|
1416
|
+
explanation: parent?.explanation,
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
@@ -172,6 +172,16 @@ export const QUESTION_TYPE_CONFIG = {
|
|
|
172
172
|
requiresContent: true,
|
|
173
173
|
hasDedicatedComponent: true,
|
|
174
174
|
},
|
|
175
|
+
TRUE_FALSE_CORRECT_GROUP: {
|
|
176
|
+
label: 'Đúng/Sai + sửa câu (nhóm)',
|
|
177
|
+
requiresContent: true,
|
|
178
|
+
hasDedicatedComponent: true,
|
|
179
|
+
},
|
|
180
|
+
FILL_IN_BLANK_GROUP: {
|
|
181
|
+
label: 'Điền chỗ trống (nhóm)',
|
|
182
|
+
requiresContent: true,
|
|
183
|
+
hasDedicatedComponent: true,
|
|
184
|
+
},
|
|
175
185
|
CROSS_OUT_WORD_GROUP: {
|
|
176
186
|
label: 'Cross out word (group)',
|
|
177
187
|
requiresContent: true,
|
|
@@ -227,6 +237,16 @@ export const QUESTION_TYPE_CONFIG = {
|
|
|
227
237
|
requiresContent: true,
|
|
228
238
|
hasDedicatedComponent: true,
|
|
229
239
|
},
|
|
240
|
+
MATCH_WORD_TO_PICTURE: {
|
|
241
|
+
label: 'Nối từ với tranh',
|
|
242
|
+
requiresContent: true,
|
|
243
|
+
hasDedicatedComponent: true,
|
|
244
|
+
},
|
|
245
|
+
MATCHING_WITH_LINES_GROUP: {
|
|
246
|
+
label: 'Nối bằng đường kẻ (nhóm)',
|
|
247
|
+
requiresContent: true,
|
|
248
|
+
hasDedicatedComponent: true,
|
|
249
|
+
},
|
|
230
250
|
WRITE_SENTENCES: {
|
|
231
251
|
label: 'Viết câu',
|
|
232
252
|
requiresContent: true,
|
|
@@ -343,6 +363,8 @@ export const QUESTION_TYPES_WITH_DEDICATED_COMPONENTS = [
|
|
|
343
363
|
'CHOOSE_THE_CORRECT_ANSWER',
|
|
344
364
|
'CHOOSE_THE_CORRECT_ANSWER_GROUP',
|
|
345
365
|
'TRUE_FALSE_GROUP',
|
|
366
|
+
'TRUE_FALSE_CORRECT_GROUP',
|
|
367
|
+
'FILL_IN_BLANK_GROUP',
|
|
346
368
|
'CROSS_OUT_WORD_GROUP',
|
|
347
369
|
'WRITE_A_SHORT_LETTER',
|
|
348
370
|
'WRITE_CORRECT_VERB_FORM',
|
|
@@ -353,6 +375,8 @@ export const QUESTION_TYPES_WITH_DEDICATED_COMPONENTS = [
|
|
|
353
375
|
'WORD_ORDERING',
|
|
354
376
|
'WORD_FILL_PARAGRAPH',
|
|
355
377
|
'MATCH_BY_WRITING_ANSWER',
|
|
378
|
+
'MATCH_WORD_TO_PICTURE',
|
|
379
|
+
'MATCHING_WITH_LINES_GROUP',
|
|
356
380
|
'WRITE_SENTENCES',
|
|
357
381
|
'LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP',
|
|
358
382
|
'LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE',
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
export interface ChooseTheCorrectAnswerGroupOptionData {
|
|
2
2
|
id: string;
|
|
3
3
|
text: string;
|
|
4
|
+
imageUrl?: string;
|
|
4
5
|
}
|
|
6
|
+
export declare function getChooseAnswerGroupOptionImageSrc(option: Pick<ChooseTheCorrectAnswerGroupOptionData, 'imageUrl' | 'text'>): string;
|
|
7
|
+
export declare function isChooseAnswerGroupOptionFilled(option: Pick<ChooseTheCorrectAnswerGroupOptionData, 'imageUrl' | 'text'>, optionType?: 'text' | 'image'): boolean;
|
|
8
|
+
export type ChooseTheCorrectAnswerGroupImageUrl = string | string[];
|
|
9
|
+
export declare function toChooseAnswerGroupImageUrls(value?: ChooseTheCorrectAnswerGroupImageUrl): string[];
|
|
10
|
+
export declare function toEditableChooseAnswerGroupImageUrls(value?: ChooseTheCorrectAnswerGroupImageUrl): string[];
|
|
11
|
+
export declare function fromChooseAnswerGroupImageUrls(urls: string[]): ChooseTheCorrectAnswerGroupImageUrl | undefined;
|
|
5
12
|
export interface ChooseTheCorrectAnswerGroupItemData {
|
|
6
13
|
question: string;
|
|
7
14
|
optionType: 'text' | 'image';
|
|
@@ -10,6 +17,7 @@ export interface ChooseTheCorrectAnswerGroupItemData {
|
|
|
10
17
|
isExample?: boolean;
|
|
11
18
|
points: number;
|
|
12
19
|
questionNumber: number;
|
|
20
|
+
imageUrl?: ChooseTheCorrectAnswerGroupImageUrl;
|
|
13
21
|
}
|
|
14
22
|
export interface ChooseTheCorrectAnswerGroupData {
|
|
15
23
|
instruction: string;
|
|
@@ -34,4 +42,5 @@ export interface ChooseTheCorrectAnswerGroupClientProps {
|
|
|
34
42
|
questionData: ChooseTheCorrectAnswerGroupData;
|
|
35
43
|
isReviewMode?: boolean;
|
|
36
44
|
userAnswers?: string[];
|
|
45
|
+
onAnswerChange?: (answers: string[]) => void;
|
|
37
46
|
}
|
|
@@ -1 +1,49 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export function getChooseAnswerGroupOptionImageSrc(option) {
|
|
2
|
+
if (typeof option.imageUrl === 'string' && option.imageUrl.trim() !== '') {
|
|
3
|
+
return option.imageUrl.trim();
|
|
4
|
+
}
|
|
5
|
+
if (typeof option.text === 'string' && option.text.trim() !== '') {
|
|
6
|
+
return option.text.trim();
|
|
7
|
+
}
|
|
8
|
+
return '';
|
|
9
|
+
}
|
|
10
|
+
export function isChooseAnswerGroupOptionFilled(option, optionType = 'text') {
|
|
11
|
+
if (optionType === 'image') {
|
|
12
|
+
return getChooseAnswerGroupOptionImageSrc(option) !== '';
|
|
13
|
+
}
|
|
14
|
+
return typeof option.text === 'string' && option.text.trim() !== '';
|
|
15
|
+
}
|
|
16
|
+
export function toChooseAnswerGroupImageUrls(value) {
|
|
17
|
+
if (Array.isArray(value)) {
|
|
18
|
+
return value
|
|
19
|
+
.filter((url) => typeof url === 'string')
|
|
20
|
+
.map((url) => url.trim())
|
|
21
|
+
.filter((url) => url !== '');
|
|
22
|
+
}
|
|
23
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
24
|
+
return [value.trim()];
|
|
25
|
+
}
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
export function toEditableChooseAnswerGroupImageUrls(value) {
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
return value.filter((url) => typeof url === 'string');
|
|
31
|
+
}
|
|
32
|
+
if (typeof value === 'string') {
|
|
33
|
+
return [value];
|
|
34
|
+
}
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
export function fromChooseAnswerGroupImageUrls(urls) {
|
|
38
|
+
const cleaned = urls
|
|
39
|
+
.filter((url) => typeof url === 'string')
|
|
40
|
+
.map((url) => url.trim())
|
|
41
|
+
.filter((url) => url !== '');
|
|
42
|
+
if (cleaned.length === 0) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
if (cleaned.length === 1) {
|
|
46
|
+
return cleaned[0];
|
|
47
|
+
}
|
|
48
|
+
return cleaned;
|
|
49
|
+
}
|