@tinyweb_dev/oe-exam-sdk 1.0.6 → 1.0.8
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/ExamCreator.js +1 -16
- package/dist/components/exams/take/ExamTakingPageContainer.js +0 -12
- package/dist/components/exams/take/components/QuestionRenderer.js +2 -15
- package/dist/components/exams/take/components/question-renderers/index.d.ts +0 -3
- package/dist/components/exams/take/components/question-renderers/index.js +0 -3
- package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionRenderer.js +0 -4
- package/dist/components/exams/take/types/speaking.types.d.ts +0 -31
- package/dist/components/exams/take/types.d.ts +0 -65
- package/dist/components/exams/take/utils/answer-transformers.js +6 -60
- package/dist/components/exams/take/utils/question-transformers.d.ts +2 -15
- package/dist/components/exams/take/utils/question-transformers.js +0 -143
- package/dist/components/questions/_shared/components/compact/CompactCreatorHeader.d.ts +23 -0
- package/dist/components/questions/_shared/components/compact/CompactCreatorHeader.js +9 -0
- package/dist/components/questions/_shared/components/compact/CompactExampleToggle.d.ts +6 -0
- package/dist/components/questions/_shared/components/compact/CompactExampleToggle.js +8 -0
- package/dist/components/questions/_shared/components/compact/CompactExplanationToggle.d.ts +7 -0
- package/dist/components/questions/_shared/components/compact/CompactExplanationToggle.js +14 -0
- package/dist/components/questions/_shared/components/compact/CompactFieldCard.d.ts +9 -0
- package/dist/components/questions/_shared/components/compact/CompactFieldCard.js +7 -0
- package/dist/components/questions/_shared/components/compact/CompactPreviewBanner.d.ts +7 -0
- package/dist/components/questions/_shared/components/compact/CompactPreviewBanner.js +7 -0
- package/dist/components/questions/_shared/components/compact/CompactPreviewButton.d.ts +6 -0
- package/dist/components/questions/_shared/components/compact/CompactPreviewButton.js +7 -0
- package/dist/components/questions/_shared/components/compact/index.d.ts +6 -0
- package/dist/components/questions/_shared/components/compact/index.js +6 -0
- package/dist/components/questions/_shared/config/question-types.config.js +0 -24
- package/dist/components/questions/_shared/hooks/useQuestionInitialization.js +0 -9
- package/dist/components/questions/_shared/types/choose-the-correct-answer-group.type.d.ts +2 -2
- package/dist/components/questions/_shared/types/choose-the-correct-answer-group.type.js +5 -1
- package/dist/components/questions/_shared/types/index.d.ts +0 -1
- package/dist/components/questions/_shared/types/index.js +0 -1
- package/dist/components/questions/_shared/types/look-and-choose-answer.type.d.ts +0 -13
- package/dist/components/questions/_shared/utils/answer-builder.js +0 -11
- package/dist/components/questions/components/ColorRegionCreator.js +66 -63
- package/dist/components/questions/components/QuestionSearchDropdown.js +0 -8
- package/dist/components/questions/components/QuestionTypeSelector.js +0 -2
- package/dist/components/questions/components/index.d.ts +1 -0
- package/dist/components/questions/components/index.js +1 -0
- package/dist/components/questions/creator/question-type-registry.js +0 -8
- package/dist/components/questions/groups/ArticlesGroupCard.js +2 -2
- package/dist/components/questions/groups/BasicQuestionGroupCard.js +1 -1
- package/dist/components/questions/groups/DocumentGroupCard.js +1 -1
- package/dist/components/questions/groups/ImageLabelGroupCard.js +1 -1
- package/dist/components/questions/groups/MatchAnswerGroupCard.js +2 -2
- package/dist/components/questions/question-bank/QuestionEditorRenderer.d.ts +0 -3
- package/dist/components/questions/question-bank/QuestionEditorRenderer.js +1 -10
- package/dist/components/questions/question-bank/editor-adapters/choice-adapters.d.ts +0 -2
- package/dist/components/questions/question-bank/editor-adapters/choice-adapters.js +0 -41
- package/dist/components/questions/question-bank/editor-adapters/index.d.ts +2 -2
- package/dist/components/questions/question-bank/editor-adapters/index.js +2 -2
- package/dist/components/questions/question-bank/editor-adapters/media-adapters.d.ts +0 -1
- package/dist/components/questions/question-bank/editor-adapters/media-adapters.js +0 -28
- package/dist/components/questions/question-bank/question-bank-picker.utils.js +0 -7
- package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +16 -16
- package/dist/components/questions/types/answer-the-question/AnswerTheQuestionCreator.js +36 -30
- package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupClient.js +1 -1
- package/dist/components/questions/types/answer-the-question-group/AnswerTheQuestionGroupCreator.js +7 -6
- package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +2 -2
- package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsCreator.js +11 -7
- package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +1 -1
- package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js +11 -5
- package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +5 -5
- package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +34 -28
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseAnswerGroupImageUpload.d.ts +7 -0
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseAnswerGroupImageUpload.js +5 -2
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupClient.js +9 -5
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupCreator.js +65 -62
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupItemEditor.d.ts +6 -0
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupItemEditor.js +145 -0
- package/dist/components/questions/types/choose-the-correct-answer-group/map-choose-the-correct-answer-group-data.js +6 -15
- package/dist/components/questions/types/choose-the-correct-answer-group/transform.js +5 -4
- package/dist/components/questions/types/choose-then-answer-group/ChooseThenAnswerGroupClient.js +7 -7
- package/dist/components/questions/types/choose-then-answer-group/ChooseThenAnswerGroupCreator.js +8 -5
- package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupClient.js +2 -2
- package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupCreator.js +20 -16
- package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleClient.js +1 -1
- package/dist/components/questions/types/crossword-puzzle/CrosswordPuzzleCreator.js +66 -29
- package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +5 -5
- package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +45 -37
- package/dist/components/questions/types/fill-in-blank-group/FillInBlankGroupCreator.js +24 -20
- package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +2 -2
- package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridCreator.js +68 -65
- package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixClient.js +1 -1
- package/dist/components/questions/types/find-words-in-matrix/FindWordsInMatrixCreator.js +45 -5
- package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +2 -2
- package/dist/components/questions/types/label-the-picture/LabelThePictureCreator.js +18 -14
- package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +2 -2
- package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupCreator.js +30 -30
- package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneClient.js +2 -2
- package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneCreator.js +24 -31
- package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneClient.js +2 -2
- package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneCreator.js +29 -32
- package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +1 -1
- package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerCreator.js +27 -29
- package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +1 -1
- package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesCreator.js +11 -15
- package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +1 -1
- package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupCreator.js +22 -24
- package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +1 -1
- package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeCreator.js +17 -24
- package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +1 -1
- package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutCreator.js +31 -31
- package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +1 -1
- package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListCreator.js +11 -15
- package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +1 -1
- package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesCreator.js +14 -15
- package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +2 -2
- package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerCreator.js +27 -25
- package/dist/components/questions/types/match-columns-to-make-sentences/MatchColumnsToMakeSentencesClient.js +12 -12
- package/dist/components/questions/types/match-columns-to-make-sentences/MatchColumnsToMakeSentencesCreator.js +8 -5
- package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureClient.js +8 -8
- package/dist/components/questions/types/match-word-to-picture/MatchWordToPictureCreator.js +25 -20
- package/dist/components/questions/types/match-word-to-picture-group/MatchWordToPictureGroupClient.js +1 -1
- package/dist/components/questions/types/match-word-to-picture-group/MatchWordToPictureGroupCreator.js +13 -10
- package/dist/components/questions/types/matching-with-lines-group/MatchingWithLinesGroupCreator.js +8 -5
- package/dist/components/questions/types/read-displayed-content/ReadDisplayedContentCreator.js +7 -11
- package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +1 -1
- package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsCreator.js +15 -12
- package/dist/components/questions/types/sort-words-into-categories/SortWordsIntoCategoriesClient.js +1 -1
- package/dist/components/questions/types/sort-words-into-categories/SortWordsIntoCategoriesCreator.js +5 -5
- package/dist/components/questions/types/speaking-conversation/SpeakingConversationCreator.js +35 -39
- package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +2 -2
- package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardClient.js +1 -1
- package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +7 -8
- package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +1 -1
- package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageCreator.js +30 -23
- package/dist/components/questions/types/spontaneous-qa/SpontaneousQAClient.js +1 -1
- package/dist/components/questions/types/spontaneous-qa/SpontaneousQACreator.js +26 -19
- package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupClient.d.ts +1 -1
- package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupClient.js +79 -3
- package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupCreator.js +13 -11
- package/dist/components/questions/types/spontaneous-qa-group/index.d.ts +1 -0
- package/dist/components/questions/types/spontaneous-qa-group/index.js +1 -0
- package/dist/components/questions/types/spontaneous-qa-group/map-spontaneous-qa-group-data.d.ts +2 -0
- package/dist/components/questions/types/spontaneous-qa-group/map-spontaneous-qa-group-data.js +74 -0
- package/dist/components/questions/types/true-false/TrueFalseClient.js +2 -2
- package/dist/components/questions/types/true-false/TrueFalseCreator.js +35 -29
- package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupClient.js +1 -1
- package/dist/components/questions/types/true-false-correct-group/TrueFalseCorrectGroupCreator.js +11 -7
- package/dist/components/questions/types/true-false-group/TrueFalseGroupClient.js +1 -1
- package/dist/components/questions/types/true-false-group/TrueFalseGroupCreator.js +11 -7
- package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +2 -2
- package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphCreator.js +21 -56
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -1
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +30 -24
- package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupClient.js +3 -3
- package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupCreator.js +12 -14
- package/dist/components/questions/types/word-ordering/WordOrderingClient.js +1 -1
- package/dist/components/questions/types/word-ordering/WordOrderingCreator.js +27 -18
- package/dist/components/questions/types/word-ordering-group/WordOrderingGroupClient.js +7 -7
- package/dist/components/questions/types/word-ordering-group/WordOrderingGroupCreator.js +16 -13
- package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +2 -2
- package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +34 -28
- package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +2 -2
- package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js +22 -22
- package/dist/components/questions/types/write-sentences/WriteSentencesCreator.js +21 -18
- package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphClient.js +1 -1
- package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphCreator.js +7 -4
- package/dist/components/questions/viewer/QuestionViewer.js +0 -98
- package/dist/components/questions/viewer/SpontaneousQaGroupViewer.js +4 -79
- package/dist/components/results/renderers/review-question-body-movers.js +2 -26
- package/dist/components/results/review-data.js +0 -4
- package/dist/components/ui/points-input.d.ts +1 -0
- package/dist/components/ui/points-input.js +12 -2
- package/dist/shared/constants/question-skills.js +0 -11
- package/dist/shared/lib/i18n/messages/en/admin.d.ts +0 -3
- package/dist/shared/lib/i18n/messages/en/admin.js +0 -3
- package/dist/shared/lib/i18n/messages/en.d.ts +0 -3
- package/dist/shared/lib/i18n/messages/vi/admin.d.ts +0 -3
- package/dist/shared/lib/i18n/messages/vi/admin.js +0 -3
- package/dist/shared/lib/i18n/messages/vi.d.ts +0 -3
- package/dist/shared/lib/utils/question-reverse-transform.js +4 -23
- package/dist/shared/lib/utils/question-transform-types.d.ts +1 -23
- package/dist/shared/lib/utils/question-transform-validation.js +0 -40
- package/dist/shared/lib/utils/question-transform.js +0 -9
- package/dist/shared/types/common.types.d.ts +1 -1
- package/dist/shared/types/entities/question.types.d.ts +1 -11
- package/dist/shared/types/questions/choose-the-correct-answer-group.d.ts +1 -1
- package/dist/shared/types/questions/index.d.ts +0 -3
- package/dist/shared/types/questions/index.js +0 -6
- package/package.json +1 -1
- package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.d.ts +0 -2
- package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.js +0 -131
- package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.d.ts +0 -2
- package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.js +0 -76
- package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.d.ts +0 -2
- package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.js +0 -68
- package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.d.ts +0 -16
- package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.js +0 -212
- package/dist/components/questions/_shared/types/gn-speaking-interview.type.d.ts +0 -32
- package/dist/components/questions/_shared/types/gn-speaking-interview.type.js +0 -1
- package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.d.ts +0 -47
- package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.js +0 -1
- package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.d.ts +0 -2
- package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.js +0 -262
- package/dist/components/questions/types/gn-speaking-interview/register.d.ts +0 -2
- package/dist/components/questions/types/gn-speaking-interview/register.js +0 -121
- package/dist/components/questions/types/gn-speaking-interview/transform.d.ts +0 -2
- package/dist/components/questions/types/gn-speaking-interview/transform.js +0 -48
- package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.d.ts +0 -20
- package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.js +0 -72
- package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.d.ts +0 -15
- package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.js +0 -230
- package/dist/components/questions/types/look-picture-choose-correct-answer/index.d.ts +0 -1
- package/dist/components/questions/types/look-picture-choose-correct-answer/index.js +0 -1
- package/dist/components/questions/types/look-picture-choose-correct-answer/register.d.ts +0 -2
- package/dist/components/questions/types/look-picture-choose-correct-answer/register.js +0 -66
- package/dist/components/questions/types/look-picture-choose-correct-answer/transform.d.ts +0 -2
- package/dist/components/questions/types/look-picture-choose-correct-answer/transform.js +0 -42
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.d.ts +0 -6
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.js +0 -96
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.d.ts +0 -15
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.js +0 -238
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.d.ts +0 -2
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.js +0 -2
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.d.ts +0 -2
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.js +0 -76
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.d.ts +0 -2
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.js +0 -19
- package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.d.ts +0 -7
- package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.js +0 -134
- package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.d.ts +0 -3
- package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.js +0 -617
- package/dist/components/questions/types/look-picture-fill-word-hint/index.d.ts +0 -2
- package/dist/components/questions/types/look-picture-fill-word-hint/index.js +0 -2
- package/dist/components/questions/types/look-picture-fill-word-hint/register.d.ts +0 -2
- package/dist/components/questions/types/look-picture-fill-word-hint/register.js +0 -82
- package/dist/components/questions/types/look-picture-fill-word-hint/transform.d.ts +0 -2
- package/dist/components/questions/types/look-picture-fill-word-hint/transform.js +0 -29
- package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.d.ts +0 -9
- package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.js +0 -12
- package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.d.ts +0 -17
- package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.js +0 -47
- package/dist/shared/types/questions/look-picture-choose-correct-answer.d.ts +0 -38
- package/dist/shared/types/questions/look-picture-choose-correct-answer.js +0 -5
- package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.d.ts +0 -63
- package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.js +0 -9
- package/dist/shared/types/questions/look-picture-fill-word-hint.d.ts +0 -57
- package/dist/shared/types/questions/look-picture-fill-word-hint.js +0 -7
package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useRef, useEffect } from 'react';
|
|
4
|
-
import { Button } from '../../../../components/ui/button';
|
|
5
4
|
import { Label } from '../../../../components/ui/label';
|
|
6
5
|
import { Input } from '../../../../components/ui/input';
|
|
7
|
-
import { Textarea } from '../../../../components/ui/textarea';
|
|
8
|
-
import { PointsInput } from '../../../../components/ui/points-input';
|
|
9
|
-
import { Card, CardContent, CardHeader, CardTitle } from '../../../../components/ui/card';
|
|
10
6
|
import { Switch } from '../../../../components/ui/switch';
|
|
11
|
-
import {
|
|
7
|
+
import { Eye, PenTool, MessageSquare, ToggleLeft, CheckCircle2 } from 'lucide-react';
|
|
8
|
+
import { CompactCreatorHeader, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, } from '../../_shared/components/compact';
|
|
12
9
|
import { WriteCorrectVerbFormClient } from './WriteCorrectVerbFormClient';
|
|
13
10
|
import { useDebouncedCallback } from '../../../../shared/lib/hooks';
|
|
14
11
|
function WriteCorrectVerbFormCreatorContent({ initialData, onSave, onCancel, onChange, externalErrors, onUnsavedChangesChange, validationRef, }) {
|
|
@@ -171,25 +168,28 @@ function WriteCorrectVerbFormCreatorContent({ initialData, onSave, onCancel, onC
|
|
|
171
168
|
caseSensitive,
|
|
172
169
|
instruction,
|
|
173
170
|
};
|
|
174
|
-
return (_jsxs("div", { className: "space-y-
|
|
171
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsx(CompactPreviewBanner, { onBack: () => setIsClientMode(false) }), _jsx(WriteCorrectVerbFormClient, { questionData: { ...questionData, explanation }, isReviewMode: true, userAnswer: correctAnswer })] }));
|
|
175
172
|
}
|
|
176
173
|
// ============ CREATOR UI ============
|
|
177
|
-
return (
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
174
|
+
return (_jsx("div", { className: "space-y-3", children: _jsxs(CompactFieldCard, { header: _jsx(CompactCreatorHeader, { icon: _jsx(PenTool, { className: "h-3.5 w-3.5" }), title: "Vi\u1EBFt d\u1EA1ng \u0111\u00FAng c\u1EE7a \u0111\u1ED9ng t\u1EEB", points: { value: points, onValueChange: setPoints }, preview: {
|
|
175
|
+
onClick: () => setIsClientMode(true),
|
|
176
|
+
disabled: !isValid(),
|
|
177
|
+
} }), children: [_jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { className: "flex items-center gap-1.5 text-sm font-semibold text-gray-800", children: [_jsx(MessageSquare, { className: "h-3.5 w-3.5 text-amber-500" }), "C\u00E2u h\u1ECFi ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { value: sentence, onChange: (e) => {
|
|
178
|
+
setSentence(e.target.value);
|
|
179
|
+
if (validationErrors.sentence) {
|
|
180
|
+
setValidationErrors(prev => ({ ...prev, sentence: undefined }));
|
|
181
|
+
}
|
|
182
|
+
}, placeholder: "V\u00ED d\u1EE5: John {0} his homework at night.", className: `h-8 border-gray-200 bg-white ${validationErrors.sentence ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` }), validationErrors.sentence && (_jsx("p", { className: "text-sm text-red-600", children: validationErrors.sentence }))] }), _jsxs("div", { className: "grid grid-cols-2 gap-2.5", children: [_jsxs("div", { className: `rounded-md border p-2.5 ${verbHint ? 'border-amber-200 bg-amber-50/70' : 'border-gray-200 bg-white'}`, children: [_jsxs(Label, { className: "flex items-center gap-1.5 text-xs font-semibold text-gray-700", children: [_jsx("span", { className: "flex h-5 w-5 items-center justify-center rounded-md bg-amber-100 text-[10px] font-bold text-amber-600", children: "V" }), "G\u1EE3i \u00FD \u0111\u1ED9ng t\u1EEB ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { value: verbHint, onChange: (e) => {
|
|
183
|
+
setVerbHint(e.target.value);
|
|
184
|
+
if (validationErrors.verbHint) {
|
|
185
|
+
setValidationErrors(prev => ({ ...prev, verbHint: undefined }));
|
|
186
|
+
}
|
|
187
|
+
}, placeholder: "V\u00ED d\u1EE5: do", className: `mt-1.5 h-8 border-gray-200 bg-white ${validationErrors.verbHint ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` }), validationErrors.verbHint && (_jsx("p", { className: "mt-1 text-sm text-red-600", children: validationErrors.verbHint }))] }), _jsxs("div", { className: `rounded-md border p-2.5 ${correctAnswer ? 'border-green-200 bg-green-50/70' : 'border-gray-200 bg-white'}`, children: [_jsxs(Label, { className: "flex items-center gap-1.5 text-xs font-semibold text-gray-700", children: [_jsx(CheckCircle2, { className: "h-3.5 w-3.5 text-green-600" }), "\u0110\u00E1p \u00E1n \u0111\u00FAng ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { value: correctAnswer, onChange: (e) => {
|
|
188
|
+
setCorrectAnswer(e.target.value);
|
|
189
|
+
if (validationErrors.correctAnswer) {
|
|
190
|
+
setValidationErrors(prev => ({ ...prev, correctAnswer: undefined }));
|
|
191
|
+
}
|
|
192
|
+
}, placeholder: "V\u00ED d\u1EE5: does", className: `mt-1.5 h-8 border-gray-200 bg-white ${validationErrors.correctAnswer ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` }), validationErrors.correctAnswer && (_jsx("p", { className: "mt-1 text-sm text-red-600", children: validationErrors.correctAnswer }))] })] }), _jsxs("div", { className: "flex items-center justify-between rounded-md border border-gray-200 bg-white px-2.5 py-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-md bg-gray-100", children: _jsx(ToggleLeft, { className: "h-3.5 w-3.5 text-gray-600" }) }), _jsxs("div", { children: [_jsx(Label, { htmlFor: "caseSensitive", className: "text-sm font-semibold text-gray-800", children: "Ph\u00E2n bi\u1EC7t ch\u1EEF hoa/th\u01B0\u1EDDng" }), _jsx("p", { className: "text-xs text-gray-500", children: "B\u1EADt n\u1EBFu \u0111\u00E1p \u00E1n c\u1EA7n kh\u1EDBp ch\u00EDnh x\u00E1c (v\u00ED d\u1EE5: \"Does\" \u2260 \"does\")" })] })] }), _jsx(Switch, { id: "caseSensitive", checked: caseSensitive, onCheckedChange: setCaseSensitive })] }), sentence && verbHint && (_jsxs("div", { className: "rounded-md border border-gray-200 bg-gray-50 p-2.5", children: [_jsxs("div", { className: "mb-1 flex items-center gap-1.5 text-xs font-semibold text-gray-600", children: [_jsx(Eye, { className: "h-3.5 w-3.5" }), "Xem tr\u01B0\u1EDBc c\u00E2u h\u1ECFi"] }), _jsxs("p", { className: "text-sm text-gray-700", children: [sentence.replace('{0}', '_______'), " ", _jsxs("span", { className: "font-semibold text-amber-600", children: ["(", verbHint, ")"] })] }), correctAnswer && (_jsxs("div", { className: "mt-1.5 flex items-center gap-1.5 rounded-md bg-green-50 px-2.5 py-1.5", children: [_jsx(CheckCircle2, { className: "h-3.5 w-3.5 text-green-500" }), _jsxs("span", { className: "text-xs text-green-700", children: ["\u0110\u00E1p \u00E1n: ", _jsx("strong", { children: sentence.replace('{0}', correctAnswer) })] })] }))] })), externalErrors && externalErrors.length > 0 && (_jsxs("div", { className: "flex items-center gap-2 rounded-md border border-red-200 bg-red-50 p-2 text-xs text-red-700", children: [_jsx("span", { className: "font-semibold text-red-800", children: "L\u1ED7i:" }), _jsx("span", { children: externalErrors.join(' · ') })] })), _jsx(CompactExplanationToggle, { value: explanation, onValueChange: setExplanation, defaultVisible: Boolean(initialData?.explanation) })] }) }));
|
|
193
193
|
}
|
|
194
194
|
export function WriteCorrectVerbFormCreator(props) {
|
|
195
195
|
return _jsx(WriteCorrectVerbFormCreatorContent, { ...props });
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useRef, useEffect } from 'react';
|
|
4
|
-
import { Button } from '../../../../components/ui/button';
|
|
5
4
|
import { Input } from '../../../../components/ui/input';
|
|
6
5
|
import { Label } from '../../../../components/ui/label';
|
|
7
6
|
import { Textarea } from '../../../../components/ui/textarea';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { Pencil, Eye, PenLine, BookOpen, Hash } from 'lucide-react';
|
|
7
|
+
import { PenLine, BookOpen, Hash } from 'lucide-react';
|
|
8
|
+
import { CompactCreatorHeader, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, } from '../../_shared/components/compact';
|
|
11
9
|
import { WriteSentencesClient } from './WriteSentencesClient';
|
|
12
10
|
import { useDebouncedCallback } from '../../../../shared/lib/hooks';
|
|
13
11
|
import { BasicQuestionGroupCard } from '../../groups/BasicQuestionGroupCard';
|
|
@@ -152,22 +150,27 @@ function WriteSentencesCreatorContent({ initialData, onChange, externalErrors, v
|
|
|
152
150
|
instruction,
|
|
153
151
|
sentenceCount,
|
|
154
152
|
};
|
|
155
|
-
return (_jsxs("div", { className: "space-y-
|
|
153
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsx(CompactPreviewBanner, { onBack: () => setIsClientMode(false) }), _jsx(WriteSentencesClient, { questionData: questionData, onSubmit: () => { }, isReviewMode: true, explanation: explanation })] }));
|
|
156
154
|
}
|
|
157
155
|
// Creator UI
|
|
158
|
-
return (_jsxs("div", { className: "space-y-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
156
|
+
return (_jsxs("div", { className: "space-y-3", children: [isGrouped && (_jsx(BasicQuestionGroupCard, { groupNumber: currentGroupNumber, title: groupTitle, subtitle: groupSubtitle, content: groupContent, imageUrl: imageUrl, onTitleChange: setGroupTitle, onSubtitleChange: setGroupSubtitle, onContentChange: setGroupContent, onImageChange: setImageUrl, uploadIdPrefix: `write-sentences-${partId ?? 'group'}` })), _jsxs(CompactFieldCard, { header: _jsx(CompactCreatorHeader, { icon: _jsx(PenLine, { className: "h-3.5 w-3.5" }), title: "Vi\u1EBFt c\u00E2u", points: {
|
|
157
|
+
value: points,
|
|
158
|
+
onValueChange: setPoints,
|
|
159
|
+
}, preview: {
|
|
160
|
+
onClick: () => setIsClientMode(true),
|
|
161
|
+
} }), children: [_jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { htmlFor: "sentenceCount", className: "flex items-center gap-1.5 text-sm font-semibold text-gray-800", children: [_jsx(Hash, { className: "h-3.5 w-3.5 text-teal-500" }), "S\u1ED1 c\u00E2u c\u1EA7n vi\u1EBFt ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { id: "sentenceCount", type: "number", min: 1, max: 10, value: sentenceCount ?? '', onChange: (e) => {
|
|
162
|
+
const raw = e.target.value;
|
|
163
|
+
if (raw === '') {
|
|
164
|
+
setSentenceCount(undefined);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
const val = parseInt(raw, 10);
|
|
168
|
+
setSentenceCount(isNaN(val) ? undefined : Math.max(1, val));
|
|
169
|
+
}
|
|
170
|
+
if (validationErrors.sentenceCount) {
|
|
171
|
+
setValidationErrors((prev) => ({ ...prev, sentenceCount: undefined }));
|
|
172
|
+
}
|
|
173
|
+
}, placeholder: "Nh\u1EADp s\u1ED1 c\u00E2u...", className: `mt-1.5 border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-200 ${validationErrors.sentenceCount ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}` }), validationErrors.sentenceCount && (_jsx("p", { className: "mt-1 text-sm text-red-600", children: validationErrors.sentenceCount }))] }), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { htmlFor: "instruction", className: "flex items-center gap-1.5 text-sm font-semibold text-gray-800", children: [_jsx(BookOpen, { className: "h-3.5 w-3.5 text-teal-500" }), "H\u01B0\u1EDBng d\u1EABn ", _jsx("span", { className: "text-xs font-normal text-gray-500", children: "(T\u00F9y ch\u1ECDn)" })] }), _jsx(Textarea, { id: "instruction", value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: "V\u00ED d\u1EE5: Now write two sentences about the picture.", rows: 2, className: "border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-200" })] }), externalErrors && externalErrors.length > 0 && (_jsxs("div", { className: "flex items-center gap-2 rounded-md border border-red-200 bg-red-50 p-2 text-xs text-red-700", children: [_jsx("span", { className: "font-semibold text-red-800", children: "L\u1ED7i:" }), _jsx("span", { children: externalErrors.join(' · ') })] }))] }), _jsx(CompactExplanationToggle, { value: explanation, onValueChange: setExplanation })] }));
|
|
171
174
|
}
|
|
172
175
|
export function WriteSentencesCreator(props) {
|
|
173
176
|
return _jsx(WriteSentencesCreatorContent, { ...props });
|
|
@@ -62,7 +62,7 @@ export function WriteShortParagraphClient({ questionData, onSubmit, isReviewMode
|
|
|
62
62
|
return 'Text';
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
|
-
return (_jsxs("div", { className: "space-y-
|
|
65
|
+
return (_jsxs("div", { className: "space-y-3", children: [instruction && (_jsx(Card, { className: "border-0 shadow-sm", children: _jsx(CardHeader, { className: "px-3 py-2", children: _jsx(CardTitle, { className: "text-sm", children: instruction }) }) })), contexts.length > 0 && (_jsxs(Card, { className: "border-0 shadow-sm", children: [_jsx(CardHeader, { className: "px-3 py-2", children: _jsx(CardTitle, { className: "text-sm", children: "Contexts" }) }), _jsx(CardContent, { className: "p-3 space-y-3", children: _jsx("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3", children: contexts.map((ctx, index) => (_jsx(ContextDisplay, { context: ctx, index: index }, ctx.id))) }) })] })), _jsxs(Card, { className: "border-0 shadow-sm", children: [_jsx(CardHeader, { className: "px-3 py-2", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx(CardTitle, { className: "text-sm", children: "Vi\u1EBFt b\u00E0i" }), _jsx("div", { className: "flex items-center gap-2", children: _jsxs("span", { className: `text-sm font-semibold ${isValidWordCount ? 'text-green-600' : 'text-red-600'}`, children: [wordCount, " / ", minWords, maxWords ? ` - ${maxWords}` : '+', " t\u1EEB"] }) })] }) }), _jsxs(CardContent, { className: "space-y-3 p-3", children: [_jsxs("div", { children: [_jsx(Label, { htmlFor: "writing-answer", children: "N\u1ED9i dung b\u00E0i vi\u1EBFt" }), _jsx(Textarea, { id: "writing-answer", value: answer, onChange: (e) => handleAnswerChange(e.target.value), placeholder: "Nh\u1EADp n\u1ED9i dung b\u00E0i vi\u1EBFt c\u1EE7a b\u1EA1n...", className: "mt-2 min-h-[200px]", rows: 10, disabled: isReviewMode })] }), !isReviewMode && (_jsx("div", { className: "flex items-start gap-2 rounded-lg border p-3", children: isValidWordCount ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "mt-0.5 h-5 w-5 rounded-full bg-green-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("p", { className: "text-sm font-medium text-green-700", children: "\u0110\u00E3 \u0111\u1EE7 s\u1ED1 t\u1EEB y\u00EAu c\u1EA7u" }), _jsxs("p", { className: "text-xs text-green-600", children: ["B\u1EA1n \u0111\u00E3 vi\u1EBFt ", wordCount, " t\u1EEB. Y\u00EAu c\u1EA7u: ", minWords, maxWords ? ` - ${maxWords}` : '+', " t\u1EEB."] })] })] })) : (_jsxs(_Fragment, { children: [_jsx(AlertCircle, { className: "h-5 w-5 text-amber-500" }), _jsxs("div", { className: "flex-1", children: [_jsx("p", { className: "text-sm font-medium text-amber-700", children: "Ch\u01B0a \u0111\u1EE7 s\u1ED1 t\u1EEB y\u00EAu c\u1EA7u" }), _jsxs("p", { className: "text-xs text-amber-600", children: ["B\u1EA1n \u0111\u00E3 vi\u1EBFt ", wordCount, " t\u1EEB. C\u1EA7n \u00EDt nh\u1EA5t ", minWords, " t\u1EEB.", maxWords && wordCount > maxWords && _jsxs("span", { children: [" T\u1ED1i \u0111a ", maxWords, " t\u1EEB."] })] })] })] })) }))] })] })] }));
|
|
66
66
|
}
|
|
67
67
|
function ContextDisplay({ context, index }) {
|
|
68
68
|
const { previewUrl } = usePresignedFileUrl(context.type !== 'text' ? context.url || '' : '');
|
|
@@ -5,8 +5,8 @@ import { Button } from '../../../../components/ui/button';
|
|
|
5
5
|
import { Label } from '../../../../components/ui/label';
|
|
6
6
|
import { Input } from '../../../../components/ui/input';
|
|
7
7
|
import { Textarea } from '../../../../components/ui/textarea';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { X, Image, Music, FileText } from 'lucide-react';
|
|
9
|
+
import { CompactCreatorHeader, CompactFieldCard, CompactPreviewBanner, } from '../../_shared/components/compact';
|
|
10
10
|
import { FileUpload } from '../../../../components/ui/file-upload';
|
|
11
11
|
import { WriteShortParagraphClient } from './WriteShortParagraphClient';
|
|
12
12
|
import { usePresignedFileUrl } from '../../../../shared/lib/hooks';
|
|
@@ -113,9 +113,12 @@ onChange, }) {
|
|
|
113
113
|
maxWords,
|
|
114
114
|
instruction,
|
|
115
115
|
};
|
|
116
|
-
return (_jsxs("div", { className: "space-y-
|
|
116
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsx(CompactPreviewBanner, { onBack: () => setIsClientMode(false) }), _jsx(WriteShortParagraphClient, { questionData: questionData, onSubmit: () => { } })] }));
|
|
117
117
|
}
|
|
118
|
-
return (_jsxs("div", { className: "space-y-
|
|
118
|
+
return (_jsxs("div", { className: "space-y-3", children: [_jsxs(CompactFieldCard, { header: _jsx(CompactCreatorHeader, { icon: _jsx(FileText, { className: "h-3.5 w-3.5" }), title: "Write Short Paragraph", preview: {
|
|
119
|
+
onClick: () => setIsClientMode(true),
|
|
120
|
+
disabled: contexts.length === 0 || minWords < 1,
|
|
121
|
+
} }), children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "instruction", className: "text-sm font-semibold text-gray-700", children: "H\u01B0\u1EDBng d\u1EABn" }), _jsx(Textarea, { id: "instruction", value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: "V\u00ED d\u1EE5: Look at the three pictures. Write about this story.", className: "mt-1", rows: 2 })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "minWords", className: "text-sm font-semibold text-gray-700", children: "S\u1ED1 t\u1EEB t\u1ED1i thi\u1EC3u *" }), _jsx(Input, { id: "minWords", type: "number", min: "1", value: minWords, onChange: (e) => setMinWords(parseInt(e.target.value) || 1), placeholder: "20", className: "mt-1" })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { htmlFor: "maxWords", className: "text-sm font-semibold text-gray-700", children: "S\u1ED1 t\u1EEB t\u1ED1i \u0111a (t\u00F9y ch\u1ECDn)" }), _jsx(Input, { id: "maxWords", type: "number", min: minWords, value: maxWords || '', onChange: (e) => setMaxWords(e.target.value ? parseInt(e.target.value) : undefined), placeholder: "Kh\u00F4ng gi\u1EDBi h\u1EA1n", className: "mt-1" })] })] })] }), _jsx(CompactFieldCard, { header: _jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-md bg-gray-100", children: _jsx(FileText, { className: "h-3.5 w-3.5 text-gray-600" }) }), _jsx("span", { className: "text-sm font-bold text-gray-900", children: "Contexts" })] }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: () => addContext('image'), className: "flex items-center gap-2 border-indigo-200 bg-indigo-50 text-indigo-700 hover:bg-indigo-100 hover:text-indigo-800", children: [_jsx(Image, { className: "h-4 w-4" }), "Th\u00EAm \u1EA3nh"] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => addContext('audio'), className: "flex items-center gap-2 border-purple-200 bg-purple-50 text-purple-700 hover:bg-purple-100 hover:text-purple-800", children: [_jsx(Music, { className: "h-4 w-4" }), "Th\u00EAm audio"] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => addContext('text'), className: "flex items-center gap-2 border-blue-200 bg-blue-50 text-blue-700 hover:bg-blue-100 hover:text-blue-800", children: [_jsx(FileText, { className: "h-4 w-4" }), "Th\u00EAm text"] })] })] }), children: contexts.length > 0 ? (contexts.map((ctx, index) => (_jsx(ContextItem, { context: ctx, index: index, onUpdate: updateContext, onRemove: removeContext }, ctx.id)))) : (_jsxs("div", { className: "flex flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50 p-12", children: [_jsx("div", { className: "mb-4 rounded-full bg-gray-200 p-4", children: _jsx(Image, { className: "h-8 w-8 text-gray-400" }) }), _jsx("p", { className: "mb-2 text-sm font-medium text-gray-700", children: "Ch\u01B0a c\u00F3 context n\u00E0o" }), _jsx("p", { className: "mb-4 text-xs text-gray-500", children: "Nh\u1EA5n c\u00E1c n\u00FAt b\u00EAn tr\u00EAn \u0111\u1EC3 th\u00EAm context" })] })) })] }));
|
|
119
122
|
}
|
|
120
123
|
function ContextItem({ context, index, onUpdate, onRemove }) {
|
|
121
124
|
const { previewUrl } = usePresignedFileUrl(context.type !== 'text' ? context.url || '' : '');
|
|
@@ -11,12 +11,9 @@ import { ReadAndColorObjectsClient } from '../types/read-and-color-objects/ReadA
|
|
|
11
11
|
import { ArrangeLettersIntoWordsClient } from '../types/arrange-letters-into-words/ArrangeLettersIntoWordsClient';
|
|
12
12
|
import { WriteShortParagraphClient } from '../types/write-short-paragraph/WriteShortParagraphClient';
|
|
13
13
|
import { LabelThePictureClient } from '../types/label-the-picture/LabelThePictureClient';
|
|
14
|
-
import { LookPictureFillWordHintClient } from '../types/look-picture-fill-word-hint/LookPictureFillWordHintClient';
|
|
15
14
|
import { ReadPassageAndAnswerQuestionsClient } from '../types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient';
|
|
16
15
|
import { ChooseTheCorrectAnswerClient } from '../types/choose-the-correct-answer/ChooseTheCorrectAnswerClient';
|
|
17
16
|
import { WriteAShortLetterClient } from '../types/write-a-short-letter/WriteAShortLetterClient';
|
|
18
|
-
import { LookPictureChooseCorrectAnswerClient } from '../types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient';
|
|
19
|
-
import { LookPictureFillBlankChooseAnswerClient } from '../types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient';
|
|
20
17
|
import { FillMissingWordsInGridClient } from '../types/fill-missing-words-in-grid/FillMissingWordsInGridClient';
|
|
21
18
|
import { CrosswordPuzzleClient } from '../types/crossword-puzzle/CrosswordPuzzleClient';
|
|
22
19
|
import { FindWordsInMatrixClient } from '../types/find-words-in-matrix/FindWordsInMatrixClient';
|
|
@@ -393,50 +390,6 @@ export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false,
|
|
|
393
390
|
onSubmitAnswer?.(userConnections);
|
|
394
391
|
} }));
|
|
395
392
|
};
|
|
396
|
-
const renderLookPictureFillWordHint = () => {
|
|
397
|
-
const answer = question.answer;
|
|
398
|
-
const content = question.content;
|
|
399
|
-
// Check if question has group info (from API)
|
|
400
|
-
const questionGroup = question.questionGroup;
|
|
401
|
-
let subQuestions = [];
|
|
402
|
-
if (answer?.subQuestions && answer.subQuestions.length > 0) {
|
|
403
|
-
subQuestions = answer.subQuestions;
|
|
404
|
-
}
|
|
405
|
-
else if (content?.imageUrl && content?.word) {
|
|
406
|
-
// Single question format - transform to subQuestions
|
|
407
|
-
subQuestions = [{
|
|
408
|
-
id: question.id,
|
|
409
|
-
imageUrl: content.imageUrl,
|
|
410
|
-
word: content.word,
|
|
411
|
-
correctAnswer: answer?.correctAnswer || '',
|
|
412
|
-
groupNumber: questionGroup?.groupNumber || 1,
|
|
413
|
-
}];
|
|
414
|
-
}
|
|
415
|
-
// Get hintLetters from multiple sources (priority order):
|
|
416
|
-
// 1. questionGroup.payload.hintLetters (from API group payload)
|
|
417
|
-
// 2. answer.hintLetters
|
|
418
|
-
// 3. content.hintLetters
|
|
419
|
-
const hintLetters = questionGroup?.payload?.hintLetters ||
|
|
420
|
-
answer?.hintLetters ||
|
|
421
|
-
content?.hintLetters ||
|
|
422
|
-
[];
|
|
423
|
-
// Build hintLettersByGroup if we have a groupNumber
|
|
424
|
-
const groupNumber = questionGroup?.groupNumber || 1;
|
|
425
|
-
const hintLettersByGroup = {};
|
|
426
|
-
if (hintLetters.length > 0) {
|
|
427
|
-
hintLettersByGroup[groupNumber] = hintLetters;
|
|
428
|
-
}
|
|
429
|
-
const questionData = {
|
|
430
|
-
subQuestions,
|
|
431
|
-
hintLetters,
|
|
432
|
-
hintLettersByGroup,
|
|
433
|
-
groups: [{ number: groupNumber, questionCount: subQuestions.length }],
|
|
434
|
-
};
|
|
435
|
-
return (_jsx(LookPictureFillWordHintClient, { questionData: questionData, userAnswer: userAnswer, isReviewMode: isReviewMode, explanation: question.explanation, onSubmit: (answers) => {
|
|
436
|
-
setSelectedAnswer(answers);
|
|
437
|
-
onSubmitAnswer?.(answers);
|
|
438
|
-
} }));
|
|
439
|
-
};
|
|
440
393
|
const renderReadPassageAndAnswerQuestions = () => {
|
|
441
394
|
const answer = question.answer;
|
|
442
395
|
const questionData = {
|
|
@@ -450,50 +403,6 @@ export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false,
|
|
|
450
403
|
onSubmitAnswer?.(answers);
|
|
451
404
|
} }));
|
|
452
405
|
};
|
|
453
|
-
const renderLookPictureChooseCorrectAnswer = () => {
|
|
454
|
-
const content = question.content;
|
|
455
|
-
const answer = question.answer;
|
|
456
|
-
// Merge correct answers into subQuestions
|
|
457
|
-
const subQuestions = (content?.subQuestions || answer?.subQuestions || []).map((sq) => {
|
|
458
|
-
const correctAnswerId = answer?.answers?.[sq.id] || sq.correctAnswer;
|
|
459
|
-
return {
|
|
460
|
-
...sq,
|
|
461
|
-
options: (sq.options || []).map((opt) => ({
|
|
462
|
-
...opt,
|
|
463
|
-
isCorrect: opt.id === correctAnswerId,
|
|
464
|
-
})),
|
|
465
|
-
};
|
|
466
|
-
});
|
|
467
|
-
const questionData = {
|
|
468
|
-
subQuestions,
|
|
469
|
-
};
|
|
470
|
-
return (_jsx(LookPictureChooseCorrectAnswerClient, { questionData: questionData, userAnswer: userAnswer, isReviewMode: isReviewMode, onSubmit: (answers) => {
|
|
471
|
-
setSelectedAnswer(answers);
|
|
472
|
-
onSubmitAnswer?.(answers);
|
|
473
|
-
} }));
|
|
474
|
-
};
|
|
475
|
-
const renderLookPictureFillBlankChooseAnswer = () => {
|
|
476
|
-
const content = question.content;
|
|
477
|
-
const answer = question.answer;
|
|
478
|
-
// Merge correct answers into subQuestions
|
|
479
|
-
const subQuestions = (content?.subQuestions || answer?.subQuestions || []).map((sq) => {
|
|
480
|
-
const correctAnswerId = answer?.answers?.[sq.id] || sq.correctAnswer;
|
|
481
|
-
return {
|
|
482
|
-
...sq,
|
|
483
|
-
options: (sq.options || []).map((opt) => ({
|
|
484
|
-
...opt,
|
|
485
|
-
isCorrect: opt.id === correctAnswerId,
|
|
486
|
-
})),
|
|
487
|
-
};
|
|
488
|
-
});
|
|
489
|
-
const questionData = {
|
|
490
|
-
subQuestions,
|
|
491
|
-
};
|
|
492
|
-
return (_jsx(LookPictureFillBlankChooseAnswerClient, { questionData: questionData, userAnswer: userAnswer, isReviewMode: isReviewMode, onSubmit: (answers) => {
|
|
493
|
-
setSelectedAnswer(answers);
|
|
494
|
-
onSubmitAnswer?.(answers);
|
|
495
|
-
} }));
|
|
496
|
-
};
|
|
497
406
|
const renderFillMissingWordsInGrid = () => {
|
|
498
407
|
const content = question.content;
|
|
499
408
|
const answer = question.answer;
|
|
@@ -629,19 +538,12 @@ export function QuestionViewer({ question, onSubmitAnswer, isReviewMode = false,
|
|
|
629
538
|
case 'WRITE_A_SHORT_LETTER':
|
|
630
539
|
return renderWriteAShortLetter();
|
|
631
540
|
// Marketing exam questions grade 1-2
|
|
632
|
-
case 'LOOK_PICTURE_FILL_WORD_HINT':
|
|
633
|
-
return renderLookPictureFillWordHint();
|
|
634
541
|
case 'LABEL_THE_PICTURE':
|
|
635
542
|
return renderLabelThePicture();
|
|
636
543
|
case 'READ_AND_COLOR_OBJECTS':
|
|
637
544
|
return renderReadAndColorObjects();
|
|
638
545
|
case 'READ_PASSAGE_AND_ANSWER_QUESTIONS':
|
|
639
546
|
return renderReadPassageAndAnswerQuestions();
|
|
640
|
-
// Additional marketing exam questions
|
|
641
|
-
case 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER':
|
|
642
|
-
return renderLookPictureChooseCorrectAnswer();
|
|
643
|
-
case 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER':
|
|
644
|
-
return renderLookPictureFillBlankChooseAnswer();
|
|
645
547
|
case 'FILL_MISSING_WORDS_IN_GRID':
|
|
646
548
|
return renderFillMissingWordsInGrid();
|
|
647
549
|
case 'WORD_FILL_PARAGRAPH':
|
|
@@ -1,82 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
function asRecord(value) {
|
|
7
|
-
return isRecord(value) ? value : {};
|
|
8
|
-
}
|
|
9
|
-
function asString(value, fallback = '') {
|
|
10
|
-
return typeof value === 'string' ? value : fallback;
|
|
11
|
-
}
|
|
12
|
-
function mapItem(item, index) {
|
|
13
|
-
const record = asRecord(item);
|
|
14
|
-
const content = asRecord(record.content);
|
|
15
|
-
const correctAnswer = asRecord(record.correctAnswer);
|
|
16
|
-
const expected = Array.isArray(correctAnswer.expectedAnswers)
|
|
17
|
-
? correctAnswer.expectedAnswers.map((value) => String(value ?? ''))
|
|
18
|
-
: [];
|
|
19
|
-
return {
|
|
20
|
-
questionText: asString(content.questionText) ||
|
|
21
|
-
asString(content.question) ||
|
|
22
|
-
asString(record.questionText),
|
|
23
|
-
audioUrl: asString(content.audioUrl) || undefined,
|
|
24
|
-
expectedAnswers: expected,
|
|
25
|
-
isExample: record.isExample === true,
|
|
26
|
-
points: typeof record.points === 'number' ? record.points : 1,
|
|
27
|
-
questionNumber: typeof record.questionNumber === 'number' ? record.questionNumber : index + 1,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
function isNestedPart(item) {
|
|
31
|
-
const record = asRecord(item);
|
|
32
|
-
return Array.isArray(record.questions);
|
|
33
|
-
}
|
|
34
|
-
function resolveGroup(question) {
|
|
35
|
-
const content = asRecord(question.content);
|
|
36
|
-
const list = asRecord(question.spontaneousQAList ?? content.spontaneousQAList ?? content);
|
|
37
|
-
const itemsRaw = Array.isArray(list.items)
|
|
38
|
-
? list.items
|
|
39
|
-
: Array.isArray(content.items)
|
|
40
|
-
? content.items
|
|
41
|
-
: [];
|
|
42
|
-
const instruction = asString(asRecord(list.meta).instruction) ||
|
|
43
|
-
asString(asRecord(content.meta).instruction) ||
|
|
44
|
-
asString(question.explanation) ||
|
|
45
|
-
'Talk about the topic.';
|
|
46
|
-
if (itemsRaw.some(isNestedPart)) {
|
|
47
|
-
return {
|
|
48
|
-
instruction,
|
|
49
|
-
parts: itemsRaw.map((item, index) => {
|
|
50
|
-
const record = asRecord(item);
|
|
51
|
-
const questions = Array.isArray(record.questions)
|
|
52
|
-
? record.questions.map(mapItem)
|
|
53
|
-
: [];
|
|
54
|
-
return {
|
|
55
|
-
partNumber: typeof record.partNumber === 'number' ? record.partNumber : index + 1,
|
|
56
|
-
partTitle: asString(record.partTitle) || `PART ${index + 1}`,
|
|
57
|
-
topic: asString(record.topic),
|
|
58
|
-
questions,
|
|
59
|
-
};
|
|
60
|
-
}),
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
return {
|
|
64
|
-
instruction,
|
|
65
|
-
parts: [
|
|
66
|
-
{
|
|
67
|
-
partNumber: 1,
|
|
68
|
-
partTitle: '',
|
|
69
|
-
topic: '',
|
|
70
|
-
questions: itemsRaw.map(mapItem),
|
|
71
|
-
},
|
|
72
|
-
],
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
function QaPromptCard({ item, index, isReviewMode = false, }) {
|
|
76
|
-
return (_jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm", children: [_jsxs("div", { className: "flex items-center justify-between border-b border-gray-100 bg-gray-50 px-4 py-2.5", children: [_jsxs("span", { className: "text-sm font-medium text-gray-700", children: ["C\u00E2u ", item.questionNumber || index + 1] }), _jsxs("span", { className: "text-xs text-gray-500", children: [item.points || 0, " \u0111i\u1EC3m"] })] }), _jsxs("div", { className: "space-y-2 p-4", children: [_jsx("p", { className: "text-sm font-semibold text-gray-800", children: item.questionText || 'Câu hỏi chưa được nhập' }), item.audioUrl ? (_jsxs("p", { className: "text-xs text-gray-500", children: ["Audio: ", item.audioUrl] })) : null, isReviewMode && item.expectedAnswers.length > 0 ? (_jsxs("div", { className: "rounded-lg border border-emerald-100 bg-emerald-50 px-3 py-2 text-sm text-emerald-800", children: [_jsx("p", { className: "mb-1 font-medium", children: "G\u1EE3i \u00FD \u0111\u00E1p \u00E1n" }), _jsx("ul", { className: "list-disc space-y-1 pl-4", children: item.expectedAnswers.map((answer) => (_jsx("li", { children: answer }, answer))) })] })) : null] })] }));
|
|
77
|
-
}
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { SpontaneousQaGroupClient } from '../types/spontaneous-qa-group/SpontaneousQaGroupClient';
|
|
4
|
+
import { mapQuestionToSpontaneousQaGroupData } from '../types/spontaneous-qa-group/map-spontaneous-qa-group-data';
|
|
78
5
|
export function SpontaneousQaGroupViewer({ question, isReviewMode = false, }) {
|
|
79
|
-
|
|
80
|
-
const showPartChrome = parts.length > 1 || parts.some((part) => part.partTitle || part.topic);
|
|
81
|
-
return (_jsxs("div", { className: "space-y-5", children: [instruction ? (_jsx("div", { className: "rounded-xl border border-indigo-100 bg-indigo-50 px-4 py-3 text-sm font-medium text-indigo-800", children: instruction })) : null, parts.map((part) => (_jsxs("section", { className: "space-y-3", children: [showPartChrome ? (_jsxs("div", { children: [part.partTitle ? (_jsx("h3", { className: "text-base font-bold tracking-wide text-sky-600", children: part.partTitle })) : null, part.topic ? (_jsx("p", { className: "text-sm font-semibold text-slate-600", children: part.topic })) : null] })) : null, _jsx("div", { className: "space-y-3", children: part.questions.map((item, index) => (_jsx(QaPromptCard, { item: item, index: index, isReviewMode: isReviewMode }, `${part.partNumber}-${item.questionNumber}-${index}`))) })] }, `part-${part.partNumber}`)))] }));
|
|
6
|
+
return (_jsx(SpontaneousQaGroupClient, { questionData: mapQuestionToSpontaneousQaGroupData(question), isReviewMode: isReviewMode }));
|
|
82
7
|
}
|
|
@@ -4,8 +4,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
4
4
|
* Movers fallback review cases (isReviewMode=true).
|
|
5
5
|
* Source: oe-exam-fe ReviewQuestionRenderer.tsx
|
|
6
6
|
*/
|
|
7
|
-
import { MoversAnswerTheQuestionRenderer,
|
|
8
|
-
import { transformAnswerTheQuestion,
|
|
7
|
+
import { MoversAnswerTheQuestionRenderer, MoversGridFillRenderer, MoversLabelThePictureRenderer, MoversMatchByWritingAnswerRenderer, MoversMatchWordToPictureRenderer, MoversReadingPassageRenderer, MoversTrueFalseRenderer, MoversTrueFalseCorrectGroupRenderer, MoversFillInBlankGroupRenderer, MoversMatchingWithLinesGroupRenderer, MoversCrossOutWordGroupRenderer, MoversWordFillParagraphRenderer, MoversWordFillStructuredFormRenderer, MoversWordOrderingRenderer, MoversWordOrderingGroupRenderer, MoversWriteSentencesRenderer, MoversWritingRenderer, MoversCrosswordPuzzleRenderer, ChooseThenAnswerGroupRenderer, SortWordsIntoCategoriesRenderer, } from '../../../components/exams/take/components/question-renderers';
|
|
8
|
+
import { transformAnswerTheQuestion, transformGridFill, transformLabelPicture, transformMatchByWritingAnswer, transformMatchWordToPicture, transformReadingPassage, transformTrueFalse, transformTrueFalseCorrectGroup, transformFillInBlankGroup, transformMatchingWithLinesGroup, transformWordFillParagraph, transformWordFillStructuredForm, transformWordOrdering, transformWordOrderingGroupTake, transformWriteSentences, transformWriteShortLetter, transformCrosswordPuzzle, transformChooseThenAnswerGroup, transformSortWordsIntoCategories, } from '../../../components/exams/take/utils/question-transformers';
|
|
9
9
|
import { normalizeCrossOutWordGroupAnswer, transformCrossOutWordGroup, } from '../../../components/exams/take/utils/cross-out-word-group.transformer';
|
|
10
10
|
function asApiQuestions(questions) {
|
|
11
11
|
return questions;
|
|
@@ -28,22 +28,6 @@ export function renderMoversReviewBody(ctx) {
|
|
|
28
28
|
const gradingInfo = essayGradingMap[firstQuestion.id];
|
|
29
29
|
return (_jsx(MoversWritingRenderer, { partNumber: partNo, partName: part.name, prompt: data.prompt, requirements: data.requirements, minWords: data.minWords, maxWords: data.maxWords, answer: writingAnswer, onAnswerChange: handleAnswerChange, isReviewMode: true, guideImages: data.guideImages, passage: data.passage, teacherScore: gradingInfo?.score, maxScore: gradingInfo?.maxScore, teacherFeedback: gradingInfo?.teacherFeedback, writingAssessment: gradingInfo?.writingAssessment }));
|
|
30
30
|
}
|
|
31
|
-
case 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER': {
|
|
32
|
-
const data = transformPictureChoose(apiQuestions);
|
|
33
|
-
const subQuestionsWithCorrect = data.subQuestions.map((sq) => ({
|
|
34
|
-
...sq,
|
|
35
|
-
correctOptionId: correctOptionIdMap[sq.id],
|
|
36
|
-
}));
|
|
37
|
-
return (_jsx(MoversPictureChooseRenderer, { partNumber: partNo, partName: part.name, instruction: part.instructions || data.instruction, questionCount: questionCount, subQuestions: subQuestionsWithCorrect, answers: answers, onAnswerChange: handleAnswerChange, isReviewMode: true }));
|
|
38
|
-
}
|
|
39
|
-
case 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER': {
|
|
40
|
-
const data = transformPictureFillBlankChoose(apiQuestions);
|
|
41
|
-
const subQuestionsWithCorrect = data.subQuestions.map((sq) => ({
|
|
42
|
-
...sq,
|
|
43
|
-
correctOptionId: correctOptionIdMap[sq.id],
|
|
44
|
-
}));
|
|
45
|
-
return (_jsx(MoversPictureFillBlankChooseRenderer, { partNumber: partNo, partName: part.name, instruction: part.instructions || data.instruction, questionCount: questionCount, subQuestions: subQuestionsWithCorrect, answers: answers, onAnswerChange: handleAnswerChange, isReviewMode: true }));
|
|
46
|
-
}
|
|
47
31
|
case 'READ_PASSAGE_AND_ANSWER_QUESTIONS': {
|
|
48
32
|
const data = transformReadingPassage(apiQuestions);
|
|
49
33
|
return (_jsx(MoversReadingPassageRenderer, { partNumber: partNo, partName: part.name, instruction: part.instructions || data.instruction, questionCount: data.questions.length, passageTitle: data.passageTitle, passage: data.passage, passageImageUrl: data.passageImageUrl, questions: data.questions, answers: answers, onAnswerChange: handleAnswerChange, isReviewMode: true, correctOptionIdMap: correctOptionIdMap }));
|
|
@@ -58,14 +42,6 @@ export function renderMoversReviewBody(ctx) {
|
|
|
58
42
|
}));
|
|
59
43
|
return (_jsx(MoversLabelThePictureRenderer, { partNumber: partNo, partName: part.name, instruction: part.instructions || data.instruction, questionCount: data.labels.length, imageUrl: data.imageUrl, wordBank: data.wordBank, labels: labelsWithCorrect, answers: answers, onAnswerChange: handleAnswerChange, isReviewMode: true }));
|
|
60
44
|
}
|
|
61
|
-
case 'LOOK_PICTURE_FILL_WORD_HINT': {
|
|
62
|
-
const data = transformFillWordHint(apiQuestions);
|
|
63
|
-
const subQuestionsWithCorrect = data.subQuestions.map((sq) => ({
|
|
64
|
-
...sq,
|
|
65
|
-
correctAnswer: correctAnswerTextMap[sq.id],
|
|
66
|
-
}));
|
|
67
|
-
return (_jsx(MoversFillWordHintRenderer, { partNumber: partNo, partName: part.name, instruction: part.instructions || data.instruction, questionCount: questionCount, hintLetters: data.hintLetters, subQuestions: subQuestionsWithCorrect, answers: answers, onAnswerChange: handleAnswerChange, isReviewMode: true }));
|
|
68
|
-
}
|
|
69
45
|
case 'FILL_MISSING_WORDS_IN_GRID': {
|
|
70
46
|
const data = transformGridFill(apiQuestions);
|
|
71
47
|
const questionId = questions[0]?.id;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { normalizeCrossOutWordGroupAnswer } from '../../components/exams/take/utils/cross-out-word-group.transformer';
|
|
2
2
|
const FLATTENED_ANSWER_TYPES = new Set([
|
|
3
3
|
'READ_PASSAGE_AND_ANSWER_QUESTIONS',
|
|
4
|
-
'LOOK_PICTURE_FILL_WORD_HINT',
|
|
5
4
|
'LABEL_THE_PICTURE',
|
|
6
5
|
'READ_AND_COLOR_OBJECTS',
|
|
7
6
|
'IMAGE_OBJECT_MATCHING',
|
|
@@ -286,9 +285,6 @@ function transformStudentAnswer(questionId, questionType, value) {
|
|
|
286
285
|
}
|
|
287
286
|
if (questionType === 'LABEL_THE_PICTURE')
|
|
288
287
|
return record.answers ?? value;
|
|
289
|
-
if (questionType === 'LOOK_PICTURE_FILL_WORD_HINT' && typeof record.answer === 'string' && record.answer.includes(',')) {
|
|
290
|
-
return Object.fromEntries(record.answer.split(',').map((item, index) => [`${questionId}-blank-${index}`, item.trim()]));
|
|
291
|
-
}
|
|
292
288
|
if (questionType === 'WORD_FILL_PARAGRAPH') {
|
|
293
289
|
if (Array.isArray(record.answers))
|
|
294
290
|
return record.answers;
|
|
@@ -10,7 +10,7 @@ import { cn } from '../../shared/lib/utils';
|
|
|
10
10
|
* - Allows clearing the input to enter new values
|
|
11
11
|
* - Strips non-digit characters automatically
|
|
12
12
|
*/
|
|
13
|
-
export const PointsInput = forwardRef(({ label = 'Điểm số', error, required = true, allowZero = false, className, id, ...props }, ref) => {
|
|
13
|
+
export const PointsInput = forwardRef(({ label = 'Điểm số', error, required = true, allowZero = false, className, id, onValueChange, onChange, ...props }, ref) => {
|
|
14
14
|
const inputId = id || 'points';
|
|
15
15
|
const handleInput = (e) => {
|
|
16
16
|
const input = e.target;
|
|
@@ -28,6 +28,16 @@ export const PointsInput = forwardRef(({ label = 'Điểm số', error, required
|
|
|
28
28
|
input.value = intValue < minVal ? minVal.toString() : intValue.toString();
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
|
-
return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Label, { htmlFor: inputId, className: "whitespace-nowrap text-sm font-medium", children: [label, " ", required && _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { ref: ref, id: inputId, type: "number", step: "1", min: allowZero ? "0" : "1", onInput: handleInput,
|
|
31
|
+
return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Label, { htmlFor: inputId, className: "whitespace-nowrap text-sm font-medium", children: [label, " ", required && _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Input, { ref: ref, id: inputId, type: "number", step: "1", min: allowZero ? "0" : "1", onInput: handleInput, onChange: (e) => {
|
|
32
|
+
onChange?.(e);
|
|
33
|
+
if (onValueChange) {
|
|
34
|
+
const raw = e.target.value;
|
|
35
|
+
if (raw === '')
|
|
36
|
+
return;
|
|
37
|
+
const parsed = parseInt(raw, 10);
|
|
38
|
+
if (!Number.isNaN(parsed))
|
|
39
|
+
onValueChange(parsed);
|
|
40
|
+
}
|
|
41
|
+
}, className: cn('w-20', error && 'border-red-500 focus:ring-red-500', className), ...props }), error && _jsx("p", { className: "text-sm text-red-600", children: error })] }));
|
|
32
42
|
});
|
|
33
43
|
PointsInput.displayName = 'PointsInput';
|