@tinyweb_dev/oe-exam-sdk 0.1.1 → 0.1.2
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/api/exam-create.js +1 -179
- package/dist/api/exam-create.types.js +1 -1
- package/dist/api/exam-questions.js +1 -98
- package/dist/api/exam-questions.types.js +1 -1
- package/dist/api/exam-taking.js +1 -73
- package/dist/api/exam-taking.types.js +1 -1
- package/dist/api/index.js +1 -6
- package/dist/api/result-review.js +1 -50
- package/dist/api/result-review.types.js +1 -1
- package/dist/components/CueCardEditor.js +1 -58
- package/dist/components/common/ResolvedImage.js +1 -15
- package/dist/components/exams/CreateExamInfoForm.js +1 -35
- package/dist/components/exams/CreateExamPageContainer.js +1 -103
- package/dist/components/exams/ExamCreator.js +1 -89
- package/dist/components/exams/ExamPartTabs.js +1 -40
- package/dist/components/exams/ExamQuestionGrid.js +1 -18
- package/dist/components/exams/ExamQuestionsPageContainer.js +1 -90
- package/dist/components/exams/PartAudioUploader.js +1 -9
- package/dist/components/exams/TemplateSelector.js +1 -66
- package/dist/components/exams/api.js +1 -3
- package/dist/components/exams/create-exam.validation.js +1 -18
- package/dist/components/exams/exam-template.utils.js +1 -18
- package/dist/components/exams/index.js +1 -10
- package/dist/components/exams/take/ExamTakingPageContainer.js +1 -153
- package/dist/components/exams/take/GenericQuestionRenderer.js +1 -14
- package/dist/components/exams/take/exam-taking.utils.js +1 -88
- package/dist/components/exams/take/hooks/useSpeakingRecorder.js +1 -24
- package/dist/components/exams/take/index.js +1 -2
- package/dist/components/exams/take/types.js +1 -1
- package/dist/components/index.js +1 -42
- package/dist/components/questions/_shared/config/question-types.config.js +1 -333
- package/dist/components/questions/_shared/constants/color-palette.js +1 -21
- package/dist/components/questions/_shared/hooks/useAnswerGroupQuestionGroup.js +1 -105
- package/dist/components/questions/_shared/hooks/useBasicQuestionGroup.js +1 -222
- package/dist/components/questions/_shared/hooks/useCompareImagesGroup.js +1 -140
- package/dist/components/questions/_shared/hooks/useImageQuestionGroup.js +1 -123
- package/dist/components/questions/_shared/hooks/useInfoExchangeGroup.js +1 -50
- package/dist/components/questions/_shared/hooks/useQuestionFormState.js +1 -54
- package/dist/components/questions/_shared/hooks/useQuestionInitialization.js +1 -123
- package/dist/components/questions/_shared/hooks/useQuestionListGroup.js +1 -121
- package/dist/components/questions/_shared/hooks/useQuestionOnChange.js +1 -70
- package/dist/components/questions/_shared/hooks/useSceneQuestionGroup.js +1 -194
- package/dist/components/questions/_shared/index.js +1 -7
- package/dist/components/questions/_shared/types/answer-the-question.type.js +1 -1
- package/dist/components/questions/_shared/types/arrange-letters-into-words.type.js +1 -1
- package/dist/components/questions/_shared/types/choose-correct-adjective.type.js +1 -3
- package/dist/components/questions/_shared/types/color-region.config.js +1 -1
- package/dist/components/questions/_shared/types/fill-in-blank.type.js +1 -1
- package/dist/components/questions/_shared/types/fill-missing-words-in-grid.type.js +1 -1
- package/dist/components/questions/_shared/types/gn-speaking-interview.type.js +1 -1
- package/dist/components/questions/_shared/types/index.js +1 -12
- package/dist/components/questions/_shared/types/label-the-picture.type.js +1 -1
- package/dist/components/questions/_shared/types/listen-and-choose-from-answer-group.type.js +1 -1
- package/dist/components/questions/_shared/types/listen-and-choose-objects-in-scene.type.js +1 -1
- package/dist/components/questions/_shared/types/listen-and-drag-objects-into-scene.type.js +1 -1
- package/dist/components/questions/_shared/types/listen-and-speak-answer.type.js +1 -1
- package/dist/components/questions/_shared/types/listen-and-speak-compare-images.type.js +1 -1
- package/dist/components/questions/_shared/types/listen-and-speak-image-group.type.js +1 -1
- package/dist/components/questions/_shared/types/listen-and-speak-info-exchange.type.js +1 -1
- package/dist/components/questions/_shared/types/listen-and-speak-odd-one-out.type.js +1 -3
- package/dist/components/questions/_shared/types/listen-and-speak-question-list.type.js +1 -1
- package/dist/components/questions/_shared/types/listen-and-speak-with-story-images.type.js +1 -3
- package/dist/components/questions/_shared/types/listen-and-tick-answer.type.js +1 -1
- package/dist/components/questions/_shared/types/listening-drawline.type.js +1 -1
- package/dist/components/questions/_shared/types/look-and-choose-answer.type.js +1 -1
- package/dist/components/questions/_shared/types/look-picture-fill-word-hint.type.js +1 -1
- package/dist/components/questions/_shared/types/match-by-writing-answer.type.js +1 -1
- package/dist/components/questions/_shared/types/multiple-choice.type.js +1 -1
- package/dist/components/questions/_shared/types/question-group.type.js +1 -11
- package/dist/components/questions/_shared/types/read-and-color-objects.type.js +1 -1
- package/dist/components/questions/_shared/types/read-displayed-content.type.js +1 -1
- package/dist/components/questions/_shared/types/read-passage-and-answer-questions.type.js +1 -1
- package/dist/components/questions/_shared/types/speaking-describe-image.type.js +1 -1
- package/dist/components/questions/_shared/types/spontaneous-qa.type.js +1 -1
- package/dist/components/questions/_shared/types/word-fill-paragraph-with-options.type.js +1 -1
- package/dist/components/questions/_shared/types/word-fill-paragraph.type.js +1 -1
- package/dist/components/questions/_shared/types/word-fill-structured-form.type.js +1 -1
- package/dist/components/questions/_shared/types/word-ordering.type.js +1 -1
- package/dist/components/questions/_shared/types/write-a-short-letter.type.js +1 -1
- package/dist/components/questions/_shared/types/write-correct-verb-form.type.js +1 -3
- package/dist/components/questions/_shared/types/write-sentences.type.js +1 -1
- package/dist/components/questions/_shared/types/write-short-paragraph.type.js +1 -1
- package/dist/components/questions/_shared/utils/answer-builder.js +1 -79
- package/dist/components/questions/_shared/utils/createColorRegionRegistration.js +1 -39
- package/dist/components/questions/_shared/utils/id-generator.js +1 -3
- package/dist/components/questions/_shared/utils/question-validation.js +1 -21
- package/dist/components/questions/components/ColorNode.js +1 -85
- package/dist/components/questions/components/ColorRegionClient.js +1 -545
- package/dist/components/questions/components/ColorRegionCreator.js +1 -420
- package/dist/components/questions/components/ColorRegionNode.js +1 -59
- package/dist/components/questions/components/CreatorGuide.js +1 -103
- package/dist/components/questions/components/NameNode.js +1 -26
- package/dist/components/questions/components/QuestionBankOption.js +1 -46
- package/dist/components/questions/components/QuestionBasicInfoForm.js +1 -9
- package/dist/components/questions/components/QuestionCommonFields.js +1 -33
- package/dist/components/questions/components/QuestionSearchDropdown.js +1 -258
- package/dist/components/questions/components/QuestionTypeSelector.js +1 -32
- package/dist/components/questions/components/QuestionTypeSpecificForms.js +1 -6
- package/dist/components/questions/components/RegionNode.js +1 -94
- package/dist/components/questions/components/index.js +1 -14
- package/dist/components/questions/creator/QuestionCreator.js +1 -90
- package/dist/components/questions/creator/QuestionGroupCreator.js +1 -119
- package/dist/components/questions/creator/dedicated-component-router.js +1 -79
- package/dist/components/questions/creator/index.js +1 -3
- package/dist/components/questions/creator/question-type-registry.js +1 -80
- package/dist/components/questions/groups/ArticlesGroupCard.js +1 -121
- package/dist/components/questions/groups/BasicQuestionGroupCard.js +1 -50
- package/dist/components/questions/groups/DocumentGroupCard.js +1 -114
- package/dist/components/questions/groups/MatchAnswerGroupCard.js +1 -25
- package/dist/components/questions/index.js +1 -10
- package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +1 -37
- package/dist/components/questions/types/answer-the-question/AnswerTheQuestionCreator.js +1 -351
- package/dist/components/questions/types/answer-the-question/register.js +1 -67
- package/dist/components/questions/types/answer-the-question/transform.js +1 -36
- package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +1 -141
- package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsCreator.js +1 -118
- package/dist/components/questions/types/arrange-letters-into-words/index.js +1 -2
- package/dist/components/questions/types/arrange-letters-into-words/register.js +1 -4
- package/dist/components/questions/types/arrange-letters-into-words/transform.js +1 -24
- package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +1 -64
- package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js +1 -169
- package/dist/components/questions/types/choose-correct-adjective/index.js +1 -2
- package/dist/components/questions/types/choose-correct-adjective/register.js +1 -55
- package/dist/components/questions/types/choose-correct-adjective/transform.js +1 -16
- package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +1 -131
- package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +1 -581
- package/dist/components/questions/types/choose-the-correct-answer/index.js +1 -2
- package/dist/components/questions/types/choose-the-correct-answer/register.js +1 -101
- package/dist/components/questions/types/choose-the-correct-answer/transform.js +1 -43
- package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +1 -275
- package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +1 -448
- package/dist/components/questions/types/fill-in-blank/index.js +1 -2
- package/dist/components/questions/types/fill-in-blank/register.js +1 -138
- package/dist/components/questions/types/fill-in-blank/transform.js +1 -59
- package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +1 -117
- package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridCreator.js +1 -671
- package/dist/components/questions/types/fill-missing-words-in-grid/index.js +1 -2
- package/dist/components/questions/types/fill-missing-words-in-grid/register.js +1 -37
- package/dist/components/questions/types/fill-missing-words-in-grid/transform.js +1 -15
- package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.js +1 -262
- package/dist/components/questions/types/gn-speaking-interview/register.js +1 -121
- package/dist/components/questions/types/gn-speaking-interview/transform.js +1 -48
- package/dist/components/questions/types/image-object-matching/ImageObjectMatchingClient.js +1 -16
- package/dist/components/questions/types/image-object-matching/ImageObjectMatchingCreator.js +1 -27
- package/dist/components/questions/types/image-object-matching/index.js +1 -2
- package/dist/components/questions/types/image-object-matching/register.js +1 -3
- package/dist/components/questions/types/image-object-matching/transform.js +1 -2
- package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +1 -102
- package/dist/components/questions/types/label-the-picture/LabelThePictureCreator.js +1 -344
- package/dist/components/questions/types/label-the-picture/index.js +1 -2
- package/dist/components/questions/types/label-the-picture/register.js +1 -54
- package/dist/components/questions/types/label-the-picture/transform.js +1 -28
- package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +1 -78
- package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupCreator.js +1 -232
- package/dist/components/questions/types/listen-and-choose-from-answer-group/index.js +1 -2
- package/dist/components/questions/types/listen-and-choose-from-answer-group/register.js +1 -82
- package/dist/components/questions/types/listen-and-choose-from-answer-group/transform.js +1 -27
- package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneClient.js +1 -70
- package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneCreator.js +1 -386
- package/dist/components/questions/types/listen-and-choose-objects-in-scene/index.js +1 -2
- package/dist/components/questions/types/listen-and-choose-objects-in-scene/register.js +1 -100
- package/dist/components/questions/types/listen-and-choose-objects-in-scene/transform.js +1 -33
- package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneClient.js +1 -106
- package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneCreator.js +1 -457
- package/dist/components/questions/types/listen-and-drag-objects-into-scene/index.js +1 -2
- package/dist/components/questions/types/listen-and-drag-objects-into-scene/register.js +1 -110
- package/dist/components/questions/types/listen-and-drag-objects-into-scene/transform.js +1 -35
- package/dist/components/questions/types/listen-and-speak-answer/ArrowIndicator.js +1 -8
- package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +1 -22
- package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerCreator.js +1 -291
- package/dist/components/questions/types/listen-and-speak-answer/index.js +1 -2
- package/dist/components/questions/types/listen-and-speak-answer/register.js +1 -84
- package/dist/components/questions/types/listen-and-speak-answer/transform.js +1 -27
- package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +1 -32
- package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesCreator.js +1 -295
- package/dist/components/questions/types/listen-and-speak-compare-images/register.js +1 -79
- package/dist/components/questions/types/listen-and-speak-compare-images/transform.js +1 -27
- package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +1 -34
- package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupCreator.js +1 -285
- package/dist/components/questions/types/listen-and-speak-image-group/register.js +1 -81
- package/dist/components/questions/types/listen-and-speak-image-group/transform.js +1 -26
- package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +1 -38
- package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeCreator.js +1 -385
- package/dist/components/questions/types/listen-and-speak-info-exchange/register.js +1 -87
- package/dist/components/questions/types/listen-and-speak-info-exchange/transform.js +1 -32
- package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +1 -26
- package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutCreator.js +1 -247
- package/dist/components/questions/types/listen-and-speak-odd-one-out/register.js +1 -59
- package/dist/components/questions/types/listen-and-speak-odd-one-out/transform.js +1 -18
- package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +1 -26
- package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListCreator.js +1 -256
- package/dist/components/questions/types/listen-and-speak-question-list/register.js +1 -81
- package/dist/components/questions/types/listen-and-speak-question-list/transform.js +1 -26
- package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +1 -26
- package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesCreator.js +1 -230
- package/dist/components/questions/types/listen-and-speak-with-story-images/register.js +1 -56
- package/dist/components/questions/types/listen-and-speak-with-story-images/transform.js +1 -16
- package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.js +1 -72
- package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.js +1 -230
- package/dist/components/questions/types/look-picture-choose-correct-answer/index.js +1 -1
- package/dist/components/questions/types/look-picture-choose-correct-answer/register.js +1 -66
- package/dist/components/questions/types/look-picture-choose-correct-answer/transform.js +1 -42
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.js +1 -96
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.js +1 -238
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.js +1 -2
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.js +1 -76
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.js +1 -19
- package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.js +1 -134
- package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.js +1 -617
- package/dist/components/questions/types/look-picture-fill-word-hint/index.js +1 -2
- package/dist/components/questions/types/look-picture-fill-word-hint/register.js +1 -82
- package/dist/components/questions/types/look-picture-fill-word-hint/transform.js +1 -29
- package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +1 -38
- package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerCreator.js +1 -359
- package/dist/components/questions/types/match-by-writing-answer/index.js +1 -3
- package/dist/components/questions/types/match-by-writing-answer/register.js +1 -58
- package/dist/components/questions/types/match-by-writing-answer/transform.js +1 -61
- package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsClient.js +1 -16
- package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsCreator.js +1 -23
- package/dist/components/questions/types/read-and-color-objects/index.js +1 -2
- package/dist/components/questions/types/read-and-color-objects/register.js +1 -3
- package/dist/components/questions/types/read-and-color-objects/transform.js +1 -36
- package/dist/components/questions/types/read-displayed-content/ReadDisplayedContentCreator.js +1 -125
- package/dist/components/questions/types/read-displayed-content/register.js +1 -64
- package/dist/components/questions/types/read-displayed-content/transform.js +1 -12
- package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +1 -64
- package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsCreator.js +1 -511
- package/dist/components/questions/types/read-passage-and-answer-questions/index.js +1 -2
- package/dist/components/questions/types/read-passage-and-answer-questions/register.js +1 -58
- package/dist/components/questions/types/read-passage-and-answer-questions/transform.js +1 -28
- package/dist/components/questions/types/speaking-conversation/SpeakingConversationCreator.js +1 -373
- package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +1 -41
- package/dist/components/questions/types/speaking-conversation/register.js +1 -110
- package/dist/components/questions/types/speaking-conversation/transform.js +1 -34
- package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +1 -74
- package/dist/components/questions/types/speaking-cue-card/register.js +1 -52
- package/dist/components/questions/types/speaking-cue-card/transform.js +1 -12
- package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +1 -10
- package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageCreator.js +1 -161
- package/dist/components/questions/types/speaking-describe-image/index.js +1 -2
- package/dist/components/questions/types/speaking-describe-image/register.js +1 -69
- package/dist/components/questions/types/speaking-describe-image/transform.js +1 -16
- package/dist/components/questions/types/spontaneous-qa/SpontaneousQACreator.js +1 -234
- package/dist/components/questions/types/spontaneous-qa/register.js +1 -93
- package/dist/components/questions/types/spontaneous-qa/transform.js +1 -34
- package/dist/components/questions/types/true-false/TrueFalseClient.js +1 -75
- package/dist/components/questions/types/true-false/TrueFalseCreator.js +1 -244
- package/dist/components/questions/types/true-false/index.js +1 -2
- package/dist/components/questions/types/true-false/register.js +1 -77
- package/dist/components/questions/types/true-false/transform.js +1 -32
- package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +1 -233
- package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphCreator.js +1 -631
- package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphWrapper.js +1 -28
- package/dist/components/questions/types/word-fill-paragraph/index.js +1 -2
- package/dist/components/questions/types/word-fill-paragraph/register.js +1 -136
- package/dist/components/questions/types/word-fill-paragraph/transform.js +1 -56
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +1 -138
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +1 -261
- package/dist/components/questions/types/word-fill-structured-form/index.js +1 -2
- package/dist/components/questions/types/word-fill-structured-form/register.js +1 -67
- package/dist/components/questions/types/word-fill-structured-form/transform.js +1 -40
- package/dist/components/questions/types/word-ordering/WordOrderingClient.js +1 -84
- package/dist/components/questions/types/word-ordering/WordOrderingCreator.js +1 -192
- package/dist/components/questions/types/word-ordering/index.js +1 -2
- package/dist/components/questions/types/word-ordering/register.js +1 -46
- package/dist/components/questions/types/word-ordering/transform.js +1 -24
- package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +1 -98
- package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +1 -320
- package/dist/components/questions/types/write-a-short-letter/index.js +1 -2
- package/dist/components/questions/types/write-a-short-letter/register.js +1 -68
- package/dist/components/questions/types/write-a-short-letter/transform.js +1 -25
- package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +1 -61
- package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js +1 -196
- package/dist/components/questions/types/write-correct-verb-form/index.js +1 -2
- package/dist/components/questions/types/write-correct-verb-form/register.js +1 -62
- package/dist/components/questions/types/write-correct-verb-form/transform.js +1 -17
- package/dist/components/questions/types/write-sentences/WriteSentencesClient.js +1 -22
- package/dist/components/questions/types/write-sentences/WriteSentencesCreator.js +1 -174
- package/dist/components/questions/types/write-sentences/index.js +1 -2
- package/dist/components/questions/types/write-sentences/register.js +1 -58
- package/dist/components/questions/types/write-sentences/transform.js +1 -28
- package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphClient.js +1 -96
- package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphCreator.js +1 -161
- package/dist/components/questions/types/write-short-paragraph/index.js +1 -2
- package/dist/components/questions/types/write-short-paragraph/register.js +1 -4
- package/dist/components/questions/types/write-short-paragraph/transform.js +1 -21
- package/dist/components/questions/viewer/QuestionGroupViewer.js +1 -36
- package/dist/components/questions/viewer/QuestionViewer.js +1 -446
- package/dist/components/questions/viewer/index.js +1 -2
- package/dist/components/results/ResultReviewPageContainer.js +1 -98
- package/dist/components/results/ReviewQuestionRenderer.js +1 -72
- package/dist/components/results/index.js +1 -2
- package/dist/components/results/result-review.utils.js +1 -6
- package/dist/components/results/review-data.js +1 -150
- package/dist/components/results/review-renderer.utils.js +1 -97
- package/dist/components/results/review-types.js +1 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleAudioPlayer.js +1 -138
- package/dist/components/themes/cambridge-yle/CambridgeYleBottomNav.js +1 -12
- package/dist/components/themes/cambridge-yle/CambridgeYleExamLayout.js +1 -18
- package/dist/components/themes/cambridge-yle/CambridgeYleExampleText.js +1 -11
- package/dist/components/themes/cambridge-yle/CambridgeYleHeader.js +1 -11
- package/dist/components/themes/cambridge-yle/CambridgeYleInstructionBanner.js +1 -9
- package/dist/components/themes/cambridge-yle/CambridgeYleNavButton.js +1 -13
- package/dist/components/themes/cambridge-yle/CambridgeYlePartBanner.js +1 -8
- package/dist/components/themes/cambridge-yle/CambridgeYleProgressBar.js +1 -6
- package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCard.js +1 -5
- package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCardFullWidth.js +1 -9
- package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.js +1 -41
- package/dist/components/themes/cambridge-yle/CambridgeYleTimer.js +1 -25
- package/dist/components/themes/cambridge-yle/index.js +1 -13
- package/dist/components/themes/english-certification/EcAnswerTheQuestion.js +1 -24
- package/dist/components/themes/english-certification/EcMatchByWritingAnswer.js +1 -88
- package/dist/components/themes/english-certification/EcWordFillParagraph.js +1 -55
- package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +1 -156
- package/dist/components/themes/english-certification/EcWritingTask.js +1 -34
- package/dist/components/themes/english-certification/EnglishCertificationAudioPlayer.js +1 -114
- package/dist/components/themes/english-certification/EnglishCertificationBrand.js +1 -11
- package/dist/components/themes/english-certification/EnglishCertificationExamLayout.js +1 -21
- package/dist/components/themes/english-certification/EnglishCertificationFlagButton.js +1 -15
- package/dist/components/themes/english-certification/EnglishCertificationFooterBar.js +1 -19
- package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.js +1 -148
- package/dist/components/themes/english-certification/EnglishCertificationHeader.js +1 -31
- package/dist/components/themes/english-certification/EnglishCertificationNavigationPanel.js +1 -71
- package/dist/components/themes/english-certification/EnglishCertificationOptionSelector.js +1 -33
- package/dist/components/themes/english-certification/EnglishCertificationPassagePanel.js +1 -16
- package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.js +1 -22
- package/dist/components/themes/english-certification/EnglishCertificationQuestionItem.js +1 -37
- package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -72
- package/dist/components/themes/english-certification/EnglishCertificationReadingSection.js +1 -90
- package/dist/components/themes/english-certification/EnglishCertificationSingleQuestion.js +1 -18
- package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js +1 -29
- package/dist/components/themes/english-certification/english-certification-theme.js +1 -58
- package/dist/components/themes/english-certification/grouped-question-utils.js +1 -218
- package/dist/components/themes/english-certification/index.js +1 -21
- package/dist/components/themes/index.js +1 -6
- package/dist/components/themes/summer-sky/SummerSkyAudioPlayer.js +1 -170
- package/dist/components/themes/summer-sky/SummerSkyLayout.js +1 -221
- package/dist/components/themes/summer-sky/SummerSkySubmitModal.js +1 -18
- package/dist/components/themes/summer-sky/SummerSkyWaitingRoom.js +1 -194
- package/dist/components/themes/types.js +1 -1
- package/dist/components/ui/alert-dialog.js +1 -26
- package/dist/components/ui/alert.js +1 -22
- package/dist/components/ui/avatar.js +1 -12
- package/dist/components/ui/badge.js +1 -38
- package/dist/components/ui/button.js +1 -35
- package/dist/components/ui/calendar.js +1 -76
- package/dist/components/ui/card.js +1 -16
- package/dist/components/ui/carousel.js +1 -91
- package/dist/components/ui/checkbox.js +1 -9
- package/dist/components/ui/collapsible.js +1 -13
- package/dist/components/ui/command.js +1 -34
- package/dist/components/ui/confirm-dialog.js +1 -49
- package/dist/components/ui/dialog.js +1 -23
- package/dist/components/ui/drawer.js +1 -35
- package/dist/components/ui/dropdown-menu.js +1 -33
- package/dist/components/ui/file-upload.js +1 -155
- package/dist/components/ui/form.js +1 -62
- package/dist/components/ui/hover-card.js +1 -10
- package/dist/components/ui/image-preview.js +1 -29
- package/dist/components/ui/input.js +1 -8
- package/dist/components/ui/label.js +1 -9
- package/dist/components/ui/language-switcher.js +1 -15
- package/dist/components/ui/multi-select.js +1 -90
- package/dist/components/ui/points-input.js +1 -33
- package/dist/components/ui/popover.js +1 -26
- package/dist/components/ui/progress.js +1 -16
- package/dist/components/ui/radio-group.js +1 -12
- package/dist/components/ui/scroll-area.js +1 -11
- package/dist/components/ui/select.js +1 -38
- package/dist/components/ui/separator.js +1 -8
- package/dist/components/ui/sheet.js +1 -40
- package/dist/components/ui/single-select.js +1 -76
- package/dist/components/ui/skeleton.js +1 -6
- package/dist/components/ui/switch.js +1 -8
- package/dist/components/ui/table.js +1 -20
- package/dist/components/ui/tabs.js +1 -17
- package/dist/components/ui/textarea.js +1 -8
- package/dist/components/ui/tooltip.js +1 -11
- package/dist/index.js +1 -19
- package/dist/mcp/config.js +1 -32
- package/dist/mcp/http-client.js +1 -48
- package/dist/mcp/index.js +1 -29
- package/dist/mcp/tools/_helpers.js +1 -25
- package/dist/mcp/tools/exams.js +1 -439
- package/dist/mcp/tools/index.js +1 -6
- package/dist/mcp/tools/results.js +1 -19
- package/dist/shared/constants/ApiConstant.js +1 -276
- package/dist/shared/constants/QueryKeyConstant.js +1 -112
- package/dist/shared/constants/exam-level.enum.js +1 -41
- package/dist/shared/constants/landings/placement-test.constants.js +1 -431
- package/dist/shared/constants/question-skills.js +1 -267
- package/dist/shared/constants/routes.js +1 -81
- package/dist/shared/index.js +1 -7
- package/dist/shared/lib/hooks/index.js +1 -10
- package/dist/shared/lib/hooks/useAlertDialog.js +1 -57
- package/dist/shared/lib/hooks/useAudioPlayCounter.js +1 -30
- package/dist/shared/lib/hooks/useAudioPreview.js +1 -81
- package/dist/shared/lib/hooks/useAudioUpload.js +1 -24
- package/dist/shared/lib/hooks/useConfirmDialog.js +1 -89
- package/dist/shared/lib/hooks/useDebouncedCallback.js +1 -32
- package/dist/shared/lib/hooks/useDelayedAutoPlay.js +1 -12
- package/dist/shared/lib/hooks/useFileUpload.js +1 -24
- package/dist/shared/lib/hooks/useImageUrl.js +1 -5
- package/dist/shared/lib/hooks/usePresignedFileUrl.js +1 -10
- package/dist/shared/lib/hooks/useReactHookForm.js +1 -31
- package/dist/shared/lib/hooks/useToast.js +1 -62
- package/dist/shared/lib/i18n/index.js +1 -54
- package/dist/shared/lib/i18n/messages/en/admin.js +1 -2104
- package/dist/shared/lib/i18n/messages/en/auth.js +1 -86
- package/dist/shared/lib/i18n/messages/en/common.js +1 -140
- package/dist/shared/lib/i18n/messages/en/file-upload.js +1 -18
- package/dist/shared/lib/i18n/messages/en/student.js +1 -133
- package/dist/shared/lib/i18n/messages/en/terms.js +1 -37
- package/dist/shared/lib/i18n/messages/en.js +1 -15
- package/dist/shared/lib/i18n/messages/vi/admin.js +1 -2104
- package/dist/shared/lib/i18n/messages/vi/auth.js +1 -86
- package/dist/shared/lib/i18n/messages/vi/common.js +1 -140
- package/dist/shared/lib/i18n/messages/vi/file-upload.js +1 -18
- package/dist/shared/lib/i18n/messages/vi/student.js +1 -133
- package/dist/shared/lib/i18n/messages/vi/terms.js +1 -37
- package/dist/shared/lib/i18n/messages/vi.js +1 -15
- package/dist/shared/lib/i18n/types.js +1 -1
- package/dist/shared/lib/stores/examQuestionStore.js +1 -212
- package/dist/shared/lib/stores/localeStore.js +1 -10
- package/dist/shared/lib/utils/public-page.js +1 -44
- package/dist/shared/lib/utils/question-transform-types.js +1 -1
- package/dist/shared/lib/utils/question-transform.js +1 -174
- package/dist/shared/lib/utils.js +1 -168
- package/dist/shared/lib/validation/choose-correct-answer.validation.js +1 -111
- package/dist/shared/lib/validation/label-the-picture.validation.js +1 -19
- package/dist/shared/lib/validation/listen-and-choose-from-answer-group.validation.js +1 -46
- package/dist/shared/lib/validation/listen-and-choose-objects-in-scene.validation.js +1 -21
- package/dist/shared/lib/validation/listen-and-drag-objects-into-scene.validation.js +1 -34
- package/dist/shared/lib/validation/listen-and-speak-answer.validation.js +1 -40
- package/dist/shared/lib/validation/listen-and-speak-compare-images.validation.js +1 -45
- package/dist/shared/lib/validation/listen-and-speak-image-group.validation.js +1 -19
- package/dist/shared/lib/validation/listen-and-speak-info-exchange.validation.js +1 -39
- package/dist/shared/lib/validation/listen-and-speak-odd-one-out.validation.js +1 -32
- package/dist/shared/lib/validation/listen-and-speak-question-list.validation.js +1 -19
- package/dist/shared/lib/validation/listen-and-speak-with-story-images.validation.js +1 -28
- package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.js +1 -12
- package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.js +1 -47
- package/dist/shared/lib/validation/read-and-color-objects.validation.js +1 -29
- package/dist/shared/lib/validation/read-displayed-content.validation.js +1 -28
- package/dist/shared/lib/validation/speaking-conversation.validation.js +1 -75
- package/dist/shared/lib/validation/speaking-describe-image.validation.js +1 -31
- package/dist/shared/lib/validation/spontaneous-qa.validation.js +1 -48
- package/dist/shared/lib/validation/word-fill-paragraph-default.validation.js +1 -38
- package/dist/shared/lib/validation/word-fill-paragraph-with-options.validation.js +1 -39
- package/dist/shared/lib/validation/word-fill-paragraph.validation.js +1 -43
- package/dist/shared/lib/validation/word-ordering.validation.js +1 -33
- package/dist/shared/types/branch.types.js +1 -6
- package/dist/shared/types/common.types.js +1 -50
- package/dist/shared/types/entities/exam-schedule.types.js +1 -5
- package/dist/shared/types/entities/exam.types.js +1 -1
- package/dist/shared/types/entities/question.types.js +1 -4
- package/dist/shared/types/entities/result.types.js +1 -4
- package/dist/shared/types/entities/user.types.js +1 -4
- package/dist/shared/types/exam-taking.types.js +1 -2
- package/dist/shared/types/history.types.js +1 -34
- package/dist/shared/types/index.js +1 -1
- package/dist/shared/types/questions/choose-correct-adjective.js +1 -4
- package/dist/shared/types/questions/choose-the-correct-answer.js +1 -9
- package/dist/shared/types/questions/fill-missing-words-in-grid.js +1 -11
- package/dist/shared/types/questions/index.js +1 -40
- package/dist/shared/types/questions/listen-and-speak-answer.js +1 -1
- package/dist/shared/types/questions/listen-and-speak-compare-images.js +1 -1
- package/dist/shared/types/questions/listen-and-speak-image-group.js +1 -1
- package/dist/shared/types/questions/listen-and-speak-info-exchange.js +1 -3
- package/dist/shared/types/questions/listen-and-speak-odd-one-out.js +1 -3
- package/dist/shared/types/questions/listen-and-speak-question-list.js +1 -1
- package/dist/shared/types/questions/listen-and-speak-with-story-images.js +1 -3
- package/dist/shared/types/questions/look-picture-choose-correct-answer.js +1 -5
- package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.js +1 -9
- package/dist/shared/types/questions/look-picture-fill-word-hint.js +1 -7
- package/dist/shared/types/questions/read-displayed-content.js +1 -1
- package/dist/shared/types/questions/speaking-conversation.js +1 -7
- package/dist/shared/types/questions/speaking-describe-image.js +1 -1
- package/dist/shared/types/questions/spontaneous-qa.js +1 -1
- package/dist/shared/types/questions/write-correct-verb-form.js +1 -12
- package/dist/shared/types/role.types.js +1 -1
- package/dist/shared/types/structure-management.js +1 -28
- package/dist/shared/types/student.types.js +1 -54
- package/dist/shared/types/teacher-dashboard-rooms.js +1 -2
- package/package.json +4 -2
package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js
CHANGED
|
@@ -1,169 +1 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useRef, useEffect } from 'react';
|
|
4
|
-
import { Button } from '../../../../components/ui/button';
|
|
5
|
-
import { Label } from '../../../../components/ui/label';
|
|
6
|
-
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
|
-
import { RadioGroup } from '../../../../components/ui/radio-group';
|
|
11
|
-
import { toast } from 'sonner';
|
|
12
|
-
import { Pencil, Eye, Plus, Trash2, Lightbulb, CheckCircle2, MessageSquare, Type, BookOpen } from 'lucide-react';
|
|
13
|
-
import { useDebouncedCallback } from '../../../../shared/lib/hooks';
|
|
14
|
-
import { ChooseCorrectAdjectiveClient } from './ChooseCorrectAdjectiveClient';
|
|
15
|
-
function ChooseCorrectAdjectiveCreatorContent({ initialData, onSave, onCancel, onChange, externalErrors, optionCount = 3, }) {
|
|
16
|
-
// ============ STATE ============
|
|
17
|
-
const [sentence, setSentence] = useState(initialData?.sentence || '');
|
|
18
|
-
const [options, setOptions] = useState(initialData?.options && initialData.options.length > 0
|
|
19
|
-
? initialData.options
|
|
20
|
-
: Array.from({ length: optionCount }, () => ''));
|
|
21
|
-
const [correctAnswer, setCorrectAnswer] = useState(initialData?.correctAnswer ?? -1);
|
|
22
|
-
const [explanation, setExplanation] = useState(initialData?.explanation || '');
|
|
23
|
-
const [points, setPoints] = useState(initialData?.points || 1);
|
|
24
|
-
// UI State
|
|
25
|
-
const [isClientMode, setIsClientMode] = useState(false);
|
|
26
|
-
// Refs for initialization tracking
|
|
27
|
-
const previousInitialDataRef = useRef(initialData);
|
|
28
|
-
const isInitializingRef = useRef(false);
|
|
29
|
-
const onChangeRef = useRef(onChange);
|
|
30
|
-
const previousPayloadRef = useRef('');
|
|
31
|
-
// Update onChange ref when it changes
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
onChangeRef.current = onChange;
|
|
34
|
-
}, [onChange]);
|
|
35
|
-
// Debounced onChange callback
|
|
36
|
-
const debouncedOnChange = useDebouncedCallback((data) => {
|
|
37
|
-
onChangeRef.current?.(data);
|
|
38
|
-
}, 300);
|
|
39
|
-
// ============ SYNC INITIAL DATA ============
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
const initialDataChanged = JSON.stringify(previousInitialDataRef.current) !== JSON.stringify(initialData);
|
|
42
|
-
if (initialDataChanged) {
|
|
43
|
-
isInitializingRef.current = true;
|
|
44
|
-
previousInitialDataRef.current = initialData;
|
|
45
|
-
// Reset to initial data values, or defaults if initialData is empty/undefined (new question)
|
|
46
|
-
setSentence(initialData?.sentence || '');
|
|
47
|
-
setOptions(initialData?.options && initialData.options.length > 0
|
|
48
|
-
? initialData.options
|
|
49
|
-
: Array.from({ length: optionCount }, () => ''));
|
|
50
|
-
setCorrectAnswer(initialData?.correctAnswer ?? -1);
|
|
51
|
-
setExplanation(initialData?.explanation || '');
|
|
52
|
-
setPoints(initialData?.points || 1);
|
|
53
|
-
setTimeout(() => {
|
|
54
|
-
isInitializingRef.current = false;
|
|
55
|
-
}, 150);
|
|
56
|
-
}
|
|
57
|
-
}, [initialData, optionCount]);
|
|
58
|
-
// ============ ON CHANGE CALLBACK ============
|
|
59
|
-
// NOTE: We stringify options for proper change detection since array reference doesn't change
|
|
60
|
-
const optionsString = JSON.stringify(options);
|
|
61
|
-
useEffect(() => {
|
|
62
|
-
const payload = {
|
|
63
|
-
sentence,
|
|
64
|
-
options,
|
|
65
|
-
correctAnswer,
|
|
66
|
-
explanation,
|
|
67
|
-
points,
|
|
68
|
-
};
|
|
69
|
-
const payloadString = JSON.stringify(payload);
|
|
70
|
-
// Skip if payload hasn't changed OR if we're still in initial mount
|
|
71
|
-
// Only skip onChange if the payload is the SAME as before (duplicate prevention)
|
|
72
|
-
// This allows user changes even during initialization window
|
|
73
|
-
if (previousPayloadRef.current === payloadString) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
// If we're initializing, just update the ref but don't trigger onChange
|
|
77
|
-
// This prevents the initial data load from triggering unsaved changes
|
|
78
|
-
if (isInitializingRef.current) {
|
|
79
|
-
previousPayloadRef.current = payloadString;
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
previousPayloadRef.current = payloadString;
|
|
83
|
-
debouncedOnChange(payload);
|
|
84
|
-
}, [sentence, optionsString, correctAnswer, explanation, points]);
|
|
85
|
-
// ============ VALIDATION ============
|
|
86
|
-
const isValid = () => {
|
|
87
|
-
if (!sentence.trim() || !sentence.includes('{0}')) {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
if (options.filter((o) => o.trim()).length < 2) {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
if (correctAnswer < 0 || correctAnswer >= options.length) {
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
return true;
|
|
97
|
-
};
|
|
98
|
-
// Handle option change
|
|
99
|
-
const handleOptionChange = (index, value) => {
|
|
100
|
-
const newOptions = [...options];
|
|
101
|
-
newOptions[index] = value;
|
|
102
|
-
setOptions(newOptions);
|
|
103
|
-
};
|
|
104
|
-
// Handle add option
|
|
105
|
-
const handleAddOption = () => {
|
|
106
|
-
setOptions([...options, '']);
|
|
107
|
-
};
|
|
108
|
-
// Handle delete option
|
|
109
|
-
const handleDeleteOption = (index) => {
|
|
110
|
-
const newOptions = options.filter((_, i) => i !== index);
|
|
111
|
-
setOptions(newOptions);
|
|
112
|
-
// Adjust correctAnswer if needed
|
|
113
|
-
if (correctAnswer === index) {
|
|
114
|
-
setCorrectAnswer(-1);
|
|
115
|
-
}
|
|
116
|
-
else if (correctAnswer > index) {
|
|
117
|
-
setCorrectAnswer(correctAnswer - 1);
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
// Handle save
|
|
121
|
-
const handleSave = () => {
|
|
122
|
-
if (!sentence.trim()) {
|
|
123
|
-
toast.error('Vui lòng nhập câu hỏi!');
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
if (!sentence.includes('{0}')) {
|
|
127
|
-
toast.error('Câu hỏi phải có chỗ trống {0}!');
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
if (options.filter((o) => o.trim()).length < 2) {
|
|
131
|
-
toast.error('Vui lòng nhập ít nhất 2 đáp án!');
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
if (correctAnswer < 0 || correctAnswer >= options.length) {
|
|
135
|
-
toast.error('Vui lòng chọn đáp án đúng!');
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
onSave?.({
|
|
139
|
-
sentence,
|
|
140
|
-
options,
|
|
141
|
-
correctAnswer,
|
|
142
|
-
explanation,
|
|
143
|
-
points,
|
|
144
|
-
});
|
|
145
|
-
};
|
|
146
|
-
// ============ CLIENT MODE PREVIEW ============
|
|
147
|
-
if (isClientMode) {
|
|
148
|
-
const questionData = {
|
|
149
|
-
sentence,
|
|
150
|
-
options,
|
|
151
|
-
correctAnswer,
|
|
152
|
-
explanation,
|
|
153
|
-
};
|
|
154
|
-
return (_jsxs("div", { className: "space-y-6", children: [_jsx(Card, { children: _jsx(CardHeader, { children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx(CardTitle, { children: "Choose the correct adjective (Preview)" }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setIsClientMode(false), children: [_jsx(Pencil, { className: "mr-2 h-4 w-4" }), "Quay l\u1EA1i Edit Mode"] })] }) }) }), _jsx(ChooseCorrectAdjectiveClient, { questionData: questionData, isReviewMode: true, userAnswer: correctAnswer !== -1 ? correctAnswer : undefined })] }));
|
|
155
|
-
}
|
|
156
|
-
// ============ CREATOR UI ============
|
|
157
|
-
return (_jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-purple-100/50", children: [_jsx("div", { className: "h-1.5 bg-gradient-to-r from-purple-500 via-violet-500 to-indigo-500" }), _jsx(CardHeader, { className: "pb-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-purple-500 to-violet-600 shadow-md", children: _jsx(Type, { className: "h-5 w-5 text-white" }) }), _jsxs("div", { children: [_jsx(CardTitle, { className: "text-xl font-bold text-gray-900", children: "Ch\u1ECDn t\u00EDnh t\u1EEB \u0111\u00FAng" }), _jsx("p", { className: "text-sm text-gray-500", children: "Ch\u1ECDn d\u1EA1ng \u0111\u00FAng c\u1EE7a t\u00EDnh t\u1EEB \u0111\u1EC3 ho\u00E0n th\u00E0nh c\u00E2u" })] })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => setIsClientMode(true), disabled: !sentence.trim() || options.filter((o) => o.trim()).length < 1, className: "gap-2 border-purple-200 text-purple-600 hover:bg-purple-50 hover:text-purple-700", children: [_jsx(Eye, { className: "h-4 w-4" }), "Xem tr\u01B0\u1EDBc"] })] }) }), _jsxs(CardContent, { className: "space-y-6", children: [_jsx("div", { className: "rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4", children: _jsx(PointsInput, { defaultValue: points, onChange: (e) => setPoints(Number(e.target.value) || 1) }) }), _jsx("div", { className: "rounded-xl border border-purple-200 bg-gradient-to-r from-purple-50 to-violet-50 p-5 shadow-sm", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-purple-100", children: _jsx(Lightbulb, { className: "h-4 w-4 text-purple-600" }) }), _jsxs("div", { className: "text-sm text-purple-900", children: [_jsx("p", { className: "font-semibold text-purple-800", children: "H\u01B0\u1EDBng d\u1EABn t\u1EA1o c\u00E2u h\u1ECFi" }), _jsxs("ul", { className: "mt-2 space-y-1.5 text-purple-700", children: [_jsxs("li", { className: "flex items-center gap-2", children: [_jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-purple-400" }), "S\u1EED d\u1EE5ng ", _jsx("code", { className: "mx-1 rounded bg-purple-100 px-1.5 py-0.5 font-mono text-purple-800", children: '{0}' }), " \u0111\u1EC3 \u0111\u00E1nh d\u1EA5u ch\u1ED7 tr\u1ED1ng"] }), _jsxs("li", { className: "flex items-center gap-2", children: [_jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-purple-400" }), "Nh\u1EADp 3 d\u1EA1ng t\u00EDnh t\u1EEB: nguy\u00EAn m\u1EABu / so s\u00E1nh h\u01A1n / so s\u00E1nh nh\u1EA5t"] }), _jsxs("li", { className: "flex items-center gap-2", children: [_jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-purple-400" }), "Ch\u1ECDn \u0111\u00E1p \u00E1n \u0111\u00FAng b\u1EB1ng c\u00E1ch click v\u00E0o \u00F4 ch\u1EEF c\u00E1i ho\u1EB7c icon \u2713"] }), _jsxs("li", { className: "flex items-center gap-2", children: [_jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-purple-400" }), "V\u00ED d\u1EE5: ", _jsxs("code", { className: "ml-1 rounded bg-purple-100 px-1.5 py-0.5 font-mono text-purple-800 select-all cursor-pointer", title: "Click \u0111\u1EC3 copy", children: ["The elephant is a very ", '{0}', " animal."] })] })] })] })] }) }), _jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { htmlFor: "sentence", className: "flex items-center gap-2 text-base font-semibold text-gray-800", children: [_jsx(MessageSquare, { className: "h-4 w-4 text-purple-500" }), "C\u00E2u h\u1ECFi ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(Textarea, { id: "sentence", value: sentence, onChange: (e) => setSentence(e.target.value), placeholder: "V\u00ED d\u1EE5: The elephant is a very {0} animal.", className: `min-h-[80px] border-gray-200 bg-white transition-all focus:border-purple-300 focus:ring-purple-200 ${!sentence.includes('{0}') && sentence ? 'border-red-400 focus:border-red-500 focus:ring-red-200' : ''}`, rows: 2 }), !sentence.includes('{0}') && sentence && (_jsxs("p", { className: "text-sm text-red-600", children: ["\u26A0\uFE0F C\u00E2u c\u1EA7n c\u00F3 ch\u1ED7 tr\u1ED1ng ", _jsx("code", { className: "rounded bg-red-100 px-1", children: '{0}' })] }))] }), externalErrors && externalErrors.length > 0 && (_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("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-red-100", children: _jsx("span", { className: "text-lg", children: "\u274C" }) }), _jsxs("div", { className: "text-sm", children: [_jsx("p", { className: "font-semibold text-red-800", children: "L\u1ED7i:" }), _jsx("ul", { className: "mt-1 list-inside list-disc text-red-700", children: externalErrors.map((error, index) => (_jsx("li", { children: error }, index))) })] })] }))] })] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-violet-100/50", children: [_jsx("div", { className: "h-1 bg-gradient-to-r from-violet-400 to-purple-400" }), _jsx(CardHeader, { className: "pb-4", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "flex h-6 w-6 items-center justify-center rounded-md bg-violet-100", children: _jsx(Lightbulb, { className: "h-3.5 w-3.5 text-violet-600" }) }), _jsxs(CardTitle, { className: "text-lg font-semibold text-gray-800", children: ["C\u00E1c l\u1EF1a ch\u1ECDn ", _jsxs("span", { className: "text-sm font-normal text-gray-500", children: ["(", options.length, " \u0111\u00E1p \u00E1n)"] })] })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: handleAddOption, className: "gap-2 border-green-200 text-green-600 hover:bg-green-50 hover:text-green-700", children: [_jsx(Plus, { className: "h-4 w-4" }), "Th\u00EAm \u0111\u00E1p \u00E1n"] })] }) }), _jsxs(CardContent, { className: "space-y-4", children: [_jsx(RadioGroup, { value: correctAnswer.toString(), onValueChange: (value) => setCorrectAnswer(Number(value)), children: options.map((option, index) => {
|
|
158
|
-
const isCorrect = correctAnswer === index;
|
|
159
|
-
const optionLetter = String.fromCharCode(65 + index);
|
|
160
|
-
return (_jsx("div", { className: `group relative rounded-xl border-2 p-4 transition-all duration-200 ${isCorrect
|
|
161
|
-
? 'border-green-300 bg-gradient-to-r from-green-50 to-emerald-50 shadow-md shadow-green-100'
|
|
162
|
-
: 'border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm'}`, children: _jsxs("div", { className: "flex items-start gap-4", children: [_jsx("div", { className: `flex h-10 w-10 flex-shrink-0 cursor-pointer items-center justify-center rounded-xl font-bold transition-all ${isCorrect
|
|
163
|
-
? 'bg-gradient-to-br from-green-500 to-emerald-600 text-white shadow-md'
|
|
164
|
-
: 'bg-gray-100 text-gray-600 hover:bg-purple-100 hover:text-purple-600'}`, onClick: () => setCorrectAnswer(index), children: optionLetter }), _jsxs("div", { className: "flex-1 space-y-2", children: [_jsx(Input, { id: `option-input-${index}`, value: option, onChange: (e) => handleOptionChange(index, e.target.value), placeholder: `Nhập đáp án ${optionLetter}...`, className: "border-gray-200 bg-white transition-all focus:border-purple-300 focus:ring-purple-200" }), isCorrect && (_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-full bg-green-100 px-3 py-1 text-xs font-semibold text-green-700", children: [_jsx(CheckCircle2, { className: "h-3.5 w-3.5" }), "\u0110\u00E1p \u00E1n \u0111\u00FAng"] }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [!isCorrect && (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => setCorrectAnswer(index), className: "text-gray-400 hover:text-green-600", title: "Ch\u1ECDn l\u00E0m \u0111\u00E1p \u00E1n \u0111\u00FAng", children: _jsx(CheckCircle2, { className: "h-4 w-4" }) })), options.length > 2 && (_jsx(Button, { variant: "ghost", size: "sm", onClick: () => handleDeleteOption(index), className: "text-red-500 hover:bg-red-50 hover:text-red-600", children: _jsx(Trash2, { className: "h-4 w-4" }) }))] })] }) }, index));
|
|
165
|
-
}) }), correctAnswer === -1 && (_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("div", { className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-amber-100", children: _jsx("span", { className: "text-lg", children: "\u26A0\uFE0F" }) }), _jsxs("div", { className: "text-sm text-amber-800", children: [_jsx("p", { className: "font-semibold", children: "Ch\u01B0a ch\u1ECDn \u0111\u00E1p \u00E1n \u0111\u00FAng" }), _jsx("p", { className: "mt-0.5 text-amber-700", children: "Click v\u00E0o \u00F4 ch\u1EEF c\u00E1i ho\u1EB7c icon \u2713 \u0111\u1EC3 ch\u1ECDn \u0111\u00E1p \u00E1n \u0111\u00FAng" })] })] })), sentence && options.filter((o) => o.trim()).length >= 2 && (_jsxs("div", { className: "rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4", children: [_jsx("p", { className: "text-xs font-semibold text-gray-600 uppercase tracking-wide", children: "Xem tr\u01B0\u1EDBc:" }), _jsxs("p", { className: "mt-2 text-sm text-gray-700", children: [sentence.split('{0}').map((part, index, arr) => (_jsxs("span", { children: [part, index < arr.length - 1 && (_jsx("span", { className: "mx-1 inline-block text-purple-600", children: "______" }))] }, index))), _jsxs("span", { className: "text-gray-500", children: [" (", options.filter((o) => o.trim()).join(' / '), ")"] })] }), correctAnswer >= 0 && options[correctAnswer] && (_jsxs("p", { className: "mt-2 flex items-center gap-2 text-sm text-green-600", children: [_jsx(CheckCircle2, { className: "h-4 w-4" }), sentence.replace('{0}', options[correctAnswer])] }))] }))] })] }), _jsxs(Card, { className: "overflow-hidden border-0 bg-white shadow-lg shadow-amber-100/50", children: [_jsx("div", { className: "h-1 bg-gradient-to-r from-amber-400 to-orange-400" }), _jsx(CardHeader, { className: "pb-4", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-9 w-9 items-center justify-center rounded-lg bg-gradient-to-br from-amber-500 to-orange-500 shadow-sm", children: _jsx(BookOpen, { className: "h-4 w-4 text-white" }) }), _jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CardTitle, { className: "text-lg font-semibold text-gray-800", children: "Gi\u1EA3i th\u00EDch" }), _jsx("span", { className: "inline-flex items-center rounded-full border border-amber-200 bg-amber-50 px-2.5 py-0.5 text-xs font-medium text-amber-600", children: "Kh\u00F4ng b\u1EAFt bu\u1ED9c" })] }), _jsx("p", { className: "text-sm text-gray-500 mt-0.5", children: "Gi\u1EA3i th\u00EDch cho \u0111\u00E1p \u00E1n \u0111\u00FAng \u2014 hi\u1EC3n th\u1ECB sau khi h\u1ECDc sinh ho\u00E0n th\u00E0nh c\u00E2u h\u1ECFi" })] })] }) }), _jsx(CardContent, { children: _jsx(Textarea, { id: "explanation", value: explanation, onChange: (e) => setExplanation(e.target.value), placeholder: "VD: C\u00E2u tr\u1EA3 l\u1EDDi \u0111\u00FAng l\u00E0... v\u00EC...", rows: 3, className: "min-h-[80px] border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200 resize-none" }) })] })] }));
|
|
166
|
-
}
|
|
167
|
-
export function ChooseCorrectAdjectiveCreator(props) {
|
|
168
|
-
return _jsx(ChooseCorrectAdjectiveCreatorContent, { ...props });
|
|
169
|
-
}
|
|
1
|
+
"use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import{useState as t,useRef as n,useEffect as s}from"react";import{Button as a}from"../../../../components/ui/button";import{Label as l}from"../../../../components/ui/label";import{Input as i}from"../../../../components/ui/input";import{Textarea as c}from"../../../../components/ui/textarea";import{PointsInput as o}from"../../../../components/ui/points-input";import{Card as d,CardContent as m,CardHeader as h,CardTitle as p}from"../../../../components/ui/card";import{RadioGroup as g}from"../../../../components/ui/radio-group";import{toast as u}from"sonner";import{Pencil as x,Eye as f,Plus as b,Trash2 as N,Lightbulb as v,CheckCircle2 as w,MessageSquare as y,Type as C,BookOpen as j}from"lucide-react";import{useDebouncedCallback as k}from"../../../../shared/lib/hooks";import{ChooseCorrectAdjectiveClient as A}from"./ChooseCorrectAdjectiveClient";function S({initialData:u,onSave:S,onCancel:z,onChange:_,externalErrors:V,optionCount:J=3}){const[O,T]=t(u?.sentence||""),[D,E]=t(u?.options&&u.options.length>0?u.options:Array.from({length:J},()=>"")),[G,M]=t(u?.correctAnswer??-1),[X,$]=t(u?.explanation||""),[q,F]=t(u?.points||1),[H,K]=t(!1),L=n(u),P=n(!1),Q=n(_),R=n("");s(()=>{Q.current=_},[_]);const B=k(e=>{Q.current?.(e)},300);s(()=>{JSON.stringify(L.current)!==JSON.stringify(u)&&(P.current=!0,L.current=u,T(u?.sentence||""),E(u?.options&&u.options.length>0?u.options:Array.from({length:J},()=>"")),M(u?.correctAnswer??-1),$(u?.explanation||""),F(u?.points||1),setTimeout(()=>{P.current=!1},150))},[u,J]);const I=JSON.stringify(D);s(()=>{const e={sentence:O,options:D,correctAnswer:G,explanation:X,points:q},r=JSON.stringify(e);R.current!==r&&(P.current?R.current=r:(R.current=r,B(e)))},[O,I,G,X,q]);if(H){const t={sentence:O,options:D,correctAnswer:G,explanation:X};return r("div",{className:"space-y-6",children:[e(d,{children:e(h,{children:r("div",{className:"flex items-center justify-between",children:[e(p,{children:"Choose the correct adjective (Preview)"}),r(a,{variant:"outline",size:"sm",onClick:()=>K(!1),children:[e(x,{className:"mr-2 h-4 w-4"}),"Quay lại Edit Mode"]})]})})}),e(A,{questionData:t,isReviewMode:!0,userAnswer:-1!==G?G:void 0})]})}return r("div",{className:"space-y-6",children:[r(d,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-purple-100/50",children:[e("div",{className:"h-1.5 bg-gradient-to-r from-purple-500 via-violet-500 to-indigo-500"}),e(h,{className:"pb-4",children:r("div",{className:"flex items-center justify-between",children:[r("div",{className:"flex items-center gap-3",children:[e("div",{className:"flex h-10 w-10 items-center justify-center rounded-xl bg-gradient-to-br from-purple-500 to-violet-600 shadow-md",children:e(C,{className:"h-5 w-5 text-white"})}),r("div",{children:[e(p,{className:"text-xl font-bold text-gray-900",children:"Chọn tính từ đúng"}),e("p",{className:"text-sm text-gray-500",children:"Chọn dạng đúng của tính từ để hoàn thành câu"})]})]}),r(a,{variant:"outline",size:"sm",onClick:()=>K(!0),disabled:!O.trim()||D.filter(e=>e.trim()).length<1,className:"gap-2 border-purple-200 text-purple-600 hover:bg-purple-50 hover:text-purple-700",children:[e(f,{className:"h-4 w-4"}),"Xem trước"]})]})}),r(m,{className:"space-y-6",children:[e("div",{className:"rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4",children:e(o,{defaultValue:q,onChange:e=>F(Number(e.target.value)||1)})}),e("div",{className:"rounded-xl border border-purple-200 bg-gradient-to-r from-purple-50 to-violet-50 p-5 shadow-sm",children:r("div",{className:"flex items-start gap-3",children:[e("div",{className:"flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-purple-100",children:e(v,{className:"h-4 w-4 text-purple-600"})}),r("div",{className:"text-sm text-purple-900",children:[e("p",{className:"font-semibold text-purple-800",children:"Hướng dẫn tạo câu hỏi"}),r("ul",{className:"mt-2 space-y-1.5 text-purple-700",children:[r("li",{className:"flex items-center gap-2",children:[e("span",{className:"h-1.5 w-1.5 rounded-full bg-purple-400"}),"Sử dụng ",e("code",{className:"mx-1 rounded bg-purple-100 px-1.5 py-0.5 font-mono text-purple-800",children:"{0}"})," để đánh dấu chỗ trống"]}),r("li",{className:"flex items-center gap-2",children:[e("span",{className:"h-1.5 w-1.5 rounded-full bg-purple-400"}),"Nhập 3 dạng tính từ: nguyên mẫu / so sánh hơn / so sánh nhất"]}),r("li",{className:"flex items-center gap-2",children:[e("span",{className:"h-1.5 w-1.5 rounded-full bg-purple-400"}),"Chọn đáp án đúng bằng cách click vào ô chữ cái hoặc icon ✓"]}),r("li",{className:"flex items-center gap-2",children:[e("span",{className:"h-1.5 w-1.5 rounded-full bg-purple-400"}),"Ví dụ: ",r("code",{className:"ml-1 rounded bg-purple-100 px-1.5 py-0.5 font-mono text-purple-800 select-all cursor-pointer",title:"Click để copy",children:["The elephant is a very ","{0}"," animal."]})]})]})]})]})}),r("div",{className:"space-y-2",children:[r(l,{htmlFor:"sentence",className:"flex items-center gap-2 text-base font-semibold text-gray-800",children:[e(y,{className:"h-4 w-4 text-purple-500"}),"Câu hỏi ",e("span",{className:"text-red-500",children:"*"})]}),e(c,{id:"sentence",value:O,onChange:e=>T(e.target.value),placeholder:"Ví dụ: The elephant is a very {0} animal.",className:"min-h-[80px] border-gray-200 bg-white transition-all focus:border-purple-300 focus:ring-purple-200 "+(!O.includes("{0}")&&O?"border-red-400 focus:border-red-500 focus:ring-red-200":""),rows:2}),!O.includes("{0}")&&O&&r("p",{className:"text-sm text-red-600",children:["⚠️ Câu cần có chỗ trống ",e("code",{className:"rounded bg-red-100 px-1",children:"{0}"})]})]}),V&&V.length>0&&r("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:[e("div",{className:"flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-red-100",children:e("span",{className:"text-lg",children:"❌"})}),r("div",{className:"text-sm",children:[e("p",{className:"font-semibold text-red-800",children:"Lỗi:"}),e("ul",{className:"mt-1 list-inside list-disc text-red-700",children:V.map((r,t)=>e("li",{children:r},t))})]})]})]})]}),r(d,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-violet-100/50",children:[e("div",{className:"h-1 bg-gradient-to-r from-violet-400 to-purple-400"}),e(h,{className:"pb-4",children:r("div",{className:"flex items-center justify-between",children:[r("div",{className:"flex items-center gap-2",children:[e("div",{className:"flex h-6 w-6 items-center justify-center rounded-md bg-violet-100",children:e(v,{className:"h-3.5 w-3.5 text-violet-600"})}),r(p,{className:"text-lg font-semibold text-gray-800",children:["Các lựa chọn ",r("span",{className:"text-sm font-normal text-gray-500",children:["(",D.length," đáp án)"]})]})]}),r(a,{variant:"outline",size:"sm",onClick:()=>{E([...D,""])},className:"gap-2 border-green-200 text-green-600 hover:bg-green-50 hover:text-green-700",children:[e(b,{className:"h-4 w-4"}),"Thêm đáp án"]})]})}),r(m,{className:"space-y-4",children:[e(g,{value:G.toString(),onValueChange:e=>M(Number(e)),children:D.map((t,n)=>{const s=G===n,l=String.fromCharCode(65+n);return e("div",{className:"group relative rounded-xl border-2 p-4 transition-all duration-200 "+(s?"border-green-300 bg-gradient-to-r from-green-50 to-emerald-50 shadow-md shadow-green-100":"border-gray-200 bg-white hover:border-gray-300 hover:shadow-sm"),children:r("div",{className:"flex items-start gap-4",children:[e("div",{className:"flex h-10 w-10 flex-shrink-0 cursor-pointer items-center justify-center rounded-xl font-bold transition-all "+(s?"bg-gradient-to-br from-green-500 to-emerald-600 text-white shadow-md":"bg-gray-100 text-gray-600 hover:bg-purple-100 hover:text-purple-600"),onClick:()=>M(n),children:l}),r("div",{className:"flex-1 space-y-2",children:[e(i,{id:`option-input-${n}`,value:t,onChange:e=>((e,r)=>{const t=[...D];t[e]=r,E(t)})(n,e.target.value),placeholder:`Nhập đáp án ${l}...`,className:"border-gray-200 bg-white transition-all focus:border-purple-300 focus:ring-purple-200"}),s&&r("span",{className:"inline-flex items-center gap-1.5 rounded-full bg-green-100 px-3 py-1 text-xs font-semibold text-green-700",children:[e(w,{className:"h-3.5 w-3.5"}),"Đáp án đúng"]})]}),r("div",{className:"flex items-center gap-2",children:[!s&&e(a,{type:"button",variant:"ghost",size:"sm",onClick:()=>M(n),className:"text-gray-400 hover:text-green-600",title:"Chọn làm đáp án đúng",children:e(w,{className:"h-4 w-4"})}),D.length>2&&e(a,{variant:"ghost",size:"sm",onClick:()=>(e=>{const r=D.filter((r,t)=>t!==e);E(r),G===e?M(-1):G>e&&M(G-1)})(n),className:"text-red-500 hover:bg-red-50 hover:text-red-600",children:e(N,{className:"h-4 w-4"})})]})]})},n)})}),-1===G&&r("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:[e("div",{className:"flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-amber-100",children:e("span",{className:"text-lg",children:"⚠️"})}),r("div",{className:"text-sm text-amber-800",children:[e("p",{className:"font-semibold",children:"Chưa chọn đáp án đúng"}),e("p",{className:"mt-0.5 text-amber-700",children:"Click vào ô chữ cái hoặc icon ✓ để chọn đáp án đúng"})]})]}),O&&D.filter(e=>e.trim()).length>=2&&r("div",{className:"rounded-xl border border-gray-200 bg-gradient-to-r from-gray-50 to-slate-50 p-4",children:[e("p",{className:"text-xs font-semibold text-gray-600 uppercase tracking-wide",children:"Xem trước:"}),r("p",{className:"mt-2 text-sm text-gray-700",children:[O.split("{0}").map((t,n,s)=>r("span",{children:[t,n<s.length-1&&e("span",{className:"mx-1 inline-block text-purple-600",children:"______"})]},n)),r("span",{className:"text-gray-500",children:[" (",D.filter(e=>e.trim()).join(" / "),")"]})]}),G>=0&&D[G]&&r("p",{className:"mt-2 flex items-center gap-2 text-sm text-green-600",children:[e(w,{className:"h-4 w-4"}),O.replace("{0}",D[G])]})]})]})]}),r(d,{className:"overflow-hidden border-0 bg-white shadow-lg shadow-amber-100/50",children:[e("div",{className:"h-1 bg-gradient-to-r from-amber-400 to-orange-400"}),e(h,{className:"pb-4",children:r("div",{className:"flex items-center gap-3",children:[e("div",{className:"flex h-9 w-9 items-center justify-center rounded-lg bg-gradient-to-br from-amber-500 to-orange-500 shadow-sm",children:e(j,{className:"h-4 w-4 text-white"})}),r("div",{children:[r("div",{className:"flex items-center gap-2",children:[e(p,{className:"text-lg font-semibold text-gray-800",children:"Giải thích"}),e("span",{className:"inline-flex items-center rounded-full border border-amber-200 bg-amber-50 px-2.5 py-0.5 text-xs font-medium text-amber-600",children:"Không bắt buộc"})]}),e("p",{className:"text-sm text-gray-500 mt-0.5",children:"Giải thích cho đáp án đúng — hiển thị sau khi học sinh hoàn thành câu hỏi"})]})]})}),e(m,{children:e(c,{id:"explanation",value:X,onChange:e=>$(e.target.value),placeholder:"VD: Câu trả lời đúng là... vì...",rows:3,className:"min-h-[80px] border-gray-200 bg-white transition-all focus:border-amber-300 focus:ring-amber-200 resize-none"})})]})]})}export function ChooseCorrectAdjectiveCreator(r){return e(S,{...r})}
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export * from './ChooseCorrectAdjectiveClient';
|
|
1
|
+
export*from"./ChooseCorrectAdjectiveCreator";export*from"./ChooseCorrectAdjectiveClient";
|
|
@@ -1,55 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
export const chooseCorrectAdjectiveRegistration = {
|
|
3
|
-
component: ChooseCorrectAdjectiveCreator,
|
|
4
|
-
transformInitialData: (initialData) => {
|
|
5
|
-
const content = initialData?.content;
|
|
6
|
-
const answer = initialData?.answer;
|
|
7
|
-
const points = initialData?.total_points
|
|
8
|
-
? parseFloat(initialData.total_points)
|
|
9
|
-
: (initialData?.points || answer?.points || 1);
|
|
10
|
-
let creatorData = answer;
|
|
11
|
-
if (content && (content.sentence !== undefined || content.options)) {
|
|
12
|
-
creatorData = {
|
|
13
|
-
sentence: content.sentence || '',
|
|
14
|
-
options: content.options || [],
|
|
15
|
-
correctAnswer: answer?.answer ?? -1,
|
|
16
|
-
explanation: initialData?.explanation || content.explanation || '',
|
|
17
|
-
points,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
return creatorData;
|
|
21
|
-
},
|
|
22
|
-
getExtraProps: (ctx) => ({
|
|
23
|
-
optionCount: ctx.optionCount || 3,
|
|
24
|
-
}),
|
|
25
|
-
wrapOnSave: (data, ctx) => ({
|
|
26
|
-
type: ctx.questionType,
|
|
27
|
-
points: data.points ?? ctx.state.points ?? 1,
|
|
28
|
-
level: ctx.state.level,
|
|
29
|
-
difficulty: ctx.state.difficulty,
|
|
30
|
-
skill: ctx.state.skill,
|
|
31
|
-
explanation: data.explanation || '',
|
|
32
|
-
content: {
|
|
33
|
-
sentence: data.sentence,
|
|
34
|
-
options: data.options,
|
|
35
|
-
},
|
|
36
|
-
answer: {
|
|
37
|
-
answer: data.correctAnswer,
|
|
38
|
-
},
|
|
39
|
-
}),
|
|
40
|
-
wrapOnChange: (data, ctx) => ({
|
|
41
|
-
type: ctx.questionType,
|
|
42
|
-
points: data.points ?? ctx.state.points ?? 1,
|
|
43
|
-
level: ctx.state.level,
|
|
44
|
-
difficulty: ctx.state.difficulty,
|
|
45
|
-
skill: ctx.state.skill,
|
|
46
|
-
explanation: data.explanation || '',
|
|
47
|
-
content: {
|
|
48
|
-
sentence: data.sentence,
|
|
49
|
-
options: data.options,
|
|
50
|
-
},
|
|
51
|
-
answer: {
|
|
52
|
-
answer: data.correctAnswer,
|
|
53
|
-
},
|
|
54
|
-
}),
|
|
55
|
-
};
|
|
1
|
+
import{ChooseCorrectAdjectiveCreator as t}from"./ChooseCorrectAdjectiveCreator";export const chooseCorrectAdjectiveRegistration={component:t,transformInitialData:t=>{const e=t?.content,n=t?.answer,o=t?.total_points?parseFloat(t.total_points):t?.points||n?.points||1;let s=n;return e&&(void 0!==e.sentence||e.options)&&(s={sentence:e.sentence||"",options:e.options||[],correctAnswer:n?.answer??-1,explanation:t?.explanation||e.explanation||"",points:o}),s},getExtraProps:t=>({optionCount:t.optionCount||3}),wrapOnSave:(t,e)=>({type:e.questionType,points:t.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,explanation:t.explanation||"",content:{sentence:t.sentence,options:t.options},answer:{answer:t.correctAnswer}}),wrapOnChange:(t,e)=>({type:e.questionType,points:t.points??e.state.points??1,level:e.state.level,difficulty:e.state.difficulty,skill:e.state.skill,explanation:t.explanation||"",content:{sentence:t.sentence,options:t.options},answer:{answer:t.correctAnswer}})};
|
|
@@ -1,16 +1 @@
|
|
|
1
|
-
export const transformChooseCorrectAdjective =
|
|
2
|
-
const contentData = question.content;
|
|
3
|
-
const answerData = question.answer;
|
|
4
|
-
if (!contentData?.sentence || !contentData?.options) {
|
|
5
|
-
return { apiContent: {}, apiCorrectAnswer: {} };
|
|
6
|
-
}
|
|
7
|
-
return {
|
|
8
|
-
apiContent: {
|
|
9
|
-
sentence: contentData.sentence,
|
|
10
|
-
options: contentData.options,
|
|
11
|
-
},
|
|
12
|
-
apiCorrectAnswer: {
|
|
13
|
-
answer: answerData?.answer ?? -1,
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
};
|
|
1
|
+
export const transformChooseCorrectAdjective=e=>{const n=e.content,t=e.answer;return n?.sentence&&n?.options?{apiContent:{sentence:n.sentence,options:n.options},apiCorrectAnswer:{answer:t?.answer??-1}}:{apiContent:{},apiCorrectAnswer:{}}};
|
package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js
CHANGED
|
@@ -1,131 +1 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useEffect, useMemo } from 'react';
|
|
4
|
-
import { Check, X, CircleHelp, Lightbulb, ClipboardList, Users, BookOpen } from 'lucide-react';
|
|
5
|
-
import { usePresignedFileUrl } from '../../../../shared/lib/hooks';
|
|
6
|
-
import { cn } from '../../../../shared/lib/utils';
|
|
7
|
-
// Helper component to resolve presigned URL for each image option
|
|
8
|
-
function OptionImage({ src, alt, className }) {
|
|
9
|
-
const { previewUrl, isLoading } = usePresignedFileUrl(src);
|
|
10
|
-
if (isLoading) {
|
|
11
|
-
return (_jsx("div", { className: "flex h-16 w-16 items-center justify-center", children: _jsx("div", { className: "h-4 w-4 animate-spin rounded-full border-2 border-gray-200 border-t-blue-500" }) }));
|
|
12
|
-
}
|
|
13
|
-
return (
|
|
14
|
-
/* eslint-disable-next-line @next/next/no-img-element */
|
|
15
|
-
_jsx("img", { src: previewUrl || src, alt: alt, className: cn('max-h-20 w-auto object-contain rounded-md', className), onError: (e) => {
|
|
16
|
-
const target = e.target;
|
|
17
|
-
target.onerror = null;
|
|
18
|
-
target.src = '/images/placeholder-image.svg';
|
|
19
|
-
} }));
|
|
20
|
-
}
|
|
21
|
-
export function ChooseTheCorrectAnswerClient({ questionData, onSubmit, isReviewMode = false, userAnswer, questionConfig, }) {
|
|
22
|
-
const isMultipleAnswers = Boolean(questionData.multipleAnswers || Array.isArray(questionData.correctAnswer));
|
|
23
|
-
const normalizedCorrectAnswers = useMemo(() => Array.isArray(questionData.correctAnswer)
|
|
24
|
-
? questionData.correctAnswer
|
|
25
|
-
: questionData.correctAnswer === -1
|
|
26
|
-
? []
|
|
27
|
-
: [questionData.correctAnswer], [questionData.correctAnswer]);
|
|
28
|
-
const normalizedUserAnswers = useMemo(() => userAnswer === undefined
|
|
29
|
-
? []
|
|
30
|
-
: Array.isArray(userAnswer)
|
|
31
|
-
? userAnswer
|
|
32
|
-
: userAnswer === -1
|
|
33
|
-
? []
|
|
34
|
-
: [userAnswer], [userAnswer]);
|
|
35
|
-
// State
|
|
36
|
-
const [selectedAnswer, setSelectedAnswer] = useState(normalizedUserAnswers);
|
|
37
|
-
// Custom hooks
|
|
38
|
-
const { previewUrl: imagePreviewUrl, isLoading } = usePresignedFileUrl(questionData.imageUrl || '');
|
|
39
|
-
// Sync userAnswer when it changes (e.g., when loading from server in review mode)
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
setSelectedAnswer(normalizedUserAnswers);
|
|
42
|
-
}, [normalizedUserAnswers]);
|
|
43
|
-
// Handle answer change
|
|
44
|
-
const handleAnswerChange = (index) => {
|
|
45
|
-
if (isReviewMode)
|
|
46
|
-
return;
|
|
47
|
-
const nextAnswer = isMultipleAnswers
|
|
48
|
-
? (selectedAnswer.includes(index)
|
|
49
|
-
? selectedAnswer.filter((answer) => answer !== index)
|
|
50
|
-
: [...selectedAnswer, index].sort((a, b) => a - b))
|
|
51
|
-
: [index];
|
|
52
|
-
setSelectedAnswer(nextAnswer);
|
|
53
|
-
// Auto submit if callback provided
|
|
54
|
-
onSubmit?.(isMultipleAnswers ? nextAnswer : nextAnswer[0]);
|
|
55
|
-
};
|
|
56
|
-
// Check if answer is correct - only used in review mode
|
|
57
|
-
const isCorrect = (optionIndex) => {
|
|
58
|
-
// Only check correctness in review mode to prevent revealing answers
|
|
59
|
-
if (!isReviewMode)
|
|
60
|
-
return false;
|
|
61
|
-
return normalizedCorrectAnswers.includes(optionIndex);
|
|
62
|
-
};
|
|
63
|
-
const hasAnswered = selectedAnswer.length > 0;
|
|
64
|
-
const isAnswerCorrect = isReviewMode
|
|
65
|
-
&& selectedAnswer.length === normalizedCorrectAnswers.length
|
|
66
|
-
&& selectedAnswer.every((answer) => normalizedCorrectAnswers.includes(answer));
|
|
67
|
-
const formatAnswerLabel = (answers) => {
|
|
68
|
-
if (answers.length === 0)
|
|
69
|
-
return '(Chưa trả lời)';
|
|
70
|
-
return answers.map((answerIndex) => {
|
|
71
|
-
const answerLetter = String.fromCharCode(65 + answerIndex);
|
|
72
|
-
return questionData.optionType === 'image'
|
|
73
|
-
? `Đáp án ${answerLetter}`
|
|
74
|
-
: `${answerLetter}. ${questionData.options[answerIndex]}`;
|
|
75
|
-
}).join(', ');
|
|
76
|
-
};
|
|
77
|
-
// Visibility toggles based on questionConfig (from template)
|
|
78
|
-
// Default to displaying if no config provided
|
|
79
|
-
const showQuestion = !questionConfig || questionConfig.length === 0 || questionConfig.includes('question');
|
|
80
|
-
const showImage = !questionConfig || questionConfig.length === 0 || questionConfig.includes('imageUrl') || questionConfig.includes('image');
|
|
81
|
-
console.log('questionConfig', questionConfig);
|
|
82
|
-
console.log('showImage', showImage);
|
|
83
|
-
const showOptions = !questionConfig || questionConfig.length === 0 || questionConfig.includes('options');
|
|
84
|
-
// Clean up imageUrl, often it might be just an empty space ' ' from DB
|
|
85
|
-
const cleanImageUrl = questionData.imageUrl?.trim() ? questionData.imageUrl : '';
|
|
86
|
-
const hasArticles = Array.isArray(questionData.articles) && questionData.articles.length > 0;
|
|
87
|
-
return (_jsxs("div", { className: "space-y-4", children: [questionData.isGroup && (questionData.groupTitle || questionData.groupSubtitle || questionData.groupContent || questionData.groupImageUrl || hasArticles) && (_jsxs("div", { className: "relative overflow-hidden rounded-2xl border border-indigo-100 bg-white shadow-sm ring-1 ring-black/5 transition-all", children: [_jsx("div", { className: "absolute inset-0 bg-gradient-to-br from-indigo-50/80 via-white to-blue-50/30 opacity-70 pointer-events-none" }), _jsx("div", { className: "absolute left-0 top-0 bottom-0 w-1.5 bg-gradient-to-b from-indigo-500 to-blue-600 rounded-l-2xl" }), _jsxs("div", { className: "relative p-6 sm:p-7", children: [_jsxs("div", { className: "flex items-start gap-4 mb-5 border-b border-indigo-50/60 pb-4", children: [_jsx("div", { className: "flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-indigo-100 to-blue-100 shadow-inner ring-1 ring-indigo-200/50", children: _jsx(BookOpen, { className: "h-5 w-5 text-indigo-600" }) }), _jsxs("div", { className: "flex-1 pt-1", children: [_jsx("div", { className: "flex items-center gap-2 mb-1", children: questionData.groupNumber && (_jsxs("span", { className: "inline-flex items-center rounded-md bg-indigo-50 px-2 py-1 text-xs font-semibold text-indigo-700 ring-1 ring-inset ring-indigo-700/10", children: ["B\u00E0i \u0111\u1ECDc ", questionData.groupNumber] })) }), questionData.groupTitle && (_jsx("h4", { className: "text-xl font-bold text-slate-800 leading-tight tracking-tight", children: questionData.groupTitle })), questionData.groupSubtitle && (_jsx("p", { className: "mt-1 text-sm text-slate-500 leading-snug", children: questionData.groupSubtitle }))] })] }), hasArticles && (_jsx("div", { className: "flex flex-col gap-4", children: questionData.articles.map((article, i) => (_jsxs("div", { className: "group relative overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm transition-all hover:shadow-md hover:border-indigo-200", children: [_jsxs("div", { className: "flex items-center gap-2 border-b border-slate-100 bg-gradient-to-r from-indigo-50/60 to-blue-50/40 px-4 py-2.5", children: [_jsx("div", { className: "flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-indigo-500 to-blue-600 text-xs font-bold text-white shadow-sm", children: String.fromCharCode(65 + i) }), _jsx("h5", { className: "flex-1 truncate text-sm font-bold text-slate-800", children: article.name || `Bài viết ${i + 1}` })] }), _jsxs("div", { className: "flex flex-col gap-3 p-4 sm:flex-row sm:items-start", children: [article.imageUrl && (_jsx("div", { className: "flex flex-shrink-0 items-center justify-center rounded-md bg-slate-50 p-2 sm:w-40", children: _jsx(OptionImage, { src: article.imageUrl, alt: article.name || `Article ${i + 1}`, className: "max-h-40 w-auto rounded-md object-contain" }) })), article.content && (_jsx("div", { className: "prose prose-sm prose-slate max-w-none flex-1 text-[14px] leading-relaxed text-slate-700", children: article.content.split('\n').map((line, j) => (_jsx("p", { className: "mb-2 last:mb-0", children: line }, j))) }))] })] }, i))) })), !hasArticles && (_jsxs("div", { className: "space-y-6 text-slate-700", children: [questionData.groupContent && (_jsx("div", { className: "prose prose-slate prose-p:leading-relaxed prose-p:mb-3 max-w-none text-[15px]", dangerouslySetInnerHTML: {
|
|
88
|
-
__html: questionData.groupContent
|
|
89
|
-
.replace(/\{(\d+)\}/g, (_m, num) => `<span style="display:inline-block;min-width:100px;padding:1px 5px;margin:0 5px;background:#eef2ff;border-bottom:2px solid #6366f1;color:#4f46e5;font-weight:700;font-size:0.85em;text-align:center;vertical-align:baseline;letter-spacing:2px">———(${Number(num) + 1})———</span>`)
|
|
90
|
-
.split('\n')
|
|
91
|
-
.map((line) => `<p class="last:mb-0">${line}</p>`)
|
|
92
|
-
.join(''),
|
|
93
|
-
} })), questionData.groupImageUrl && (_jsxs("div", { className: "mt-5 relative overflow-hidden rounded-xl border border-slate-200/60 bg-slate-50 shadow-sm transition-all hover:shadow-md", children: [_jsx("div", { className: "flex items-center justify-between border-b border-slate-200/60 bg-slate-100/50 px-4 py-2", children: _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("div", { className: "h-2.5 w-2.5 rounded-full bg-slate-300" }), _jsx("div", { className: "h-2.5 w-2.5 rounded-full bg-slate-300" }), _jsx("div", { className: "h-2.5 w-2.5 rounded-full bg-slate-300" }), _jsx("span", { className: "ml-2 text-[11px] font-semibold uppercase tracking-wider text-slate-500", children: "T\u00E0i li\u1EC7u \u0111\u00EDnh k\u00E8m" })] }) }), _jsx("div", { className: "flex items-center justify-center p-4 min-h-[160px]", children: _jsx(OptionImage, { src: questionData.groupImageUrl, alt: questionData.groupTitle || 'Group Image Attachment', className: "max-h-72 w-auto object-contain drop-shadow-sm rounded-lg" }) })] }))] }))] })] })), _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-gradient-to-r from-gray-50 to-white px-5 py-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-blue-500 to-indigo-600 text-white shadow-sm", children: _jsx(CircleHelp, { className: "h-4 w-4" }) }), _jsx("span", { className: "text-sm font-medium text-gray-700", children: isMultipleAnswers ? 'Chọn các đáp án đúng' : 'Chọn đáp án đúng' })] }), isReviewMode && hasAnswered && (_jsxs("div", { className: cn('flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold', isAnswerCorrect
|
|
94
|
-
? 'bg-green-100 text-green-700'
|
|
95
|
-
: 'bg-red-100 text-red-700'), children: [isAnswerCorrect ? _jsx(Check, { className: "h-3.5 w-3.5" }) : _jsx(X, { className: "h-3.5 w-3.5" }), isAnswerCorrect ? 'Đúng' : 'Sai'] }))] }), _jsxs("div", { className: "p-5 space-y-5", children: [(questionData.askerName || questionData.answererName) && (_jsxs("div", { className: "flex items-center gap-4 rounded-lg border border-purple-100 bg-gradient-to-r from-purple-50 to-violet-50 px-4 py-3", children: [_jsx(Users, { className: "h-4 w-4 flex-shrink-0 text-purple-500" }), _jsxs("div", { className: "flex items-center gap-4 text-sm", children: [questionData.askerName && (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "font-medium text-gray-500", children: "Ng\u01B0\u1EDDi h\u1ECFi:" }), _jsx("span", { className: "font-semibold text-purple-700", children: questionData.askerName })] })), questionData.askerName && questionData.answererName && (_jsx("div", { className: "h-4 w-px bg-purple-200" })), questionData.answererName && (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "font-medium text-gray-500", children: "Ng\u01B0\u1EDDi tr\u1EA3 l\u1EDDi:" }), _jsx("span", { className: "font-semibold text-purple-700", children: questionData.answererName })] }))] })] })), showQuestion && (_jsx("div", { className: "rounded-lg bg-gradient-to-r from-blue-50 to-indigo-50 p-4 border border-blue-100", children: _jsx("h3", { className: "text-base font-semibold text-gray-800 leading-relaxed", children: questionData.question || 'Câu hỏi chưa được nhập' }) })), showImage && (imagePreviewUrl || cleanImageUrl) && (_jsxs("div", { className: "overflow-hidden rounded-lg border border-gray-200 bg-gradient-to-br from-slate-50 to-gray-100", children: [_jsx("div", { className: "border-b border-gray-100 px-3 py-1.5", children: _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("div", { className: "h-2 w-2 rounded-full bg-red-400" }), _jsx("div", { className: "h-2 w-2 rounded-full bg-yellow-400" }), _jsx("div", { className: "h-2 w-2 rounded-full bg-green-400" }), _jsx("span", { className: "ml-2 text-xs font-medium text-gray-500", children: "H\u00ECnh \u1EA3nh" })] }) }), _jsx("div", { className: "flex items-center justify-center p-4", children: isLoading ? (_jsx("div", { className: "flex h-48 items-center justify-center", children: _jsx("div", { className: "h-8 w-8 animate-spin rounded-full border-4 border-gray-200 border-t-blue-500" }) })) : (
|
|
96
|
-
/* eslint-disable-next-line @next/next/no-img-element */
|
|
97
|
-
_jsx("img", { src: imagePreviewUrl || cleanImageUrl, alt: "Question illustration", className: "max-h-56 w-auto object-contain rounded-md", onError: (e) => {
|
|
98
|
-
const target = e.target;
|
|
99
|
-
target.onerror = null;
|
|
100
|
-
target.src = '/images/placeholder-image.svg';
|
|
101
|
-
} })) })] })), showOptions && (_jsxs("div", { className: "space-y-2.5", children: [_jsx("span", { className: "text-xs font-medium text-gray-500 uppercase tracking-wider", children: isMultipleAnswers ? 'Chọn một hoặc nhiều đáp án' : 'Chọn đáp án' }), questionData.options.map((option, index) => {
|
|
102
|
-
const isSelected = selectedAnswer.includes(index);
|
|
103
|
-
const isCorrectAnswer = isCorrect(index);
|
|
104
|
-
const letter = String.fromCharCode(65 + index);
|
|
105
|
-
return (_jsxs("button", { type: "button", onClick: () => handleAnswerChange(index), disabled: isReviewMode, className: cn('group flex w-full items-center gap-3 rounded-lg border-2 p-3.5 text-left transition-all', isReviewMode
|
|
106
|
-
? isCorrectAnswer
|
|
107
|
-
? 'border-green-400 bg-green-50'
|
|
108
|
-
: isSelected
|
|
109
|
-
? 'border-red-400 bg-red-50'
|
|
110
|
-
: 'border-gray-200 bg-gray-50'
|
|
111
|
-
: isSelected
|
|
112
|
-
? 'border-blue-500 bg-blue-50 shadow-sm ring-2 ring-blue-100'
|
|
113
|
-
: 'border-gray-200 bg-white hover:border-gray-300 hover:bg-gray-50 hover:shadow-sm'), children: [_jsx("div", { className: cn('flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg text-sm font-bold transition-all', isReviewMode
|
|
114
|
-
? isCorrectAnswer
|
|
115
|
-
? 'bg-green-500 text-white'
|
|
116
|
-
: isSelected
|
|
117
|
-
? 'bg-red-500 text-white'
|
|
118
|
-
: 'bg-gray-200 text-gray-600'
|
|
119
|
-
: isSelected
|
|
120
|
-
? 'bg-gradient-to-br from-blue-500 to-indigo-600 text-white shadow-sm'
|
|
121
|
-
: 'bg-gray-100 text-gray-600 group-hover:bg-gray-200'), children: letter }), questionData.optionType === 'image' ? (_jsx("div", { className: "flex-1 flex items-center justify-center py-1", children: _jsx(OptionImage, { src: option, alt: `Đáp án ${letter}` }) })) : (_jsx("span", { className: cn('flex-1 text-sm font-medium', isReviewMode && isCorrectAnswer
|
|
122
|
-
? 'text-green-800'
|
|
123
|
-
: isReviewMode && isSelected && !isCorrectAnswer
|
|
124
|
-
? 'text-red-800'
|
|
125
|
-
: 'text-gray-700'), children: option })), isReviewMode && (isCorrectAnswer || isSelected) && (_jsx("div", { className: cn('flex h-6 w-6 items-center justify-center rounded-full', isCorrectAnswer ? 'bg-green-500' : 'bg-red-500'), children: isCorrectAnswer
|
|
126
|
-
? _jsx(Check, { className: "h-4 w-4 text-white" })
|
|
127
|
-
: _jsx(X, { className: "h-4 w-4 text-white" }) }))] }, index));
|
|
128
|
-
})] })), !isReviewMode && !hasAnswered && (_jsxs("div", { className: "rounded-lg border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-3 flex items-center gap-2", children: [_jsx("div", { className: "flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full bg-amber-400 text-white", children: _jsx("span", { className: "text-xs font-bold", children: "!" }) }), _jsx("span", { className: "text-sm text-amber-800", children: isMultipleAnswers ? 'Vui lòng chọn ít nhất một đáp án' : 'Vui lòng chọn một đáp án' })] }))] })] }), isReviewMode && questionData.explanation && (_jsxs("div", { className: "overflow-hidden rounded-xl border border-blue-200 bg-gradient-to-br from-blue-50 to-indigo-50 shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-2 border-b border-blue-100 bg-white/50 px-4 py-3", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-amber-400 to-orange-500 text-white shadow-sm", children: _jsx(Lightbulb, { className: "h-4 w-4" }) }), _jsx("h4", { className: "text-sm font-semibold text-gray-800", children: "Gi\u1EA3i th\u00EDch" })] }), _jsx("div", { className: "p-4", children: _jsx("p", { className: "text-sm text-gray-700 leading-relaxed", children: questionData.explanation }) })] })), isReviewMode && (_jsxs("div", { className: "overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-2 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-4 py-3", children: [_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-slate-500 to-gray-600 text-white shadow-sm", children: _jsx(ClipboardList, { className: "h-4 w-4" }) }), _jsx("h4", { className: "text-sm font-semibold text-gray-800", children: "T\u1ED5ng k\u1EBFt" })] }), _jsxs("div", { className: "p-4 space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg bg-gray-50 p-3", children: [_jsx("span", { className: "text-sm text-gray-600", children: "\u0110\u00E1p \u00E1n c\u1EE7a b\u1EA1n:" }), _jsx("span", { className: cn('text-sm font-semibold', isAnswerCorrect ? 'text-green-600' : hasAnswered ? 'text-red-600' : 'text-gray-500'), children: formatAnswerLabel(selectedAnswer) })] }), _jsxs("div", { className: "flex items-center justify-between rounded-lg bg-green-50 p-3 border border-green-100", children: [_jsx("span", { className: "text-sm text-gray-600", children: "\u0110\u00E1p \u00E1n \u0111\u00FAng:" }), _jsx("span", { className: "text-sm font-semibold text-green-600", children: formatAnswerLabel(normalizedCorrectAnswers) })] }), _jsxs("div", { className: cn('flex items-center justify-between rounded-lg p-3 border', isAnswerCorrect
|
|
129
|
-
? 'bg-green-50 border-green-200'
|
|
130
|
-
: 'bg-red-50 border-red-200'), children: [_jsx("span", { className: "text-sm text-gray-600", children: "K\u1EBFt qu\u1EA3:" }), _jsx("div", { className: cn('flex items-center gap-1.5 text-sm font-semibold', isAnswerCorrect ? 'text-green-600' : 'text-red-600'), children: isAnswerCorrect ? (_jsxs(_Fragment, { children: [_jsx(Check, { className: "h-4 w-4" }), _jsx("span", { children: "Ch\u00EDnh x\u00E1c" })] })) : (_jsxs(_Fragment, { children: [_jsx(X, { className: "h-4 w-4" }), _jsx("span", { children: "Sai" })] })) })] })] })] }))] }));
|
|
131
|
-
}
|
|
1
|
+
"use client";import{jsx as e,jsxs as r,Fragment as t}from"react/jsx-runtime";import{useState as s,useEffect as a,useMemo as l}from"react";import{Check as n,X as i,CircleHelp as d,Lightbulb as o,ClipboardList as c,Users as m,BookOpen as g}from"lucide-react";import{usePresignedFileUrl as h}from"../../../../shared/lib/hooks";import{cn as b}from"../../../../shared/lib/utils";function p({src:r,alt:t,className:s}){const{previewUrl:a,isLoading:l}=h(r);return l?e("div",{className:"flex h-16 w-16 items-center justify-center",children:e("div",{className:"h-4 w-4 animate-spin rounded-full border-2 border-gray-200 border-t-blue-500"})}):e("img",{src:a||r,alt:t,className:b("max-h-20 w-auto object-contain rounded-md",s),onError:e=>{const r=e.target;r.onerror=null,r.src="/images/placeholder-image.svg"}})}export function ChooseTheCorrectAnswerClient({questionData:x,onSubmit:u,isReviewMode:f=!1,userAnswer:N,questionConfig:w}){const v=Boolean(x.multipleAnswers||Array.isArray(x.correctAnswer)),y=l(()=>Array.isArray(x.correctAnswer)?x.correctAnswer:-1===x.correctAnswer?[]:[x.correctAnswer],[x.correctAnswer]),j=l(()=>void 0===N?[]:Array.isArray(N)?N:-1===N?[]:[N],[N]),[C,k]=s(j),{previewUrl:A,isLoading:U}=h(x.imageUrl||"");a(()=>{k(j)},[j]);const S=C.length>0,T=f&&C.length===y.length&&C.every(e=>y.includes(e)),$=e=>0===e.length?"(Chưa trả lời)":e.map(e=>{const r=String.fromCharCode(65+e);return"image"===x.optionType?`Đáp án ${r}`:`${r}. ${x.options[e]}`}).join(", "),q=!w||0===w.length||w.includes("question"),I=!w||0===w.length||w.includes("imageUrl")||w.includes("image");console.log("questionConfig",w),console.log("showImage",I);const B=!w||0===w.length||w.includes("options"),G=x.imageUrl?.trim()?x.imageUrl:"",L=Array.isArray(x.articles)&&x.articles.length>0;return r("div",{className:"space-y-4",children:[x.isGroup&&(x.groupTitle||x.groupSubtitle||x.groupContent||x.groupImageUrl||L)&&r("div",{className:"relative overflow-hidden rounded-2xl border border-indigo-100 bg-white shadow-sm ring-1 ring-black/5 transition-all",children:[e("div",{className:"absolute inset-0 bg-gradient-to-br from-indigo-50/80 via-white to-blue-50/30 opacity-70 pointer-events-none"}),e("div",{className:"absolute left-0 top-0 bottom-0 w-1.5 bg-gradient-to-b from-indigo-500 to-blue-600 rounded-l-2xl"}),r("div",{className:"relative p-6 sm:p-7",children:[r("div",{className:"flex items-start gap-4 mb-5 border-b border-indigo-50/60 pb-4",children:[e("div",{className:"flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-xl bg-gradient-to-br from-indigo-100 to-blue-100 shadow-inner ring-1 ring-indigo-200/50",children:e(g,{className:"h-5 w-5 text-indigo-600"})}),r("div",{className:"flex-1 pt-1",children:[e("div",{className:"flex items-center gap-2 mb-1",children:x.groupNumber&&r("span",{className:"inline-flex items-center rounded-md bg-indigo-50 px-2 py-1 text-xs font-semibold text-indigo-700 ring-1 ring-inset ring-indigo-700/10",children:["Bài đọc ",x.groupNumber]})}),x.groupTitle&&e("h4",{className:"text-xl font-bold text-slate-800 leading-tight tracking-tight",children:x.groupTitle}),x.groupSubtitle&&e("p",{className:"mt-1 text-sm text-slate-500 leading-snug",children:x.groupSubtitle})]})]}),L&&e("div",{className:"flex flex-col gap-4",children:x.articles.map((t,s)=>r("div",{className:"group relative overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm transition-all hover:shadow-md hover:border-indigo-200",children:[r("div",{className:"flex items-center gap-2 border-b border-slate-100 bg-gradient-to-r from-indigo-50/60 to-blue-50/40 px-4 py-2.5",children:[e("div",{className:"flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-lg bg-gradient-to-br from-indigo-500 to-blue-600 text-xs font-bold text-white shadow-sm",children:String.fromCharCode(65+s)}),e("h5",{className:"flex-1 truncate text-sm font-bold text-slate-800",children:t.name||`Bài viết ${s+1}`})]}),r("div",{className:"flex flex-col gap-3 p-4 sm:flex-row sm:items-start",children:[t.imageUrl&&e("div",{className:"flex flex-shrink-0 items-center justify-center rounded-md bg-slate-50 p-2 sm:w-40",children:e(p,{src:t.imageUrl,alt:t.name||`Article ${s+1}`,className:"max-h-40 w-auto rounded-md object-contain"})}),t.content&&e("div",{className:"prose prose-sm prose-slate max-w-none flex-1 text-[14px] leading-relaxed text-slate-700",children:t.content.split("\n").map((r,t)=>e("p",{className:"mb-2 last:mb-0",children:r},t))})]})]},s))}),!L&&r("div",{className:"space-y-6 text-slate-700",children:[x.groupContent&&e("div",{className:"prose prose-slate prose-p:leading-relaxed prose-p:mb-3 max-w-none text-[15px]",dangerouslySetInnerHTML:{__html:x.groupContent.replace(/\{(\d+)\}/g,(e,r)=>`<span style="display:inline-block;min-width:100px;padding:1px 5px;margin:0 5px;background:#eef2ff;border-bottom:2px solid #6366f1;color:#4f46e5;font-weight:700;font-size:0.85em;text-align:center;vertical-align:baseline;letter-spacing:2px">———(${Number(r)+1})———</span>`).split("\n").map(e=>`<p class="last:mb-0">${e}</p>`).join("")}}),x.groupImageUrl&&r("div",{className:"mt-5 relative overflow-hidden rounded-xl border border-slate-200/60 bg-slate-50 shadow-sm transition-all hover:shadow-md",children:[e("div",{className:"flex items-center justify-between border-b border-slate-200/60 bg-slate-100/50 px-4 py-2",children:r("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"h-2.5 w-2.5 rounded-full bg-slate-300"}),e("div",{className:"h-2.5 w-2.5 rounded-full bg-slate-300"}),e("div",{className:"h-2.5 w-2.5 rounded-full bg-slate-300"}),e("span",{className:"ml-2 text-[11px] font-semibold uppercase tracking-wider text-slate-500",children:"Tài liệu đính kèm"})]})}),e("div",{className:"flex items-center justify-center p-4 min-h-[160px]",children:e(p,{src:x.groupImageUrl,alt:x.groupTitle||"Group Image Attachment",className:"max-h-72 w-auto object-contain drop-shadow-sm rounded-lg"})})]})]})]})]}),r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center justify-between border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-5 py-3",children:[r("div",{className:"flex items-center gap-3",children:[e("div",{className:"flex h-8 w-8 items-center justify-center rounded-lg bg-gradient-to-br from-blue-500 to-indigo-600 text-white shadow-sm",children:e(d,{className:"h-4 w-4"})}),e("span",{className:"text-sm font-medium text-gray-700",children:v?"Chọn các đáp án đúng":"Chọn đáp án đúng"})]}),f&&S&&r("div",{className:b("flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold",T?"bg-green-100 text-green-700":"bg-red-100 text-red-700"),children:[e(T?n:i,{className:"h-3.5 w-3.5"}),T?"Đúng":"Sai"]})]}),r("div",{className:"p-5 space-y-5",children:[(x.askerName||x.answererName)&&r("div",{className:"flex items-center gap-4 rounded-lg border border-purple-100 bg-gradient-to-r from-purple-50 to-violet-50 px-4 py-3",children:[e(m,{className:"h-4 w-4 flex-shrink-0 text-purple-500"}),r("div",{className:"flex items-center gap-4 text-sm",children:[x.askerName&&r("div",{className:"flex items-center gap-1.5",children:[e("span",{className:"font-medium text-gray-500",children:"Người hỏi:"}),e("span",{className:"font-semibold text-purple-700",children:x.askerName})]}),x.askerName&&x.answererName&&e("div",{className:"h-4 w-px bg-purple-200"}),x.answererName&&r("div",{className:"flex items-center gap-1.5",children:[e("span",{className:"font-medium text-gray-500",children:"Người trả lời:"}),e("span",{className:"font-semibold text-purple-700",children:x.answererName})]})]})]}),q&&e("div",{className:"rounded-lg bg-gradient-to-r from-blue-50 to-indigo-50 p-4 border border-blue-100",children:e("h3",{className:"text-base font-semibold text-gray-800 leading-relaxed",children:x.question||"Câu hỏi chưa được nhập"})}),I&&(A||G)&&r("div",{className:"overflow-hidden rounded-lg border border-gray-200 bg-gradient-to-br from-slate-50 to-gray-100",children:[e("div",{className:"border-b border-gray-100 px-3 py-1.5",children:r("div",{className:"flex items-center gap-1.5",children:[e("div",{className:"h-2 w-2 rounded-full bg-red-400"}),e("div",{className:"h-2 w-2 rounded-full bg-yellow-400"}),e("div",{className:"h-2 w-2 rounded-full bg-green-400"}),e("span",{className:"ml-2 text-xs font-medium text-gray-500",children:"Hình ảnh"})]})}),e("div",{className:"flex items-center justify-center p-4",children:U?e("div",{className:"flex h-48 items-center justify-center",children:e("div",{className:"h-8 w-8 animate-spin rounded-full border-4 border-gray-200 border-t-blue-500"})}):e("img",{src:A||G,alt:"Question illustration",className:"max-h-56 w-auto object-contain rounded-md",onError:e=>{const r=e.target;r.onerror=null,r.src="/images/placeholder-image.svg"}})})]}),B&&r("div",{className:"space-y-2.5",children:[e("span",{className:"text-xs font-medium text-gray-500 uppercase tracking-wider",children:v?"Chọn một hoặc nhiều đáp án":"Chọn đáp án"}),x.options.map((t,s)=>{const a=C.includes(s),l=(d=s,!!f&&y.includes(d));var d;const o=String.fromCharCode(65+s);return r("button",{type:"button",onClick:()=>(e=>{if(f)return;const r=v?C.includes(e)?C.filter(r=>r!==e):[...C,e].sort((e,r)=>e-r):[e];k(r),u?.(v?r:r[0])})(s),disabled:f,className:b("group flex w-full items-center gap-3 rounded-lg border-2 p-3.5 text-left transition-all",f?l?"border-green-400 bg-green-50":a?"border-red-400 bg-red-50":"border-gray-200 bg-gray-50":a?"border-blue-500 bg-blue-50 shadow-sm ring-2 ring-blue-100":"border-gray-200 bg-white hover:border-gray-300 hover:bg-gray-50 hover:shadow-sm"),children:[e("div",{className:b("flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg text-sm font-bold transition-all",f?l?"bg-green-500 text-white":a?"bg-red-500 text-white":"bg-gray-200 text-gray-600":a?"bg-gradient-to-br from-blue-500 to-indigo-600 text-white shadow-sm":"bg-gray-100 text-gray-600 group-hover:bg-gray-200"),children:o}),"image"===x.optionType?e("div",{className:"flex-1 flex items-center justify-center py-1",children:e(p,{src:t,alt:`Đáp án ${o}`})}):e("span",{className:b("flex-1 text-sm font-medium",f&&l?"text-green-800":f&&a&&!l?"text-red-800":"text-gray-700"),children:t}),f&&(l||a)&&e("div",{className:b("flex h-6 w-6 items-center justify-center rounded-full",l?"bg-green-500":"bg-red-500"),children:e(l?n:i,{className:"h-4 w-4 text-white"})})]},s)})]}),!f&&!S&&r("div",{className:"rounded-lg border border-amber-200 bg-gradient-to-r from-amber-50 to-yellow-50 p-3 flex items-center gap-2",children:[e("div",{className:"flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full bg-amber-400 text-white",children:e("span",{className:"text-xs font-bold",children:"!"})}),e("span",{className:"text-sm text-amber-800",children:v?"Vui lòng chọn ít nhất một đáp án":"Vui lòng chọn một đáp án"})]})]})]}),f&&x.explanation&&r("div",{className:"overflow-hidden rounded-xl border border-blue-200 bg-gradient-to-br from-blue-50 to-indigo-50 shadow-sm",children:[r("div",{className:"flex items-center gap-2 border-b border-blue-100 bg-white/50 px-4 py-3",children:[e("div",{className:"flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-amber-400 to-orange-500 text-white shadow-sm",children:e(o,{className:"h-4 w-4"})}),e("h4",{className:"text-sm font-semibold text-gray-800",children:"Giải thích"})]}),e("div",{className:"p-4",children:e("p",{className:"text-sm text-gray-700 leading-relaxed",children:x.explanation})})]}),f&&r("div",{className:"overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm",children:[r("div",{className:"flex items-center gap-2 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white px-4 py-3",children:[e("div",{className:"flex h-7 w-7 items-center justify-center rounded-lg bg-gradient-to-br from-slate-500 to-gray-600 text-white shadow-sm",children:e(c,{className:"h-4 w-4"})}),e("h4",{className:"text-sm font-semibold text-gray-800",children:"Tổng kết"})]}),r("div",{className:"p-4 space-y-3",children:[r("div",{className:"flex items-center justify-between rounded-lg bg-gray-50 p-3",children:[e("span",{className:"text-sm text-gray-600",children:"Đáp án của bạn:"}),e("span",{className:b("text-sm font-semibold",T?"text-green-600":S?"text-red-600":"text-gray-500"),children:$(C)})]}),r("div",{className:"flex items-center justify-between rounded-lg bg-green-50 p-3 border border-green-100",children:[e("span",{className:"text-sm text-gray-600",children:"Đáp án đúng:"}),e("span",{className:"text-sm font-semibold text-green-600",children:$(y)})]}),r("div",{className:b("flex items-center justify-between rounded-lg p-3 border",T?"bg-green-50 border-green-200":"bg-red-50 border-red-200"),children:[e("span",{className:"text-sm text-gray-600",children:"Kết quả:"}),e("div",{className:b("flex items-center gap-1.5 text-sm font-semibold",T?"text-green-600":"text-red-600"),children:r(t,T?{children:[e(n,{className:"h-4 w-4"}),e("span",{children:"Chính xác"})]}:{children:[e(i,{className:"h-4 w-4"}),e("span",{children:"Sai"})]})})]})]})]})]})}
|