@tinyweb_dev/oe-exam-sdk 1.0.6 → 1.0.7
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/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.js +2 -2
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupClient.js +1 -1
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupCreator.js +44 -28
- 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.js +1 -1
- package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupCreator.js +13 -11
- 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/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 +0 -19
- 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/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
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
interface CompactFieldCardProps {
|
|
3
|
+
header?: ReactNode;
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
contentClassName?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function CompactFieldCard({ header, children, className, contentClassName, }: CompactFieldCardProps): import("react").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Card, CardContent, CardHeader } from '../../../../../components/ui/card';
|
|
4
|
+
import { cn } from '../../../../../shared/lib/utils';
|
|
5
|
+
export function CompactFieldCard({ header, children, className, contentClassName, }) {
|
|
6
|
+
return (_jsxs(Card, { className: cn('overflow-hidden border-0 bg-white shadow-sm', className), children: [header ? _jsx(CardHeader, { className: "px-3 py-2", children: header }) : null, _jsx(CardContent, { className: cn('space-y-2.5 px-3 pb-3', !header && 'pt-3', contentClassName), children: children })] }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Button } from '../../../../../components/ui/button';
|
|
4
|
+
import { Pencil } from 'lucide-react';
|
|
5
|
+
export function CompactPreviewBanner({ message = 'Xem trước — hiển thị đáp án đúng, ảnh và audio đã thêm', onBack, backLabel = 'Quay lại chỉnh sửa', }) {
|
|
6
|
+
return (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 rounded-xl border border-indigo-100 bg-indigo-50/70 px-4 py-2.5", children: [_jsx("p", { className: "text-sm font-medium text-indigo-800", children: message }), _jsxs(Button, { variant: "outline", size: "sm", onClick: onBack, children: [_jsx(Pencil, { className: "mr-2 h-4 w-4" }), backLabel] })] }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Button } from '../../../../../components/ui/button';
|
|
4
|
+
import { Eye } from 'lucide-react';
|
|
5
|
+
export function CompactPreviewButton({ onClick, disabled }) {
|
|
6
|
+
return (_jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: onClick, disabled: disabled, className: "h-8 gap-1.5 border-indigo-200 px-2.5 text-xs text-indigo-600 hover:bg-indigo-50 hover:text-indigo-700", children: [_jsx(Eye, { className: "h-3.5 w-3.5" }), "Xem tr\u01B0\u1EDBc"] }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { CompactPreviewBanner } from './CompactPreviewBanner';
|
|
2
|
+
export { CompactExampleToggle } from './CompactExampleToggle';
|
|
3
|
+
export { CompactPreviewButton } from './CompactPreviewButton';
|
|
4
|
+
export { CompactCreatorHeader } from './CompactCreatorHeader';
|
|
5
|
+
export { CompactFieldCard } from './CompactFieldCard';
|
|
6
|
+
export { CompactExplanationToggle } from './CompactExplanationToggle';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { CompactPreviewBanner } from './CompactPreviewBanner';
|
|
2
|
+
export { CompactExampleToggle } from './CompactExampleToggle';
|
|
3
|
+
export { CompactPreviewButton } from './CompactPreviewButton';
|
|
4
|
+
export { CompactCreatorHeader } from './CompactCreatorHeader';
|
|
5
|
+
export { CompactFieldCard } from './CompactFieldCard';
|
|
6
|
+
export { CompactExplanationToggle } from './CompactExplanationToggle';
|
|
@@ -101,21 +101,6 @@ export const QUESTION_TYPE_CONFIG = {
|
|
|
101
101
|
requiresContent: true,
|
|
102
102
|
hasDedicatedComponent: true,
|
|
103
103
|
},
|
|
104
|
-
LOOK_PICTURE_CHOOSE_CORRECT_ANSWER: {
|
|
105
|
-
label: 'Nhìn tranh, chọn đáp án đúng',
|
|
106
|
-
requiresContent: true,
|
|
107
|
-
hasDedicatedComponent: true,
|
|
108
|
-
},
|
|
109
|
-
LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER: {
|
|
110
|
-
label: 'Nhìn tranh, điền chỗ trống, chọn đáp án',
|
|
111
|
-
requiresContent: true,
|
|
112
|
-
hasDedicatedComponent: true,
|
|
113
|
-
},
|
|
114
|
-
LOOK_PICTURE_FILL_WORD_HINT: {
|
|
115
|
-
label: 'Nhìn tranh điền từ gợi ý',
|
|
116
|
-
requiresContent: true,
|
|
117
|
-
hasDedicatedComponent: true,
|
|
118
|
-
},
|
|
119
104
|
LABEL_THE_PICTURE: {
|
|
120
105
|
label: 'Label the Picture',
|
|
121
106
|
requiresContent: true,
|
|
@@ -322,11 +307,6 @@ export const QUESTION_TYPE_CONFIG = {
|
|
|
322
307
|
requiresContent: true,
|
|
323
308
|
hasDedicatedComponent: true,
|
|
324
309
|
},
|
|
325
|
-
GN_SPEAKING_INTERVIEW: {
|
|
326
|
-
label: 'GN Speaking - Hỏi đáp (Virtual + Real)',
|
|
327
|
-
requiresContent: true,
|
|
328
|
-
hasDedicatedComponent: true,
|
|
329
|
-
},
|
|
330
310
|
SPEAKING_CUE_CARD: {
|
|
331
311
|
label: 'IELTS Cue Card (Speaking Part 2)',
|
|
332
312
|
requiresContent: true,
|
|
@@ -378,9 +358,6 @@ export const QUESTION_TYPES_WITH_DEDICATED_COMPONENTS = [
|
|
|
378
358
|
'ARRANGE_LETTERS_INTO_WORDS',
|
|
379
359
|
'WRITE_SHORT_PARAGRAPH',
|
|
380
360
|
'FILL_MISSING_WORDS_IN_GRID',
|
|
381
|
-
'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER',
|
|
382
|
-
'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER',
|
|
383
|
-
'LOOK_PICTURE_FILL_WORD_HINT',
|
|
384
361
|
'LABEL_THE_PICTURE',
|
|
385
362
|
'READ_AND_COLOR_OBJECTS',
|
|
386
363
|
'IMAGE_OBJECT_MATCHING',
|
|
@@ -418,7 +395,6 @@ export const QUESTION_TYPES_WITH_DEDICATED_COMPONENTS = [
|
|
|
418
395
|
'SPONTANEOUS_QA',
|
|
419
396
|
'SPONTANEOUS_QA_GROUP',
|
|
420
397
|
'SPEAKING_CONVERSATION',
|
|
421
|
-
'GN_SPEAKING_INTERVIEW',
|
|
422
398
|
'SPEAKING_CUE_CARD',
|
|
423
399
|
'WORD_FILL_STRUCTURED_FORM',
|
|
424
400
|
'CROSSWORD_PUZZLE',
|
|
@@ -98,15 +98,6 @@ export function useQuestionInitialization({ initialData, prefilledType, prefille
|
|
|
98
98
|
if (answerData.missingLetters)
|
|
99
99
|
updateFieldRef.current('fillMissingWordsInGridAnswers', answerData.missingLetters);
|
|
100
100
|
break;
|
|
101
|
-
case 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER':
|
|
102
|
-
case 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER':
|
|
103
|
-
if (answerData.subQuestions)
|
|
104
|
-
updateFieldRef.current('lookPictureChooseSubQuestions', answerData.subQuestions);
|
|
105
|
-
break;
|
|
106
|
-
case 'LOOK_PICTURE_FILL_WORD_HINT':
|
|
107
|
-
if (answerData.subQuestions)
|
|
108
|
-
updateFieldRef.current('lookPictureFillWordHintSubQuestions', answerData.subQuestions);
|
|
109
|
-
break;
|
|
110
101
|
}
|
|
111
102
|
}
|
|
112
103
|
}
|
|
@@ -5,7 +5,6 @@ export * from './arrange-letters-into-words.type';
|
|
|
5
5
|
export * from './write-short-paragraph.type';
|
|
6
6
|
export * from './fill-missing-words-in-grid.type';
|
|
7
7
|
export * from './look-and-choose-answer.type';
|
|
8
|
-
export * from './look-picture-fill-word-hint.type';
|
|
9
8
|
export * from './label-the-picture.type';
|
|
10
9
|
export * from './read-and-color-objects.type';
|
|
11
10
|
export * from './fill-in-blank.type';
|
|
@@ -5,7 +5,6 @@ export * from './arrange-letters-into-words.type';
|
|
|
5
5
|
export * from './write-short-paragraph.type';
|
|
6
6
|
export * from './fill-missing-words-in-grid.type';
|
|
7
7
|
export * from './look-and-choose-answer.type';
|
|
8
|
-
export * from './look-picture-fill-word-hint.type';
|
|
9
8
|
export * from './label-the-picture.type';
|
|
10
9
|
export * from './read-and-color-objects.type';
|
|
11
10
|
export * from './fill-in-blank.type';
|
|
@@ -10,10 +10,6 @@ export interface LookAndChooseData {
|
|
|
10
10
|
correctAnswerId?: string;
|
|
11
11
|
points?: number;
|
|
12
12
|
}
|
|
13
|
-
export interface LookPictureChooseCorrectAnswerData {
|
|
14
|
-
subQuestions: LookAndChooseSubQuestion[];
|
|
15
|
-
points?: number;
|
|
16
|
-
}
|
|
17
13
|
export interface ValidationRef {
|
|
18
14
|
triggerValidation: () => Promise<boolean>;
|
|
19
15
|
getFormData?: () => any;
|
|
@@ -27,15 +23,6 @@ export interface LookAndChooseCreatorProps {
|
|
|
27
23
|
optionCount?: number | null;
|
|
28
24
|
validationRef?: React.MutableRefObject<ValidationRef | null>;
|
|
29
25
|
}
|
|
30
|
-
export interface LookPictureChooseCorrectAnswerCreatorProps {
|
|
31
|
-
initialData?: LookPictureChooseCorrectAnswerData;
|
|
32
|
-
onSave?: (data: LookPictureChooseCorrectAnswerData) => void;
|
|
33
|
-
onCancel?: () => void;
|
|
34
|
-
onChange?: (data: LookPictureChooseCorrectAnswerData) => void;
|
|
35
|
-
onUnsavedChangesChange?: (hasUnsavedChanges: boolean) => void;
|
|
36
|
-
optionCount?: number | null;
|
|
37
|
-
validationRef?: React.MutableRefObject<ValidationRef | null>;
|
|
38
|
-
}
|
|
39
26
|
export interface LookAndChooseClientProps {
|
|
40
27
|
questionData: {
|
|
41
28
|
imageUrl?: string;
|
|
@@ -59,17 +59,6 @@ export function buildAnswerPayload(questionType, state) {
|
|
|
59
59
|
missingLetters: state.fillMissingWordsInGridAnswers || [],
|
|
60
60
|
caseSensitive: false,
|
|
61
61
|
};
|
|
62
|
-
case 'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER':
|
|
63
|
-
// This type uses dedicated component, so answer is built by the component itself
|
|
64
|
-
return undefined;
|
|
65
|
-
case 'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER':
|
|
66
|
-
// This type uses dedicated component, so answer is built by the component itself
|
|
67
|
-
return undefined;
|
|
68
|
-
case 'LOOK_PICTURE_FILL_WORD_HINT':
|
|
69
|
-
return {
|
|
70
|
-
subQuestions: state.lookPictureFillWordHintSubQuestions || [],
|
|
71
|
-
caseSensitive: false,
|
|
72
|
-
};
|
|
73
62
|
case 'READ_PASSAGE_AND_ANSWER_QUESTIONS':
|
|
74
63
|
// This type uses dedicated component, so answer is built by the component itself
|
|
75
64
|
return undefined;
|
|
@@ -3,11 +3,9 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
4
4
|
import { Button } from '../../../components/ui/button';
|
|
5
5
|
import { Label } from '../../../components/ui/label';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { X, Pencil, Eye, Plus, Trash2, MessageSquare, Palette, Lightbulb, Image } from 'lucide-react';
|
|
6
|
+
import { X, Plus, Trash2, MessageSquare, Palette, Image } from 'lucide-react';
|
|
7
|
+
import { CompactCreatorHeader, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, } from '../_shared/components/compact';
|
|
9
8
|
import { Input } from '../../../components/ui/input';
|
|
10
|
-
import { Textarea } from '../../../components/ui/textarea';
|
|
11
9
|
import { FileUpload } from '../../../components/ui/file-upload';
|
|
12
10
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../../components/ui/select';
|
|
13
11
|
import { ColorRegionNode } from './ColorRegionNode';
|
|
@@ -352,68 +350,73 @@ function ColorRegionCreatorContent({ initialData, onSave, onCancel, onChange, on
|
|
|
352
350
|
instructions,
|
|
353
351
|
explanation,
|
|
354
352
|
};
|
|
355
|
-
return (_jsxs("div", { className: "space-y-
|
|
353
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsx(CompactPreviewBanner, { onBack: () => setIsClientMode(false) }), _jsx(ClientComponent, { questionData: questionData, onSubmit: () => { }, isReviewMode: true, explanation: explanation })] }));
|
|
356
354
|
}
|
|
357
355
|
// Get available colors (not yet added)
|
|
358
356
|
const availableColors = COLOR_PALETTE.filter((color) => !colorNodes.some((node) => node.color === color));
|
|
359
|
-
return (_jsxs("div", { className: "space-y-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
357
|
+
return (_jsxs("div", { className: "space-y-3", children: [_jsxs(CompactFieldCard, { header: _jsx(CompactCreatorHeader, { icon: _jsx(Palette, { className: "h-3.5 w-3.5" }), title: config.creatorTitle, points: {
|
|
358
|
+
value: points,
|
|
359
|
+
onValueChange: setPoints,
|
|
360
|
+
}, preview: {
|
|
361
|
+
onClick: () => setIsClientMode(true),
|
|
362
|
+
} }), children: [!isClientMode && (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(MessageSquare, { className: "h-4 w-4 text-indigo-500" }), config.instructionsLabel, " ", instructionsRequired && _jsx("span", { className: "text-red-500", children: "*" })] }), _jsxs(Button, { onClick: () => {
|
|
363
|
+
setInstructions([...instructions, '']);
|
|
364
|
+
form.clearErrors('instructions');
|
|
365
|
+
}, className: "gap-2 border-green-200 text-green-600 hover:bg-green-50 hover:text-green-700", size: "sm", variant: "outline", children: [_jsx(Plus, { className: "h-4 w-4" }), "Th\u00EAm c\u00E2u l\u1EC7nh"] })] }), errors.instructions && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-red-200 bg-gradient-to-r from-red-50 to-rose-50 p-4", children: [_jsx("span", { className: "text-lg", children: "\u274C" }), _jsx("p", { className: "text-sm text-red-600", children: errors.instructions })] })), _jsx("div", { className: "space-y-3", children: instructions.map((instruction, index) => {
|
|
366
|
+
const hasError = errors.instructionItems?.[index];
|
|
367
|
+
return (_jsxs("div", { className: `group relative rounded-xl border-2 p-3 transition-all duration-200 ${instruction.trim()
|
|
368
|
+
? 'border-green-200 bg-gradient-to-r from-green-50 to-emerald-50'
|
|
369
|
+
: 'border-gray-200 bg-white hover:border-gray-300'}`, children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: `flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg font-bold transition-all ${instruction.trim()
|
|
370
|
+
? 'bg-gradient-to-br from-green-500 to-emerald-600 text-white shadow-md'
|
|
371
|
+
: 'bg-gray-100 text-gray-600'}`, children: index + 1 }), _jsx(Input, { value: instruction, onChange: (e) => {
|
|
372
|
+
const newInstructions = [...instructions];
|
|
373
|
+
newInstructions[index] = e.target.value;
|
|
374
|
+
setInstructions(newInstructions);
|
|
375
|
+
form.clearErrors('instructions');
|
|
376
|
+
}, placeholder: `Ví dụ: ${config.instructionPlaceholder}`, className: `flex-1 border-gray-200 bg-white transition-all focus:border-indigo-300 focus:ring-indigo-200 ${hasError ? 'border-red-400' : ''}` }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
|
|
377
|
+
setInstructions(instructions.filter((_, i) => i !== index));
|
|
378
|
+
}, className: "text-gray-400 hover:bg-red-50 hover:text-red-500", children: _jsx(Trash2, { className: "h-4 w-4" }) })] }), hasError && (_jsx("p", { className: "ml-11 mt-2 text-sm text-red-600", children: hasError }))] }, index));
|
|
379
|
+
}) }), instructions.length === 0 && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-4", children: [_jsx("span", { className: "text-lg", children: "\u26A0\uFE0F" }), _jsx("p", { className: "text-sm text-amber-800", children: "Ch\u01B0a c\u00F3 h\u01B0\u1EDBng d\u1EABn n\u00E0o. Nh\u1EA5n \"Th\u00EAm c\u00E2u l\u1EC7nh\" \u0111\u1EC3 b\u1EAFt \u0111\u1EA7u." })] }))] })), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(Image, { className: "h-4 w-4 text-indigo-500" }), "\u1EA2nh n\u1EC1n ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(FileUpload, { id: "image-upload", label: "\u1EA2nh n\u1EC1n", accept: "image/*", value: backgroundImageUrl, onChange: (key) => {
|
|
380
|
+
setBackgroundImageUrl(key);
|
|
381
|
+
setImageLoaded(false);
|
|
382
|
+
form.clearErrors();
|
|
383
|
+
}, onPresignedUrlChange: (url) => {
|
|
384
|
+
setBackgroundPreviewUrl(url);
|
|
385
|
+
setImageLoaded(false);
|
|
386
|
+
}, disabled: isClientMode, maxSize: 5, placeholder: "Paste URL ho\u1EB7c upload file", required: true, autoUpload: true, prefix: "questions", onFileLoad: () => {
|
|
387
|
+
setImageLoaded(false);
|
|
388
|
+
} }), errors.backgroundImageUrl && (_jsx("p", { className: "mt-1 text-sm text-red-600", children: errors.backgroundImageUrl }))] }), !isClientMode && (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(Palette, { className: "h-4 w-4 text-purple-500" }), config.addItemLabel || 'Thêm Màu', " ", _jsx("span", { className: "text-red-500", children: "*" })] }), !showAddColorPanel && (_jsxs(Button, { onClick: () => setShowAddColorPanel(true), className: "gap-2 border-purple-200 text-purple-600 hover:bg-purple-50 hover:text-purple-700", size: "sm", variant: "outline", disabled: availableColors.length === 0, children: [_jsx(Plus, { className: "h-4 w-4" }), config.addItemLabel || 'Thêm màu'] }))] }), errors.colorNodes && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-red-200 bg-gradient-to-r from-red-50 to-rose-50 p-4", children: [_jsx("span", { className: "text-lg", children: "\u274C" }), _jsx("p", { className: "text-sm text-red-600", children: errors.colorNodes })] })), showAddColorPanel && (_jsxs("div", { className: "flex flex-col gap-3 rounded-xl border-2 border-purple-200 bg-gradient-to-r from-purple-50 to-indigo-50 p-4", children: [showColorLabel && (_jsx(Input, { value: colorLabelValue, onChange: (e) => setColorLabelValue(e.target.value), placeholder: config.colorLabelPlaceholder || 'Nhập label (ví dụ: Tom, Apple...)', className: "h-9 border-gray-200 bg-white" })), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Select, { value: selectedColor, onValueChange: setSelectedColor, children: [_jsx(SelectTrigger, { className: "flex-1 border-gray-200 bg-white", children: _jsx(SelectValue, { placeholder: "Ch\u1ECDn m\u00E0u..." }) }), _jsx(SelectContent, { children: availableColors.map((color) => (_jsx(SelectItem, { value: color, children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-4 w-4 rounded border border-gray-300", style: { backgroundColor: color } }), _jsx("span", { className: "font-mono text-xs", children: color })] }) }, color))) })] }), _jsx(Button, { size: "sm", onClick: addNewColorNode, disabled: !selectedColor ||
|
|
389
|
+
availableColors.length === 0 ||
|
|
390
|
+
(showColorLabel && !colorLabelValue.trim()), className: "bg-purple-600 hover:bg-purple-700", children: "T\u1EA1o" }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
391
|
+
setShowAddColorPanel(false);
|
|
392
|
+
setSelectedColor('');
|
|
393
|
+
setColorLabelValue('');
|
|
394
|
+
}, children: "H\u1EE7y" })] })] })), colorNodes.length === 0 && !showAddColorPanel && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-4", children: [_jsx("span", { className: "text-lg", children: "\u26A0\uFE0F" }), _jsx("p", { className: "text-sm text-amber-800", children: config.emptyItemMessage || 'Chưa có màu nào. Nhấn "Thêm màu" để bắt đầu.' })] }))] })), errors.regionNodes && (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border border-red-200 bg-gradient-to-r from-red-50 to-rose-50 p-4", children: [_jsx("span", { className: "text-lg", children: "\u274C" }), _jsx("p", { className: "text-sm text-red-600", children: errors.regionNodes })] }))] }), _jsxs(CompactFieldCard, { header: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("p", { className: "text-sm font-semibold text-gray-800", children: "Workspace \u2014 \u1EA2nh n\u1EC1n" }), _jsx("span", { className: "text-xs text-gray-500", children: "K\u00E9o th\u1EA3 region \u0111\u1EC3 \u0111\u1ECBnh v\u1ECB" })] }), contentClassName: "p-0 space-y-0 px-0 pb-0", children: [colorNodes.length > 0 && (_jsx("div", { className: "border-b border-gray-100 px-4 py-3 flex flex-wrap gap-2", children: colorNodes.map((node) => (_jsxs("div", { className: "inline-flex items-center gap-1.5 rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-900", children: [_jsx("div", { className: "h-4 w-4 rounded border border-gray-300", style: { backgroundColor: node.color } }), node.label ? (_jsx("span", { className: "text-xs", children: node.label })) : (_jsx("span", { className: "font-mono text-xs", children: node.color })), !isClientMode && (_jsx("button", { onClick: () => removeColorNode(node.id), className: "group rounded p-0.5 transition-all hover:scale-110 hover:bg-red-100", type: "button", children: _jsx(X, { className: "h-3 w-3 text-gray-500 transition-colors group-hover:text-red-600" }) }))] }, node.id))) })), _jsx("div", { ref: workspaceRef, className: "relative w-full overflow-hidden select-none isolate", style: { cursor: draggingId ? 'grabbing' : 'default' }, children: backgroundPreviewUrl ? (_jsxs(_Fragment, { children: [_jsx("img", { src: backgroundPreviewUrl, alt: "Background", className: "block w-full h-auto", draggable: false, onLoad: () => setImageLoaded(true), onError: () => {
|
|
395
|
+
form.setError('backgroundImageUrl', { message: 'Không thể load ảnh!' });
|
|
396
|
+
setImageLoaded(false);
|
|
397
|
+
} }), imageLoaded &&
|
|
398
|
+
regionNodes.map((region) => {
|
|
399
|
+
const linkedColorNode = colorNodes.find((n) => n.id === region.linkedColorNodeId);
|
|
400
|
+
return (_jsx("div", { style: {
|
|
401
|
+
position: 'absolute',
|
|
402
|
+
left: `${region.x}%`,
|
|
403
|
+
top: `${region.y}%`,
|
|
404
|
+
width: `${region.width}%`,
|
|
405
|
+
height: `${region.height}%`,
|
|
406
|
+
cursor: isClientMode ? 'default' : 'grab',
|
|
407
|
+
zIndex: draggingId === region.id ? 2 : 1,
|
|
408
|
+
}, onMouseDown: (e) => handleRegionMouseDown(region.id, region.x, region.y, e), children: _jsx(ColorRegionNode, { data: {
|
|
409
|
+
color: region.color,
|
|
410
|
+
x: region.x,
|
|
411
|
+
y: region.y,
|
|
412
|
+
width: region.width,
|
|
413
|
+
height: region.height,
|
|
414
|
+
onRemove: () => removeRegion(region.id),
|
|
415
|
+
isEditMode: !isClientMode,
|
|
416
|
+
isClientMode: isClientMode,
|
|
417
|
+
label: linkedColorNode?.label || '',
|
|
418
|
+
} }) }, region.id));
|
|
419
|
+
})] })) : (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 py-20 text-gray-400", children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-10 w-10 text-gray-300", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), _jsx("p", { className: "text-sm", children: "Ch\u01B0a c\u00F3 \u1EA3nh n\u1EC1n. H\u00E3y upload \u1EA3nh \u1EDF tr\u00EAn." })] })) })] }), _jsx(CompactExplanationToggle, { value: explanation, onValueChange: setExplanation, defaultVisible: Boolean(initialData?.explanation) })] }));
|
|
417
420
|
}
|
|
418
421
|
export function ColorRegionCreator(props) {
|
|
419
422
|
return _jsx(ColorRegionCreatorContent, { ...props });
|
|
@@ -19,9 +19,6 @@ const truncate = (text, maxLength) => {
|
|
|
19
19
|
};
|
|
20
20
|
// Image-based question types
|
|
21
21
|
const IMAGE_BASED_TYPES = [
|
|
22
|
-
'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER',
|
|
23
|
-
'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER',
|
|
24
|
-
'LOOK_PICTURE_FILL_WORD_HINT',
|
|
25
22
|
'FILL_IN_BLANK',
|
|
26
23
|
'FILL_IN_BLANK_GROUP',
|
|
27
24
|
'LABEL_THE_PICTURE',
|
|
@@ -54,9 +51,6 @@ const getQuestionTypeIcon = (type) => {
|
|
|
54
51
|
// Get question type display name in Vietnamese
|
|
55
52
|
const getQuestionTypeName = (type) => {
|
|
56
53
|
const typeMap = {
|
|
57
|
-
'LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER': 'Nhìn tranh điền chỗ trống',
|
|
58
|
-
'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER': 'Nhìn tranh chọn đáp án',
|
|
59
|
-
'LOOK_PICTURE_FILL_WORD_HINT': 'Nhìn tranh điền từ gợi ý',
|
|
60
54
|
'FILL_MISSING_WORDS_IN_GRID': 'Điền chữ trong bảng',
|
|
61
55
|
'CHOOSE_THE_CORRECT_ANSWER': 'Chọn đáp án đúng',
|
|
62
56
|
'LABEL_THE_PICTURE': 'Gắn nhãn hình ảnh',
|
|
@@ -90,7 +84,6 @@ export const getContentDisplayText = (content, type) => {
|
|
|
90
84
|
}
|
|
91
85
|
// Handle object content based on question type
|
|
92
86
|
if (typeof content === 'object') {
|
|
93
|
-
// LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER, LOOK_PICTURE_CHOOSE_CORRECT_ANSWER
|
|
94
87
|
if (content.subQuestions && Array.isArray(content.subQuestions)) {
|
|
95
88
|
const firstSubQ = content.subQuestions[0];
|
|
96
89
|
if (firstSubQ?.question) {
|
|
@@ -101,7 +94,6 @@ export const getContentDisplayText = (content, type) => {
|
|
|
101
94
|
if (content.question) {
|
|
102
95
|
return content.question;
|
|
103
96
|
}
|
|
104
|
-
// LOOK_PICTURE_FILL_WORD_HINT - show word pattern
|
|
105
97
|
if (content.word) {
|
|
106
98
|
return `Điền chữ: ${content.word}`;
|
|
107
99
|
}
|
|
@@ -19,8 +19,6 @@ export function QuestionTypeSelector({ value, onValueChange, disabled, }) {
|
|
|
19
19
|
'READ_AND_CHOOSE_APPROPRIATE_WORD',
|
|
20
20
|
'WRITE_SHORT_PARAGRAPH',
|
|
21
21
|
'FILL_MISSING_WORDS_IN_GRID',
|
|
22
|
-
'LOOK_PICTURE_CHOOSE_CORRECT_ANSWER',
|
|
23
|
-
'LOOK_PICTURE_FILL_WORD_HINT',
|
|
24
22
|
'LABEL_THE_PICTURE',
|
|
25
23
|
'READ_AND_COLOR_OBJECTS',
|
|
26
24
|
'ANSWER_THE_QUESTION',
|
|
@@ -3,6 +3,7 @@ export { ColorRegionClient } from './ColorRegionClient';
|
|
|
3
3
|
export { ColorRegionCreator } from './ColorRegionCreator';
|
|
4
4
|
export { ColorRegionNode } from './ColorRegionNode';
|
|
5
5
|
export { CreatorGuide } from './CreatorGuide';
|
|
6
|
+
export { CompactCreatorHeader, CompactExampleToggle, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, CompactPreviewButton, } from '../_shared/components/compact';
|
|
6
7
|
export { NameNode } from './NameNode';
|
|
7
8
|
export { QuestionBankOption } from './QuestionBankOption';
|
|
8
9
|
export { QuestionBasicInfoForm } from './QuestionBasicInfoForm';
|
|
@@ -3,6 +3,7 @@ export { ColorRegionClient } from './ColorRegionClient';
|
|
|
3
3
|
export { ColorRegionCreator } from './ColorRegionCreator';
|
|
4
4
|
export { ColorRegionNode } from './ColorRegionNode';
|
|
5
5
|
export { CreatorGuide } from './CreatorGuide';
|
|
6
|
+
export { CompactCreatorHeader, CompactExampleToggle, CompactExplanationToggle, CompactFieldCard, CompactPreviewBanner, CompactPreviewButton, } from '../_shared/components/compact';
|
|
6
7
|
export { NameNode } from './NameNode';
|
|
7
8
|
export { QuestionBankOption } from './QuestionBankOption';
|
|
8
9
|
export { QuestionBasicInfoForm } from './QuestionBasicInfoForm';
|
|
@@ -3,9 +3,6 @@ import { fillInBlankRegistration } from '../types/fill-in-blank/register';
|
|
|
3
3
|
import { arrangeLettersIntoWordsRegistration } from '../types/arrange-letters-into-words/register';
|
|
4
4
|
import { writeShortParagraphRegistration } from '../types/write-short-paragraph/register';
|
|
5
5
|
import { fillMissingWordsInGridRegistration } from '../types/fill-missing-words-in-grid/register';
|
|
6
|
-
import { lookPictureChooseCorrectAnswerRegistration } from '../types/look-picture-choose-correct-answer/register';
|
|
7
|
-
import { lookPictureFillBlankChooseAnswerRegistration } from '../types/look-picture-fill-blank-choose-answer/register';
|
|
8
|
-
import { lookPictureFillWordHintRegistration } from '../types/look-picture-fill-word-hint/register';
|
|
9
6
|
import { labelThePictureRegistration } from '../types/label-the-picture/register';
|
|
10
7
|
import { readAndColorObjectsRegistration } from '../types/read-and-color-objects/register';
|
|
11
8
|
import { imageObjectMatchingRegistration } from '../types/image-object-matching/register';
|
|
@@ -44,7 +41,6 @@ import { spontaneousQARegistration } from '../types/spontaneous-qa/register';
|
|
|
44
41
|
import { spontaneousQaGroupRegistration } from '../types/spontaneous-qa-group/register';
|
|
45
42
|
import { readDisplayedContentRegistration } from '../types/read-displayed-content/register';
|
|
46
43
|
import { speakingConversationRegistration } from '../types/speaking-conversation/register';
|
|
47
|
-
import { gnSpeakingInterviewRegistration } from '../types/gn-speaking-interview/register';
|
|
48
44
|
import { speakingCueCardRegistration } from '../types/speaking-cue-card/register';
|
|
49
45
|
import { wordFillStructuredFormRegistration } from '../types/word-fill-structured-form/register';
|
|
50
46
|
import { wordOrderAndMatchGroupRegistration } from '../types/word-order-and-match-group/register';
|
|
@@ -68,9 +64,6 @@ export const questionTypeRegistry = {
|
|
|
68
64
|
ARRANGE_LETTERS_INTO_WORDS: arrangeLettersIntoWordsRegistration,
|
|
69
65
|
WRITE_SHORT_PARAGRAPH: writeShortParagraphRegistration,
|
|
70
66
|
FILL_MISSING_WORDS_IN_GRID: fillMissingWordsInGridRegistration,
|
|
71
|
-
LOOK_PICTURE_CHOOSE_CORRECT_ANSWER: lookPictureChooseCorrectAnswerRegistration,
|
|
72
|
-
LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER: lookPictureFillBlankChooseAnswerRegistration,
|
|
73
|
-
LOOK_PICTURE_FILL_WORD_HINT: lookPictureFillWordHintRegistration,
|
|
74
67
|
LABEL_THE_PICTURE: labelThePictureRegistration,
|
|
75
68
|
READ_AND_COLOR_OBJECTS: readAndColorObjectsRegistration,
|
|
76
69
|
IMAGE_OBJECT_MATCHING: imageObjectMatchingRegistration,
|
|
@@ -102,7 +95,6 @@ export const questionTypeRegistry = {
|
|
|
102
95
|
SPONTANEOUS_QA_GROUP: spontaneousQaGroupRegistration,
|
|
103
96
|
READ_DISPLAYED_CONTENT: readDisplayedContentRegistration,
|
|
104
97
|
SPEAKING_CONVERSATION: speakingConversationRegistration,
|
|
105
|
-
GN_SPEAKING_INTERVIEW: gnSpeakingInterviewRegistration,
|
|
106
98
|
SPEAKING_CUE_CARD: speakingCueCardRegistration,
|
|
107
99
|
WORD_FILL_STRUCTURED_FORM: wordFillStructuredFormRegistration,
|
|
108
100
|
CROSSWORD_PUZZLE: crosswordPuzzleRegistration,
|
|
@@ -114,8 +114,8 @@ export function ArticlesGroupCard({ groupNumber, articleCount, articles, onArtic
|
|
|
114
114
|
const updated = displayArticles.filter((_, i) => i !== index);
|
|
115
115
|
onArticlesChange(updated);
|
|
116
116
|
};
|
|
117
|
-
return (_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-
|
|
117
|
+
return (_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-sm", children: [_jsx(CardHeader, { className: "px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-gray-100", children: _jsx(Layers, { className: "h-3.5 w-3.5 text-gray-600" }) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-sm font-bold text-gray-900", children: "B\u00E0i vi\u1EBFt nh\u00F3m" }), _jsxs("span", { className: "inline-flex items-center rounded-md border border-gray-200 bg-gray-50 px-2 py-0.5 text-xs font-semibold text-gray-600", children: ["Nh\u00F3m ", groupNumber] }), _jsxs("span", { className: "inline-flex items-center rounded-md border border-emerald-200 bg-emerald-50 px-2 py-0.5 text-xs font-medium text-emerald-600", children: [articles.length || articleCount, " b\u00E0i vi\u1EBFt"] })] })] }) }), _jsxs(CardContent, { className: "space-y-2.5 px-3 pb-3", children: [_jsxs("div", { className: "space-y-2 pb-2", children: [_jsxs(Label, { htmlFor: `${uploadIdPrefix}-title`, className: "flex items-center gap-2 text-sm font-semibold text-gray-800", children: [_jsx(Type, { className: "h-4 w-4 text-teal-500" }), "Ti\u00EAu \u0111\u1EC1 nh\u00F3m b\u00E0i vi\u1EBFt", ' ', _jsx("span", { className: "text-xs font-normal text-gray-500", children: "(T\u00F9y ch\u1ECDn)" })] }), _jsx(Input, { id: `${uploadIdPrefix}-title`, value: title, onChange: (e) => onTitleChange?.(e.target.value), placeholder: "Nh\u1EADp ti\u00EAu \u0111\u1EC1 chung cho nh\u00F3m b\u00E0i vi\u1EBFt\u2026", readOnly: isReadOnly, className: `border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-200 ${isReadOnly ? 'bg-gray-50 text-gray-500 cursor-not-allowed border-transparent focus:border-transparent focus:ring-0' : ''}` })] }), displayArticles.map((article, index) => {
|
|
118
118
|
const letter = String.fromCharCode(65 + index); // A, B, C...
|
|
119
|
-
return (_jsxs("div", { className: "rounded-
|
|
119
|
+
return (_jsxs("div", { className: "rounded-md border border-gray-200 bg-white p-3 transition-all hover:border-gray-300 hover:shadow-sm", children: [_jsxs("div", { className: "mb-3 flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-teal-500 to-emerald-600 text-sm font-bold text-white shadow-sm", children: letter }), _jsxs("span", { className: "text-sm font-semibold text-gray-700", children: ["B\u00E0i vi\u1EBFt ", index + 1] })] }), displayArticles.length > 1 && !isReadOnly && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => handleDeleteArticle(index), className: "h-8 w-8 p-0 text-red-500 hover:bg-red-50 hover:text-red-600", title: "X\u00F3a b\u00E0i vi\u1EBFt", children: _jsx(Trash2, { className: "h-4 w-4" }) }))] }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { htmlFor: `${uploadIdPrefix}-name-${index}`, className: "flex items-center gap-1.5 text-sm font-medium text-gray-700", children: [_jsx(Type, { className: "h-3.5 w-3.5 text-teal-500" }), "T\u00EAn ng\u01B0\u1EDDi / ti\u00EAu \u0111\u1EC1"] }), _jsx(Input, { id: `${uploadIdPrefix}-name-${index}`, value: article.name, onChange: (e) => handleFieldChange(index, 'name', e.target.value), placeholder: `VD: Ariel, Clive, Vicky...`, readOnly: isReadOnly, className: `border-gray-200 bg-white transition-all focus:border-teal-300 focus:ring-teal-200 ${isReadOnly ? 'bg-gray-50 text-gray-500 cursor-not-allowed border-transparent focus:border-transparent focus:ring-0' : ''}` })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { className: "flex items-center gap-1.5 text-sm font-medium text-gray-700", children: [_jsx(FileText, { className: "h-3.5 w-3.5 text-teal-500" }), "N\u1ED9i dung b\u00E0i vi\u1EBFt"] }), _jsx(ArticleEditor, { value: article.content, onChange: (html) => handleFieldChange(index, 'content', html), isReadOnly: isReadOnly })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsxs(Label, { className: "flex items-center gap-1.5 text-sm font-medium text-gray-700", children: [_jsx(ImageIcon, { className: "h-3.5 w-3.5 text-teal-500" }), "H\u00ECnh \u1EA3nh", ' ', _jsx("span", { className: "text-xs font-normal text-gray-400", children: "(T\u00F9y ch\u1ECDn)" })] }), !isReadOnly && (_jsx(FileUpload, { id: `${uploadIdPrefix}-image-${index}`, label: "", accept: "image/*", value: article.imageUrl, onChange: (url) => handleFieldChange(index, 'imageUrl', url), maxSize: 5, placeholder: "Upload \u1EA3nh ho\u1EB7c paste URL", autoUpload: true, prefix: "questions" })), article.imageUrl && (_jsx(ArticleImagePreview, { src: article.imageUrl, alt: `Article ${letter} image` }))] })] })] }, index));
|
|
120
120
|
}), !isReadOnly && (_jsxs(Button, { type: "button", variant: "outline", className: "w-full border-dashed border-teal-300 bg-teal-50/50 text-teal-700 hover:bg-teal-50 hover:text-teal-800 hover:border-teal-400", onClick: handleAddArticle, children: [_jsx(PlusCircle, { className: "mr-2 h-4 w-4" }), "Th\u00EAm b\u00E0i vi\u1EBFt"] }))] })] }));
|
|
121
121
|
}
|
|
@@ -34,7 +34,7 @@ export function BasicQuestionGroupCard({ groupNumber, title, subtitle, content,
|
|
|
34
34
|
// Resolve presigned preview URL for the stored image key
|
|
35
35
|
const { previewUrl } = usePresignedFileUrl(imageUrl);
|
|
36
36
|
const displayPreviewUrl = previewUrl || '';
|
|
37
|
-
return (_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-
|
|
37
|
+
return (_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-sm", children: [_jsx(CardHeader, { className: "px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-gray-100", children: _jsx(Layers, { className: "h-3.5 w-3.5 text-gray-600" }) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-sm font-bold text-gray-900", children: "D\u1EEF li\u1EC7u nh\u00F3m" }), _jsxs("span", { className: "inline-flex items-center rounded-md border border-gray-200 bg-gray-50 px-2 py-0.5 text-xs font-semibold text-gray-600", children: ["Nh\u00F3m ", groupNumber] })] })] }) }), _jsxs(CardContent, { className: "space-y-2.5 px-3 pb-3", children: [showTitle && (_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { htmlFor: `${uploadIdPrefix}-title`, className: "flex items-center gap-2 text-sm font-semibold text-gray-800", children: [_jsx(Type, { className: "h-4 w-4 text-purple-500" }), "Ti\u00EAu \u0111\u1EC1 nh\u00F3m", ' ', _jsx("span", { className: "text-xs font-normal text-gray-500", children: "(T\u00F9y ch\u1ECDn)" })] }), _jsx(Input, { id: `${uploadIdPrefix}-title`, value: title, onChange: (e) => {
|
|
38
38
|
if (!isReadOnly)
|
|
39
39
|
onTitleChange(e.target.value);
|
|
40
40
|
}, readOnly: isReadOnly, placeholder: "Nh\u1EADp ti\u00EAu \u0111\u1EC1 nh\u00F3m c\u00E2u h\u1ECFi\u2026", className: `border-gray-200 bg-white transition-all focus:border-purple-300 focus:ring-purple-200 ${isReadOnly ? 'bg-gray-50 text-gray-500 cursor-not-allowed border-transparent focus:border-transparent focus:ring-0' : ''}` })] })), showSubtitle && (_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { htmlFor: `${uploadIdPrefix}-subtitle`, className: "flex items-center gap-2 text-sm font-semibold text-gray-800", children: [_jsx(Type, { className: "h-4 w-4 text-purple-500" }), "Ph\u1EE5 \u0111\u1EC1 nh\u00F3m", ' ', _jsx("span", { className: "text-xs font-normal text-gray-500", children: "(T\u00F9y ch\u1ECDn)" })] }), _jsx(Input, { id: `${uploadIdPrefix}-subtitle`, value: subtitle, onChange: (e) => {
|