@tinyweb_dev/oe-exam-sdk 0.2.2 → 0.2.4
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/CueCardEditor.d.ts +1 -7
- package/dist/components/CueCardEditor.js +1 -58
- package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +1 -1
- package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +16 -2
- package/dist/components/questions/viewer/AnswerTheQuestionGroupViewer.d.ts +8 -0
- package/dist/components/questions/viewer/AnswerTheQuestionGroupViewer.js +11 -0
- package/dist/components/questions/viewer/QuestionViewer.js +40 -6
- package/dist/components/questions/viewer/index.d.ts +1 -0
- package/dist/components/questions/viewer/index.js +1 -0
- package/dist/components/shared/CueCardEditor.d.ts +7 -0
- package/dist/components/shared/CueCardEditor.js +44 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/shared/lib/utils/question-reverse-transform.js +55 -2
- package/package.json +1 -1
|
@@ -1,7 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export interface CueCardEditorProps {
|
|
3
|
-
value?: string;
|
|
4
|
-
onChange: (html: string) => void;
|
|
5
|
-
label?: React.ReactNode;
|
|
6
|
-
}
|
|
7
|
-
export declare function CueCardEditor({ value, onChange, label, }: CueCardEditorProps): React.JSX.Element;
|
|
1
|
+
export * from './shared/CueCardEditor';
|
|
@@ -1,58 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
4
|
-
import { useEditor, EditorContent } from '@tiptap/react';
|
|
5
|
-
import StarterKit from '@tiptap/starter-kit';
|
|
6
|
-
const DEFAULT_CONTENT = `
|
|
7
|
-
<p><strong>Describe a topic you know well.</strong></p>
|
|
8
|
-
<p>You should say:</p>
|
|
9
|
-
<ul>
|
|
10
|
-
<li>What it is</li>
|
|
11
|
-
<li>When you first learned about it</li>
|
|
12
|
-
<li>Why you find it interesting</li>
|
|
13
|
-
</ul>
|
|
14
|
-
<p><em>and explain how it has impacted your life.</em></p>
|
|
15
|
-
`;
|
|
16
|
-
export function CueCardEditor({ value, onChange, label, }) {
|
|
17
|
-
const [mounted, setMounted] = useState(false);
|
|
18
|
-
const editor = useEditor({
|
|
19
|
-
immediatelyRender: false,
|
|
20
|
-
extensions: [StarterKit],
|
|
21
|
-
content: value || DEFAULT_CONTENT,
|
|
22
|
-
onUpdate: ({ editor }) => {
|
|
23
|
-
onChange(editor.getHTML());
|
|
24
|
-
},
|
|
25
|
-
editorProps: {
|
|
26
|
-
attributes: {
|
|
27
|
-
class: 'tiptap-editor focus:outline-none min-h-[250px] p-4 bg-white border border-gray-200 rounded-b-md',
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
useEffect(() => {
|
|
32
|
-
setMounted(true);
|
|
33
|
-
}, []);
|
|
34
|
-
// Sync value if changed from outside (e.g., initial load)
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
if (editor && value !== undefined && value !== editor.getHTML()) {
|
|
37
|
-
// Small timeout to prevent update loops
|
|
38
|
-
setTimeout(() => editor.commands.setContent(value), 0);
|
|
39
|
-
}
|
|
40
|
-
}, [value, editor]);
|
|
41
|
-
if (!mounted)
|
|
42
|
-
return null;
|
|
43
|
-
return (_jsxs("div", { className: "w-full flex flex-col gap-4", children: [label && _jsx("div", { children: label }), _jsxs("div", { className: "flex flex-col border border-gray-300 rounded-md shadow-sm", children: [_jsxs("div", { className: "flex flex-wrap gap-2 p-2 relative bg-gray-50 border-b border-gray-300 rounded-t-md", children: [_jsx("button", { type: "button", onClick: () => editor?.chain().focus().toggleBold().run(), disabled: !editor?.can().chain().focus().toggleBold().run(), className: `px-3 py-1 rounded text-sm font-bold ${editor?.isActive('bold')
|
|
44
|
-
? 'bg-blue-500 text-white'
|
|
45
|
-
: 'bg-white border text-gray-700 hover:bg-gray-100'}`, children: "B" }), _jsx("button", { type: "button", onClick: () => editor?.chain().focus().toggleItalic().run(), disabled: !editor?.can().chain().focus().toggleItalic().run(), className: `px-3 py-1 rounded text-sm italic ${editor?.isActive('italic')
|
|
46
|
-
? 'bg-blue-500 text-white'
|
|
47
|
-
: 'bg-white border text-gray-700 hover:bg-gray-100'}`, children: "I" }), _jsx("div", { className: "w-px h-6 bg-gray-300 mx-1 self-center" }), _jsx("button", { type: "button", onClick: () => editor?.chain().focus().toggleHeading({ level: 1 }).run(), className: `px-3 py-1 rounded text-sm font-bold ${editor?.isActive('heading', { level: 1 })
|
|
48
|
-
? 'bg-blue-500 text-white'
|
|
49
|
-
: 'bg-white border text-gray-700 hover:bg-gray-100'}`, children: "H1" }), _jsx("button", { type: "button", onClick: () => editor?.chain().focus().toggleHeading({ level: 2 }).run(), className: `px-3 py-1 rounded text-sm font-bold ${editor?.isActive('heading', { level: 2 })
|
|
50
|
-
? 'bg-blue-500 text-white'
|
|
51
|
-
: 'bg-white border text-gray-700 hover:bg-gray-100'}`, children: "H2" }), _jsx("button", { type: "button", onClick: () => editor?.chain().focus().toggleHeading({ level: 3 }).run(), className: `px-3 py-1 rounded text-sm font-bold ${editor?.isActive('heading', { level: 3 })
|
|
52
|
-
? 'bg-blue-500 text-white'
|
|
53
|
-
: 'bg-white border text-gray-700 hover:bg-gray-100'}`, children: "H3" }), _jsx("div", { className: "w-px h-6 bg-gray-300 mx-1 self-center" }), _jsx("button", { type: "button", onClick: () => editor?.chain().focus().toggleBulletList().run(), className: `px-3 py-1 rounded text-sm ${editor?.isActive('bulletList')
|
|
54
|
-
? 'bg-blue-500 text-white'
|
|
55
|
-
: 'bg-white border text-gray-700 hover:bg-gray-100'}`, children: "\u2022 List" }), _jsx("button", { type: "button", onClick: () => editor?.chain().focus().toggleOrderedList().run(), className: `px-3 py-1 rounded text-sm ${editor?.isActive('orderedList')
|
|
56
|
-
? 'bg-blue-500 text-white'
|
|
57
|
-
: 'bg-white border text-gray-700 hover:bg-gray-100'}`, children: "1. List" })] }), _jsx(EditorContent, { editor: editor })] })] }));
|
|
58
|
-
}
|
|
1
|
+
export * from './shared/CueCardEditor';
|
|
@@ -4,7 +4,7 @@ import { useState, useEffect, useRef, useCallback } from 'react';
|
|
|
4
4
|
import { Card, CardContent, CardHeader, CardTitle } from '../../../../components/ui/card';
|
|
5
5
|
import { Input } from '../../../../components/ui/input';
|
|
6
6
|
import { Label } from '../../../../components/ui/label';
|
|
7
|
-
import { CueCardEditor } from '../../../../components/CueCardEditor';
|
|
7
|
+
import { CueCardEditor } from '../../../../components/shared/CueCardEditor';
|
|
8
8
|
import { CreatorGuide } from '../../components/CreatorGuide';
|
|
9
9
|
import { CreditCard } from 'lucide-react';
|
|
10
10
|
export function SpeakingCueCardCreator({ initialData, onChange, onUnsavedChangesChange, externalErrors, validationRef, }) {
|
|
@@ -17,8 +17,22 @@ function GuideImageDisplay({ imageKey }) {
|
|
|
17
17
|
} }) }));
|
|
18
18
|
}
|
|
19
19
|
export function WriteAShortLetterClient({ questionData, onSubmit, isReviewMode = false, userAnswer, explanation, }) {
|
|
20
|
-
const {
|
|
21
|
-
const instruction = instructions?.mainInstruction ||
|
|
20
|
+
const { minWords = 20, maxWords } = questionData;
|
|
21
|
+
const instruction = questionData.instructions?.mainInstruction ||
|
|
22
|
+
(typeof questionData.instructions === 'string' ? questionData.instructions : '') ||
|
|
23
|
+
questionData.instruction ||
|
|
24
|
+
questionData.prompt ||
|
|
25
|
+
'';
|
|
26
|
+
const informations = Array.isArray(questionData.informations)
|
|
27
|
+
? questionData.informations
|
|
28
|
+
: Array.isArray(questionData.requirements)
|
|
29
|
+
? questionData.requirements
|
|
30
|
+
: [];
|
|
31
|
+
const guideImages = Array.isArray(questionData.guideImages)
|
|
32
|
+
? questionData.guideImages
|
|
33
|
+
: Array.isArray(questionData.images)
|
|
34
|
+
? questionData.images
|
|
35
|
+
: [];
|
|
22
36
|
// Initialize answer state - ensure it's always a string
|
|
23
37
|
const [answer, setAnswer] = useState(typeof userAnswer === 'string' ? userAnswer : '');
|
|
24
38
|
// Sync userAnswer when it changes (e.g., when loading from server in review mode)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Question } from '../../../shared/types/entities/question.types';
|
|
2
|
+
type AnswerTheQuestionGroupViewerProps = {
|
|
3
|
+
question: Question;
|
|
4
|
+
isReviewMode?: boolean;
|
|
5
|
+
userAnswer?: string[];
|
|
6
|
+
};
|
|
7
|
+
export declare function AnswerTheQuestionGroupViewer({ question, isReviewMode, userAnswer, }: AnswerTheQuestionGroupViewerProps): import("react").JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { AnswerTheQuestionGroupClient } from '../types/answer-the-question-group/AnswerTheQuestionGroupClient';
|
|
4
|
+
import { mapQuestionToAnswerTheQuestionGroupData } from '../types/answer-the-question-group/map-answer-the-question-group-data';
|
|
5
|
+
export function AnswerTheQuestionGroupViewer({ question, isReviewMode = false, userAnswer, }) {
|
|
6
|
+
const questionData = mapQuestionToAnswerTheQuestionGroupData(question);
|
|
7
|
+
const reviewAnswers = isReviewMode && !userAnswer
|
|
8
|
+
? questionData.items.map((item) => item.expectedAnswers[0] || '')
|
|
9
|
+
: userAnswer;
|
|
10
|
+
return (_jsx(AnswerTheQuestionGroupClient, { questionData: questionData, isReviewMode: isReviewMode, userAnswers: reviewAnswers }));
|
|
11
|
+
}
|
|
@@ -20,6 +20,7 @@ import { LookPictureFillBlankChooseAnswerClient } from '../types/look-picture-fi
|
|
|
20
20
|
import { FillMissingWordsInGridClient } from '../types/fill-missing-words-in-grid/FillMissingWordsInGridClient';
|
|
21
21
|
import { WordFillStructuredFormClient } from '../types/word-fill-structured-form/WordFillStructuredFormClient';
|
|
22
22
|
import { CrosswordPuzzleClient } from '../types/crossword-puzzle/CrosswordPuzzleClient';
|
|
23
|
+
import { FindWordsInMatrixClient } from '../types/find-words-in-matrix/FindWordsInMatrixClient';
|
|
23
24
|
import { parseFillBlankStemLine } from '../_shared/utils/parseFillBlankStem';
|
|
24
25
|
import { WordFillStructuredFormViewer } from './WordFillStructuredFormViewer';
|
|
25
26
|
import { ChooseTheCorrectAnswerGroupViewer } from './ChooseTheCorrectAnswerGroupViewer';
|
|
@@ -27,6 +28,7 @@ import { TrueFalseGroupViewer } from './TrueFalseGroupViewer';
|
|
|
27
28
|
import { CrossOutWordGroupViewer } from './CrossOutWordGroupViewer';
|
|
28
29
|
import { SpontaneousQaGroupViewer } from './SpontaneousQaGroupViewer';
|
|
29
30
|
import { WordOrderAndMatchGroupViewer } from './WordOrderAndMatchGroupViewer';
|
|
31
|
+
import { AnswerTheQuestionGroupViewer } from './AnswerTheQuestionGroupViewer';
|
|
30
32
|
export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false, userAnswer, }) {
|
|
31
33
|
const [selectedAnswer, setSelectedAnswer] = useState(userAnswer || null);
|
|
32
34
|
const [playCount, setPlayCount] = useState(0);
|
|
@@ -314,13 +316,41 @@ export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false,
|
|
|
314
316
|
}, isReviewMode: isReviewMode, userAnswer: userAnswer }));
|
|
315
317
|
};
|
|
316
318
|
const renderWriteAShortLetter = () => {
|
|
317
|
-
const
|
|
319
|
+
const content = (question.content || {});
|
|
320
|
+
const answer = (question.answer || {});
|
|
321
|
+
const mainInstruction = content?.instructions?.mainInstruction ||
|
|
322
|
+
content?.instruction ||
|
|
323
|
+
content?.prompt ||
|
|
324
|
+
answer?.instructions?.mainInstruction ||
|
|
325
|
+
answer?.instruction ||
|
|
326
|
+
(typeof content?.instructions === 'string' ? content.instructions : '') ||
|
|
327
|
+
(typeof content === 'string' ? content : '') ||
|
|
328
|
+
'';
|
|
329
|
+
const informations = (Array.isArray(content?.informations)
|
|
330
|
+
? content.informations
|
|
331
|
+
: Array.isArray(content?.requirements)
|
|
332
|
+
? content.requirements
|
|
333
|
+
: Array.isArray(answer?.informations)
|
|
334
|
+
? answer.informations
|
|
335
|
+
: []).map((info) => typeof info === 'string' ? info : (info.text || info.content || ''));
|
|
336
|
+
const guideImages = Array.isArray(content?.guideImages)
|
|
337
|
+
? content.guideImages
|
|
338
|
+
: Array.isArray(answer?.guideImages)
|
|
339
|
+
? answer.guideImages
|
|
340
|
+
: [];
|
|
341
|
+
const contexts = content?.contexts || answer?.contexts || [];
|
|
342
|
+
const minWords = content?.minWords ?? answer?.minWords ?? 20;
|
|
343
|
+
const maxWords = content?.maxWords ?? answer?.maxWords ?? null;
|
|
318
344
|
const questionData = {
|
|
319
|
-
contexts
|
|
320
|
-
informations
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
345
|
+
contexts,
|
|
346
|
+
informations,
|
|
347
|
+
guideImages,
|
|
348
|
+
minWords,
|
|
349
|
+
maxWords,
|
|
350
|
+
instructions: {
|
|
351
|
+
mainInstruction,
|
|
352
|
+
},
|
|
353
|
+
instruction: mainInstruction,
|
|
324
354
|
};
|
|
325
355
|
return (_jsx(WriteAShortLetterClient, { questionData: questionData, onSubmit: (answerText) => {
|
|
326
356
|
setSelectedAnswer(answerText);
|
|
@@ -600,6 +630,8 @@ export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false,
|
|
|
600
630
|
return (_jsx(TrueFalseGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer }));
|
|
601
631
|
case 'CROSS_OUT_WORD_GROUP':
|
|
602
632
|
return (_jsx(CrossOutWordGroupViewer, { question: question, isReviewMode: isReviewMode }));
|
|
633
|
+
case 'ANSWER_THE_QUESTION_GROUP':
|
|
634
|
+
return (_jsx(AnswerTheQuestionGroupViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer }));
|
|
603
635
|
case 'SPONTANEOUS_QA_GROUP':
|
|
604
636
|
return (_jsx(SpontaneousQaGroupViewer, { question: question, isReviewMode: isReviewMode }));
|
|
605
637
|
case 'WORD_ORDER_AND_MATCH_GROUP':
|
|
@@ -646,6 +678,8 @@ export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false,
|
|
|
646
678
|
return (_jsx(WordFillStructuredFormViewer, { question: question, isReviewMode: isReviewMode, userAnswer: userAnswer, onSubmitAnswer: onSubmitAnswer }));
|
|
647
679
|
case 'CROSSWORD_PUZZLE':
|
|
648
680
|
return (_jsx(CrosswordPuzzleClient, { content: question.content, correctAnswer: question.answer, isReviewMode: isReviewMode, userAnswers: userAnswer }));
|
|
681
|
+
case 'FIND_WORDS_IN_MATRIX':
|
|
682
|
+
return (_jsx(FindWordsInMatrixClient, { content: question.content, correctAnswer: question.answer, showSolution: isReviewMode }));
|
|
649
683
|
default:
|
|
650
684
|
return _jsxs("div", { children: ["Lo\u1EA1i c\u00E2u h\u1ECFi kh\u00F4ng \u0111\u01B0\u1EE3c h\u1ED7 tr\u1EE3: ", question.type] });
|
|
651
685
|
}
|
|
@@ -6,3 +6,4 @@ export { TrueFalseGroupViewer } from './TrueFalseGroupViewer';
|
|
|
6
6
|
export { CrossOutWordGroupViewer } from './CrossOutWordGroupViewer';
|
|
7
7
|
export { SpontaneousQaGroupViewer } from './SpontaneousQaGroupViewer';
|
|
8
8
|
export { WordOrderAndMatchGroupViewer } from './WordOrderAndMatchGroupViewer';
|
|
9
|
+
export { AnswerTheQuestionGroupViewer } from './AnswerTheQuestionGroupViewer';
|
|
@@ -6,3 +6,4 @@ export { TrueFalseGroupViewer } from './TrueFalseGroupViewer';
|
|
|
6
6
|
export { CrossOutWordGroupViewer } from './CrossOutWordGroupViewer';
|
|
7
7
|
export { SpontaneousQaGroupViewer } from './SpontaneousQaGroupViewer';
|
|
8
8
|
export { WordOrderAndMatchGroupViewer } from './WordOrderAndMatchGroupViewer';
|
|
9
|
+
export { AnswerTheQuestionGroupViewer } from './AnswerTheQuestionGroupViewer';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { useEditor, EditorContent } from '@tiptap/react';
|
|
5
|
+
import StarterKit from '@tiptap/starter-kit';
|
|
6
|
+
const DEFAULT_CONTENT = `
|
|
7
|
+
<p><strong>Describe a topic you know well.</strong></p>
|
|
8
|
+
<p>You should say:</p>
|
|
9
|
+
<ul>
|
|
10
|
+
<li>What it is</li>
|
|
11
|
+
<li>When you first learned about it</li>
|
|
12
|
+
<li>Why you find it interesting</li>
|
|
13
|
+
</ul>
|
|
14
|
+
<p><em>and explain how it has impacted your life.</em></p>
|
|
15
|
+
`;
|
|
16
|
+
export function CueCardEditor({ value, onChange, label, }) {
|
|
17
|
+
const [mounted, setMounted] = useState(false);
|
|
18
|
+
const editor = useEditor({
|
|
19
|
+
immediatelyRender: false,
|
|
20
|
+
extensions: [StarterKit],
|
|
21
|
+
content: value || DEFAULT_CONTENT,
|
|
22
|
+
onUpdate: ({ editor }) => {
|
|
23
|
+
onChange(editor.getHTML());
|
|
24
|
+
},
|
|
25
|
+
editorProps: {
|
|
26
|
+
attributes: {
|
|
27
|
+
class: 'tiptap-editor focus:outline-none min-h-[250px] p-4 bg-white border border-gray-200 rounded-b-md',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
setMounted(true);
|
|
33
|
+
}, []);
|
|
34
|
+
// Sync value if changed from outside (e.g., initial load)
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (editor && value !== undefined && value !== editor.getHTML()) {
|
|
37
|
+
// Small timeout to prevent update loops
|
|
38
|
+
setTimeout(() => editor.commands.setContent(value), 0);
|
|
39
|
+
}
|
|
40
|
+
}, [value, editor]);
|
|
41
|
+
if (!mounted)
|
|
42
|
+
return null;
|
|
43
|
+
return (_jsxs("div", { className: "flex flex-col gap-1.5 w-full", children: [label && (_jsx("label", { className: "text-sm font-medium leading-none text-gray-700", children: label })), _jsxs("div", { className: "rounded-md border border-gray-200 shadow-sm overflow-hidden focus-within:ring-2 focus-within:ring-blue-500 focus-within:border-blue-500", children: [editor && (_jsxs("div", { className: "flex items-center gap-1 p-2 bg-gray-50 border-b border-gray-200 flex-wrap", children: [_jsx("button", { type: "button", onClick: () => editor.chain().focus().toggleBold().run(), className: `p-1.5 rounded hover:bg-gray-200 text-xs font-semibold text-gray-700 ${editor.isActive('bold') ? 'bg-gray-200' : ''}`, title: "Bold", children: "B" }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().toggleItalic().run(), className: `p-1.5 rounded hover:bg-gray-200 text-xs italic text-gray-700 ${editor.isActive('italic') ? 'bg-gray-200' : ''}`, title: "Italic", children: "I" }), _jsx("div", { className: "w-[1px] h-4 bg-gray-300 mx-1" }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().toggleHeading({ level: 3 }).run(), className: `p-1.5 rounded hover:bg-gray-200 text-xs font-semibold text-gray-700 ${editor.isActive('heading', { level: 3 }) ? 'bg-gray-200' : ''}`, title: "Heading", children: "H3" }), _jsx("div", { className: "w-[1px] h-4 bg-gray-300 mx-1" }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().toggleBulletList().run(), className: `p-1.5 rounded hover:bg-gray-200 text-xs text-gray-700 ${editor.isActive('bulletList') ? 'bg-gray-200' : ''}`, title: "Bullet List", children: "\u2022 List" }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().toggleOrderedList().run(), className: `p-1.5 rounded hover:bg-gray-200 text-xs text-gray-700 ${editor.isActive('orderedList') ? 'bg-gray-200' : ''}`, title: "Numbered List", children: "1. List" }), _jsx("div", { className: "w-[1px] h-4 bg-gray-300 mx-1" }), _jsx("button", { type: "button", onClick: () => editor.chain().focus().clearNodes().unsetAllMarks().run(), className: "p-1.5 rounded hover:bg-gray-200 text-xs text-gray-500", title: "Clear Formatting", children: "Clear" })] })), _jsx(EditorContent, { editor: editor })] })] }));
|
|
44
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -26,4 +26,4 @@ export { validateQuestion } from './components/questions/_shared/utils/question-
|
|
|
26
26
|
export { buildAnswerPayload } from './components/questions/_shared/utils/answer-builder';
|
|
27
27
|
export type { QuestionFormState } from './components/questions/_shared/hooks/useQuestionFormState';
|
|
28
28
|
export * from './components/questions/_shared/types';
|
|
29
|
-
export { QuestionViewer, QuestionGroupViewer, WordFillStructuredFormViewer, ChooseTheCorrectAnswerGroupViewer, TrueFalseGroupViewer, CrossOutWordGroupViewer, SpontaneousQaGroupViewer, WordOrderAndMatchGroupViewer, } from './components/questions/viewer';
|
|
29
|
+
export { QuestionViewer, QuestionGroupViewer, WordFillStructuredFormViewer, ChooseTheCorrectAnswerGroupViewer, TrueFalseGroupViewer, CrossOutWordGroupViewer, SpontaneousQaGroupViewer, WordOrderAndMatchGroupViewer, AnswerTheQuestionGroupViewer, } from './components/questions/viewer';
|
package/dist/index.js
CHANGED
|
@@ -21,4 +21,4 @@ export { QUESTION_TYPE_CONFIG, QUESTION_TYPES_WITH_DEDICATED_COMPONENTS } from '
|
|
|
21
21
|
export { validateQuestion } from './components/questions/_shared/utils/question-validation';
|
|
22
22
|
export { buildAnswerPayload } from './components/questions/_shared/utils/answer-builder';
|
|
23
23
|
export * from './components/questions/_shared/types';
|
|
24
|
-
export { QuestionViewer, QuestionGroupViewer, WordFillStructuredFormViewer, ChooseTheCorrectAnswerGroupViewer, TrueFalseGroupViewer, CrossOutWordGroupViewer, SpontaneousQaGroupViewer, WordOrderAndMatchGroupViewer, } from './components/questions/viewer';
|
|
24
|
+
export { QuestionViewer, QuestionGroupViewer, WordFillStructuredFormViewer, ChooseTheCorrectAnswerGroupViewer, TrueFalseGroupViewer, CrossOutWordGroupViewer, SpontaneousQaGroupViewer, WordOrderAndMatchGroupViewer, AnswerTheQuestionGroupViewer, } from './components/questions/viewer';
|
|
@@ -424,8 +424,8 @@ const handlers = {
|
|
|
424
424
|
WORD_ORDERING: reverseSimpleAnswer,
|
|
425
425
|
WORD_FILL_PARAGRAPH: reverseSimpleAnswer,
|
|
426
426
|
MATCH_BY_WRITING_ANSWER: reverseGroupPayload,
|
|
427
|
-
|
|
428
|
-
WRITE_A_SHORT_LETTER:
|
|
427
|
+
WRITE_SHORT_PARAGRAPH: reverseWriteShortParagraph,
|
|
428
|
+
WRITE_A_SHORT_LETTER: reverseWriteAShortLetter,
|
|
429
429
|
WRITE_CORRECT_VERB_FORM: reverseSimpleAnswer,
|
|
430
430
|
CHOOSE_CORRECT_ADJECTIVE: reverseSimpleAnswer,
|
|
431
431
|
WORD_FILL_STRUCTURED_FORM: reverseGroupPayload,
|
|
@@ -449,6 +449,59 @@ const handlers = {
|
|
|
449
449
|
CROSSWORD_PUZZLE: reverseCrosswordPuzzle,
|
|
450
450
|
FIND_WORDS_IN_MATRIX: reverseFindWordsInMatrix,
|
|
451
451
|
};
|
|
452
|
+
function reverseWriteAShortLetter(apiQuestion) {
|
|
453
|
+
const content = asRecord(apiQuestion.content);
|
|
454
|
+
const answer = readAnswer(apiQuestion);
|
|
455
|
+
const informations = asArray(content.informations ?? answer.informations).map((item) => asString(item)).filter(Boolean);
|
|
456
|
+
const guideImages = asArray(content.guideImages ?? answer.guideImages).map((item) => asString(item)).filter(Boolean);
|
|
457
|
+
const contexts = asArray(content.contexts ?? answer.contexts);
|
|
458
|
+
const instructions = isRecord(content.instructions)
|
|
459
|
+
? content.instructions
|
|
460
|
+
: isRecord(answer.instructions)
|
|
461
|
+
? answer.instructions
|
|
462
|
+
: { mainInstruction: asString(content.instruction ?? content.prompt ?? answer.instruction ?? answer.prompt) };
|
|
463
|
+
const minWords = asNumber(content.minWords ?? answer.minWords, 20);
|
|
464
|
+
const maxWords = content.maxWords !== undefined && content.maxWords !== null
|
|
465
|
+
? asNumber(content.maxWords, 0) || null
|
|
466
|
+
: answer.maxWords !== undefined && answer.maxWords !== null
|
|
467
|
+
? asNumber(answer.maxWords, 0) || null
|
|
468
|
+
: null;
|
|
469
|
+
const resolved = {
|
|
470
|
+
instructions,
|
|
471
|
+
instruction: asString(instructions.mainInstruction || instructions.instruction),
|
|
472
|
+
informations,
|
|
473
|
+
guideImages,
|
|
474
|
+
contexts,
|
|
475
|
+
minWords,
|
|
476
|
+
maxWords,
|
|
477
|
+
};
|
|
478
|
+
return {
|
|
479
|
+
content: resolved,
|
|
480
|
+
answer: resolved,
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
function reverseWriteShortParagraph(apiQuestion) {
|
|
484
|
+
const content = asRecord(apiQuestion.content);
|
|
485
|
+
const answer = readAnswer(apiQuestion);
|
|
486
|
+
const contexts = asArray(content.contexts ?? answer.contexts);
|
|
487
|
+
const instruction = asString(content.instruction ?? content.instructions?.mainInstruction ?? answer.instruction);
|
|
488
|
+
const minWords = asNumber(content.minWords ?? answer.minWords, 20);
|
|
489
|
+
const maxWords = content.maxWords !== undefined && content.maxWords !== null
|
|
490
|
+
? asNumber(content.maxWords, 0) || null
|
|
491
|
+
: answer.maxWords !== undefined && answer.maxWords !== null
|
|
492
|
+
? asNumber(answer.maxWords, 0) || null
|
|
493
|
+
: null;
|
|
494
|
+
const resolved = {
|
|
495
|
+
instruction,
|
|
496
|
+
contexts,
|
|
497
|
+
minWords,
|
|
498
|
+
maxWords,
|
|
499
|
+
};
|
|
500
|
+
return {
|
|
501
|
+
content: resolved,
|
|
502
|
+
answer: resolved,
|
|
503
|
+
};
|
|
504
|
+
}
|
|
452
505
|
function reverseCrosswordPuzzle(apiQuestion) {
|
|
453
506
|
const apiContent = (apiQuestion.content || {});
|
|
454
507
|
const apiAnswer = (apiQuestion.correctAnswer || apiQuestion.correct_answer || apiQuestion.answer || {});
|