@tinyweb_dev/oe-exam-sdk 0.2.11 → 0.2.12
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/components/question-renderers/MoversWordOrderingGroupRenderer.js +1 -0
- package/dist/components/exams/take/utils/question-transformers.d.ts +1 -0
- package/dist/components/exams/take/utils/question-transformers.js +2 -0
- package/dist/components/questions/_shared/types/word-ordering-group.type.d.ts +1 -0
- package/dist/components/questions/types/word-ordering-group/WordOrderingGroupClient.js +1 -0
- package/dist/components/questions/types/word-ordering-group/WordOrderingGroupCreator.js +3 -2
- package/dist/components/questions/types/word-ordering-group/map-word-ordering-group-data.js +2 -0
- package/dist/components/questions/types/word-ordering-group/transform.js +4 -1
- package/dist/shared/lib/utils/question-reverse-transform.js +2 -0
- package/dist/shared/types/questions/word-ordering-group.d.ts +1 -0
- package/package.json +1 -1
package/dist/components/exams/take/components/question-renderers/MoversWordOrderingGroupRenderer.js
CHANGED
|
@@ -14,6 +14,7 @@ export function MoversWordOrderingGroupRenderer({ partNumber, partName, question
|
|
|
14
14
|
items: data.questions.map((question) => ({
|
|
15
15
|
words: question.words,
|
|
16
16
|
answer: question.answer,
|
|
17
|
+
imageUrl: question.imageUrl,
|
|
17
18
|
isExample: question.isExample,
|
|
18
19
|
points: question.points,
|
|
19
20
|
questionNumber: question.questionNumber,
|
|
@@ -1424,11 +1424,13 @@ export function transformWordOrderingGroupTake(questions) {
|
|
|
1424
1424
|
const isExample = item.isExample === true;
|
|
1425
1425
|
const fromItem = Array.isArray(item.correctAnswer?.answer) ? item.correctAnswer.answer : [];
|
|
1426
1426
|
const fromParent = Array.isArray(parentCorrect[index]) ? parentCorrect[index] : [];
|
|
1427
|
+
const imageUrl = typeof item.content?.imageUrl === 'string' ? item.content.imageUrl.trim() : '';
|
|
1427
1428
|
return {
|
|
1428
1429
|
id: `${parent?.id || 'q'}-item-${index}`,
|
|
1429
1430
|
questionNumber: item.questionNumber || index + 1,
|
|
1430
1431
|
words: Array.isArray(item.content?.words) ? item.content.words : [],
|
|
1431
1432
|
answer: fromItem.length ? fromItem : fromParent,
|
|
1433
|
+
...(imageUrl ? { imageUrl } : {}),
|
|
1432
1434
|
isExample,
|
|
1433
1435
|
points: isExample ? 0 : (typeof item.points === 'number' ? item.points : 1),
|
|
1434
1436
|
};
|
|
@@ -21,5 +21,6 @@ export function WordOrderingGroupClient({ questionData, isReviewMode = false, us
|
|
|
21
21
|
answer: item.answer,
|
|
22
22
|
isExample: item.isExample,
|
|
23
23
|
points: item.points,
|
|
24
|
+
imageUrl: item.imageUrl,
|
|
24
25
|
}, isReviewMode: isReviewMode || item.isExample, userAnswer: item.isExample ? item.answer : userAnswers[itemIndex], onSubmit: (ordered) => handleItemSubmit(itemIndex, ordered) })] }, `${item.questionNumber}-${itemIndex}`))), isReviewMode && questionData.explanation && (_jsxs("div", { className: "flex items-start gap-2 rounded-xl border border-amber-100 bg-amber-50 px-4 py-3 text-sm text-amber-800", children: [_jsx(Lightbulb, { className: "mt-0.5 h-4 w-4 flex-shrink-0" }), questionData.explanation] }))] }));
|
|
25
26
|
}
|
|
@@ -18,7 +18,8 @@ function parsePointsValue(raw, allowZero = false) {
|
|
|
18
18
|
const min = allowZero ? 0 : 1;
|
|
19
19
|
return Math.max(min, parsed);
|
|
20
20
|
}
|
|
21
|
-
import { Eye, Pencil, Plus, Star, Trash2 } from 'lucide-react';
|
|
21
|
+
import { Eye, ImageIcon, Pencil, Plus, Star, Trash2 } from 'lucide-react';
|
|
22
|
+
import { FileUpload } from '../../../../components/ui/file-upload';
|
|
22
23
|
import { WordOrderingGroupClient } from './WordOrderingGroupClient';
|
|
23
24
|
import { WORD_ORDERING_GROUP_DEFAULT_INSTRUCTION } from '../../_shared/types/word-ordering-group.type';
|
|
24
25
|
import { createEmptyWordOrderingGroupItem, mapQuestionToWordOrderingGroupData, } from './map-word-ordering-group-data';
|
|
@@ -109,7 +110,7 @@ export function WordOrderingGroupCreator({ initialData, onChange, externalErrors
|
|
|
109
110
|
const displayErrors = externalErrors && externalErrors.length > 0 ? externalErrors : errors;
|
|
110
111
|
return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-lg font-medium text-gray-900", children: "T\u1EA1o c\u00E2u h\u1ECFi S\u1EAFp x\u1EBFp t\u1EEB (nh\u00F3m)" }), _jsx("p", { className: "text-sm text-gray-500", children: "M\u1ED7i d\u00F2ng m\u1ED9t c\u00E2u x\u00E1o tr\u1ED9n. M\u1ED7i token \u0111i\u1EC1n m\u1ED9t \u00F4." })] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setIsClientMode((prev) => !prev), className: "gap-2", children: [isClientMode ? _jsx(Pencil, { className: "h-4 w-4" }) : _jsx(Eye, { className: "h-4 w-4" }), isClientMode ? 'Chế độ chỉnh sửa' : 'Xem trước học sinh'] })] }), displayErrors.length > 0 && (_jsx("div", { className: "rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-700", children: _jsx("ul", { className: "list-disc space-y-1 pl-5", children: displayErrors.map((err, i) => _jsx("li", { children: err }, i)) }) })), isClientMode ? (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { className: "text-base font-semibold", children: "Xem tr\u01B0\u1EDBc hi\u1EC3n th\u1ECB h\u1ECDc sinh" }) }), _jsx(CardContent, { children: _jsx(WordOrderingGroupClient, { questionData: currentPayload }) })] })) : (_jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { className: "text-base font-semibold", children: "H\u01B0\u1EDBng d\u1EABn" }) }), _jsx(CardContent, { children: _jsx(Input, { value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: WORD_ORDERING_GROUP_DEFAULT_INSTRUCTION }) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between", children: [_jsxs(CardTitle, { className: "text-base font-semibold", children: ["C\u00E2u h\u1ECFi (", items.length, ")"] }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setItems((prev) => [...prev, createEmptyWordOrderingGroupItem(prev.length + 1)]), children: [_jsx(Plus, { className: "mr-1 h-4 w-4" }), "Th\u00EAm c\u00E2u"] })] }), _jsx(CardContent, { className: "space-y-4", children: items.map((item, index) => (_jsxs("div", { className: "space-y-3 rounded-lg border border-gray-200 p-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("span", { className: "text-sm font-medium", children: ["C\u00E2u ", item.questionNumber || index + 1] }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Switch, { checked: item.isExample || false, onCheckedChange: (checked) => updateItem(index, { isExample: checked, points: checked ? 0 : 1 }) }), _jsxs(Label, { className: "flex items-center gap-1 text-xs", children: [_jsx(Star, { className: "h-3 w-3 text-amber-500" }), "Example"] }), !item.isExample && (_jsx("div", { className: "w-24", children: _jsx(PointsInput, { value: item.points, allowZero: true, onChange: (event) => updateItem(index, {
|
|
111
112
|
points: parsePointsValue(event.target.value, true),
|
|
112
|
-
}) }) })), items.length > 1 && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setItems((prev) => prev.filter((_, i) => i !== index).map((entry, i) => ({ ...entry, questionNumber: i + 1 }))), children: _jsx(Trash2, { className: "h-4 w-4 text-red-500" }) }))] })] }), _jsxs("div", { children: [_jsx(Label, { children: "Token x\u00E1o tr\u1ED9n" }), _jsx(TokenBoxRow, { tokens: withMinTokens(item.words), onChange: (tokenIndex, value) => updateItem(index, {
|
|
113
|
+
}) }) })), items.length > 1 && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setItems((prev) => prev.filter((_, i) => i !== index).map((entry, i) => ({ ...entry, questionNumber: i + 1 }))), children: _jsx(Trash2, { className: "h-4 w-4 text-red-500" }) }))] })] }), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2", children: [_jsx(ImageIcon, { className: "h-4 w-4 text-amber-500" }), "H\u00ECnh \u1EA3nh (tu\u1EF3 ch\u1ECDn)"] }), _jsx(FileUpload, { id: `word-ordering-group-image-${index}`, label: "", accept: "image/*", value: item.imageUrl || '', onChange: (url) => updateItem(index, { imageUrl: url || undefined }), maxSize: 5, placeholder: "Upload h\u00ECnh \u1EA3nh ho\u1EB7c paste URL", autoUpload: true, prefix: "questions" })] }), _jsxs("div", { children: [_jsx(Label, { children: "Token x\u00E1o tr\u1ED9n" }), _jsx(TokenBoxRow, { tokens: withMinTokens(item.words), onChange: (tokenIndex, value) => updateItem(index, {
|
|
113
114
|
words: setTokenAt(item.words, tokenIndex, value),
|
|
114
115
|
}), onAdd: () => updateItem(index, { words: [...item.words, ''] }), onRemove: (tokenIndex) => updateItem(index, {
|
|
115
116
|
words: item.words.filter((_, current) => current !== tokenIndex),
|
|
@@ -37,9 +37,11 @@ export function mapWordOrderingGroupItem(item, index, fallbackAnswer) {
|
|
|
37
37
|
: asStringList(record.answer).length
|
|
38
38
|
? asStringList(record.answer)
|
|
39
39
|
: asStringList(fallbackAnswer);
|
|
40
|
+
const imageUrl = asString(content.imageUrl).trim() || asString(record.imageUrl).trim();
|
|
40
41
|
return {
|
|
41
42
|
words,
|
|
42
43
|
answer,
|
|
44
|
+
...(imageUrl ? { imageUrl } : {}),
|
|
43
45
|
isExample,
|
|
44
46
|
points: isExample ? 0 : (typeof record.points === 'number' ? record.points : 1),
|
|
45
47
|
questionNumber: typeof record.questionNumber === 'number' ? record.questionNumber : index + 1,
|
|
@@ -13,7 +13,10 @@ export const transformWordOrderingGroup = (question) => {
|
|
|
13
13
|
const apiItems = items.map((item, index) => ({
|
|
14
14
|
questionType: WORD_ORDERING_ITEM_TYPE,
|
|
15
15
|
...(item.isExample ? { isExample: true } : {}),
|
|
16
|
-
content: {
|
|
16
|
+
content: {
|
|
17
|
+
words: tokens(item.words),
|
|
18
|
+
...(item.imageUrl?.trim() ? { imageUrl: item.imageUrl.trim() } : {}),
|
|
19
|
+
},
|
|
17
20
|
correctAnswer: { answer: tokens(item.answer) },
|
|
18
21
|
points: item.isExample ? 0 : (typeof item.points === 'number' ? item.points : 1),
|
|
19
22
|
questionNumber: item.questionNumber || index + 1,
|
|
@@ -627,9 +627,11 @@ const reverseWordOrderingGroup = (apiQuestion) => {
|
|
|
627
627
|
const words = asArray(itemContent.words).map((token) => asString(token)).filter(Boolean);
|
|
628
628
|
const itemTokens = asArray(itemAnswer.answer).map((token) => asString(token)).filter(Boolean);
|
|
629
629
|
const fallbackTokens = asArray(fallbackAnswers[index]).map((token) => asString(token)).filter(Boolean);
|
|
630
|
+
const imageUrl = asString(itemContent.imageUrl).trim();
|
|
630
631
|
return {
|
|
631
632
|
words,
|
|
632
633
|
answer: itemTokens.length ? itemTokens : fallbackTokens,
|
|
634
|
+
...(imageUrl ? { imageUrl } : {}),
|
|
633
635
|
isExample,
|
|
634
636
|
points: isExample ? 0 : (typeof item.points === 'number' ? item.points : 1),
|
|
635
637
|
questionNumber: typeof item.questionNumber === 'number' ? item.questionNumber : index + 1,
|