@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
|
@@ -1,153 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useMemo, useState } from 'react';
|
|
4
|
-
import { ArrowLeft, ArrowRight, Loader2, Send } from 'lucide-react';
|
|
5
|
-
import { Button } from '../../../components/ui/button';
|
|
6
|
-
import { CambridgeYleExamLayout, EnglishCertificationExamLayout, SummerSkyLayout } from '../../../components/themes';
|
|
7
|
-
import { useToast } from '../../../shared/lib/hooks/useToast';
|
|
8
|
-
import { GenericQuestionRenderer } from './GenericQuestionRenderer';
|
|
9
|
-
import { groupQuestions, unwrap, unwrapAttempt } from './exam-taking.utils';
|
|
10
|
-
export function ExamTakingPageContainer({ examId, api, exitPath = '/student/exams', onNavigate, onSubmitted }) {
|
|
11
|
-
const { error: errorToast, success } = useToast();
|
|
12
|
-
const [attempt, setAttempt] = useState(null);
|
|
13
|
-
const [parts, setParts] = useState([]);
|
|
14
|
-
const [questionsResult, setQuestionsResult] = useState(null);
|
|
15
|
-
const [partIndex, setPartIndex] = useState(0);
|
|
16
|
-
const [answers, setAnswers] = useState({});
|
|
17
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
18
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
19
|
-
useEffect(() => {
|
|
20
|
-
let ignore = false;
|
|
21
|
-
setIsLoading(true);
|
|
22
|
-
loadAttempt(api, examId)
|
|
23
|
-
.then(async (loadedAttempt) => {
|
|
24
|
-
const questions = unwrap(await api.getQuestions(loadedAttempt.id));
|
|
25
|
-
if (ignore)
|
|
26
|
-
return;
|
|
27
|
-
setAttempt(loadedAttempt);
|
|
28
|
-
setQuestionsResult(questions);
|
|
29
|
-
setParts(groupQuestions(questions));
|
|
30
|
-
})
|
|
31
|
-
.catch((err) => errorToast({ message: 'Không tải được bài thi', description: err instanceof Error ? err.message : undefined }))
|
|
32
|
-
.finally(() => { if (!ignore)
|
|
33
|
-
setIsLoading(false); });
|
|
34
|
-
return () => { ignore = true; };
|
|
35
|
-
}, [api, examId, errorToast]);
|
|
36
|
-
const currentPart = parts[partIndex];
|
|
37
|
-
const flatQuestions = useMemo(() => parts.flatMap((part) => part.questions), [parts]);
|
|
38
|
-
const currentQuestionIndex = useMemo(() => flatQuestions.findIndex((question) => currentPart?.questions[0]?.id === question.id), [currentPart?.questions, flatQuestions]);
|
|
39
|
-
const answeredCount = useMemo(() => Object.values(answers).filter((value) => value !== '' && value !== null && value !== undefined).length, [answers]);
|
|
40
|
-
const totalQuestions = flatQuestions.length;
|
|
41
|
-
const theme = normalizeTheme(questionsResult?.examTemplate?.theme);
|
|
42
|
-
const examName = questionsResult?.examTemplate?.title ?? 'Làm bài thi';
|
|
43
|
-
const remainingSeconds = getRemainingSeconds(attempt);
|
|
44
|
-
const navigate = (href) => {
|
|
45
|
-
if (onNavigate)
|
|
46
|
-
onNavigate(href);
|
|
47
|
-
else if (typeof window !== 'undefined')
|
|
48
|
-
window.location.href = href;
|
|
49
|
-
};
|
|
50
|
-
const handleAnswerChange = async (questionId, answer) => {
|
|
51
|
-
setAnswers((prev) => ({ ...prev, [questionId]: answer }));
|
|
52
|
-
if (attempt && api.saveAnswers)
|
|
53
|
-
await api.saveAnswers({ attemptId: attempt.id, answers: [{ questionId, answer }] });
|
|
54
|
-
};
|
|
55
|
-
const handleSubmit = async () => {
|
|
56
|
-
if (!attempt)
|
|
57
|
-
return;
|
|
58
|
-
setIsSubmitting(true);
|
|
59
|
-
try {
|
|
60
|
-
await api.submitAttempt(attempt.id);
|
|
61
|
-
success({ message: 'Đã nộp bài' });
|
|
62
|
-
onSubmitted?.(attempt.id);
|
|
63
|
-
}
|
|
64
|
-
catch (err) {
|
|
65
|
-
errorToast({ message: 'Không nộp được bài', description: err instanceof Error ? err.message : undefined });
|
|
66
|
-
}
|
|
67
|
-
finally {
|
|
68
|
-
setIsSubmitting(false);
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
if (isLoading)
|
|
72
|
-
return _jsx(Loading, {});
|
|
73
|
-
if (!attempt || !currentPart)
|
|
74
|
-
return _jsx(Empty, { onExit: () => navigate(exitPath) });
|
|
75
|
-
const content = _jsx(QuestionList, { part: currentPart, answers: answers, onAnswerChange: handleAnswerChange });
|
|
76
|
-
const goPrev = () => setPartIndex((prev) => Math.max(0, prev - 1));
|
|
77
|
-
const goNext = () => setPartIndex((prev) => Math.min(parts.length - 1, prev + 1));
|
|
78
|
-
const isFirstPart = partIndex === 0;
|
|
79
|
-
const isLastPart = partIndex >= parts.length - 1;
|
|
80
|
-
if (theme === 'ENGLISH_CERTIFICATION') {
|
|
81
|
-
return (_jsx(EnglishCertificationExamLayout, { headerProps: { examName, remainingSeconds, totalQuestions, answeredCount, isSubmitting, onSubmit: handleSubmit, onClose: () => navigate(exitPath), lastSavedAt: null, isSaving: false, partLabel: currentPart.name, questionRange: getQuestionRange(currentPart) }, navigationProps: { parts: toStoreParts(parts), questions: toStudentQuestions(flatQuestions), answers, flaggedQuestions: new Set(), currentIndex: Math.max(0, currentQuestionIndex), onQuestionClick: (index) => setPartIndex(findPartIndex(parts, index)), onPartClick: setPartIndex }, footerProps: { onPrevious: goPrev, onNext: goNext, onClear: () => undefined, onToggleMark: () => undefined, isPreviousDisabled: isFirstPart, isNextDisabled: isLastPart, isMarked: false }, children: content }));
|
|
82
|
-
}
|
|
83
|
-
if (theme === 'CAMBRIDGE_YLE') {
|
|
84
|
-
return (_jsx(CambridgeYleExamLayout, { onPrevious: goPrev, onNext: goNext, onClose: () => navigate(exitPath), isFirstQuestion: isFirstPart, isLastQuestion: isLastPart, headerProps: { examName, examType: 'Exam', totalQuestions, answeredCount, remainingSeconds, isSubmitting, onSubmit: handleSubmit }, sidebarProps: toCambridgeSidebar(parts, answers, Math.max(0, currentQuestionIndex), setPartIndex), children: content }));
|
|
85
|
-
}
|
|
86
|
-
if (theme === 'SUMMER_SKY') {
|
|
87
|
-
return (_jsx(SummerSkyLayout, { onExit: () => navigate(exitPath), partName: currentPart.name, instruction: currentPart.instructions ?? '', onPrev: goPrev, onNext: goNext, canGoPrev: !isFirstPart, canGoNext: !isLastPart, audioUrl: currentPart.audioUrl ?? '', questionNumber: partIndex + 1, recorder: null, children: content }));
|
|
88
|
-
}
|
|
89
|
-
return _jsx(DefaultLayout, { title: examName, answeredCount: answeredCount, totalQuestions: totalQuestions, onExit: () => navigate(exitPath), onPrev: goPrev, onNext: goNext, isFirst: isFirstPart, isLast: isLastPart, currentPart: currentPart, onSubmit: handleSubmit, isSubmitting: isSubmitting, children: content });
|
|
90
|
-
}
|
|
91
|
-
async function loadAttempt(api, examId) {
|
|
92
|
-
const activeAttempt = unwrap(await api.getActiveAttempt(examId));
|
|
93
|
-
if (activeAttempt)
|
|
94
|
-
return activeAttempt;
|
|
95
|
-
return unwrapAttempt(unwrap(await api.startAttempt(examId)));
|
|
96
|
-
}
|
|
97
|
-
function QuestionList({ part, answers, onAnswerChange }) {
|
|
98
|
-
return _jsx("div", { className: "space-y-4", children: part.questions.map((question) => _jsx(GenericQuestionRenderer, { question: question, value: answers[question.id], onChange: onAnswerChange }, question.id)) });
|
|
99
|
-
}
|
|
100
|
-
function DefaultLayout({ title, answeredCount, totalQuestions, onExit, onPrev, onNext, isFirst, isLast, currentPart, onSubmit, isSubmitting, children }) {
|
|
101
|
-
return (_jsxs("div", { className: "min-h-screen bg-slate-50", children: [_jsx("header", { className: "sticky top-0 z-10 border-b bg-white px-4 py-3 shadow-sm", children: _jsxs("div", { className: "mx-auto flex max-w-5xl items-center justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h1", { className: "font-semibold text-gray-900", children: title }), _jsxs("p", { className: "text-sm text-gray-500", children: ["\u0110\u00E3 tr\u1EA3 l\u1EDDi ", answeredCount, "/", totalQuestions] })] }), _jsx(Button, { variant: "outline", onClick: onExit, children: "Tho\u00E1t" })] }) }), _jsxs("main", { className: "mx-auto max-w-5xl space-y-4 p-4", children: [_jsxs("div", { className: "flex items-center justify-between rounded-lg bg-white p-4 shadow-sm", children: [_jsxs(Button, { variant: "outline", disabled: isFirst, onClick: onPrev, children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), "Ph\u1EA7n tr\u01B0\u1EDBc"] }), _jsx("div", { className: "text-center", children: _jsx("h2", { className: "font-medium", children: currentPart.name }) }), _jsxs(Button, { variant: "outline", disabled: isLast, onClick: onNext, children: ["Ph\u1EA7n sau", _jsx(ArrowRight, { className: "ml-2 h-4 w-4" })] })] }), children, _jsx("div", { className: "flex justify-end", children: _jsxs(Button, { onClick: onSubmit, disabled: isSubmitting, className: "bg-blue-600 hover:bg-blue-700", children: [isSubmitting ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(Send, { className: "mr-2 h-4 w-4" }), "N\u1ED9p b\u00E0i"] }) })] })] }));
|
|
102
|
-
}
|
|
103
|
-
function normalizeTheme(theme) {
|
|
104
|
-
if (theme === 'ENGLISH_CERTIFICATION')
|
|
105
|
-
return theme;
|
|
106
|
-
if (theme === 'CAMBRIDGE_YLE')
|
|
107
|
-
return theme;
|
|
108
|
-
if (theme === 'SUMMER_SKY')
|
|
109
|
-
return theme;
|
|
110
|
-
return 'DEFAULT';
|
|
111
|
-
}
|
|
112
|
-
function getRemainingSeconds(attempt) {
|
|
113
|
-
if (!attempt)
|
|
114
|
-
return 0;
|
|
115
|
-
const end = new Date(attempt.startedAt).getTime() + attempt.durationMinutes * 60000;
|
|
116
|
-
return Math.max(0, Math.floor((end - Date.now()) / 1000));
|
|
117
|
-
}
|
|
118
|
-
function getQuestionRange(part) {
|
|
119
|
-
const numbers = part.questions.map((question) => question.question_number).filter((value) => Number.isFinite(value));
|
|
120
|
-
if (numbers.length === 0)
|
|
121
|
-
return '';
|
|
122
|
-
return `${Math.min(...numbers)}–${Math.max(...numbers)}`;
|
|
123
|
-
}
|
|
124
|
-
function toStoreParts(parts) {
|
|
125
|
-
let index = 0;
|
|
126
|
-
return parts.map((part) => {
|
|
127
|
-
const startIndex = index;
|
|
128
|
-
index += part.questions.length;
|
|
129
|
-
return { id: part.id, name: part.name, category: part.template?.category, startIndex, endIndex: index - 1, questionCount: part.questions.length, audioUrl: part.audioUrl, isGroup: part.isGroup };
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
function toStudentQuestions(questions) {
|
|
133
|
-
return questions.map((question) => ({ id: question.id, question_type: question.question_type, content: question.content ?? {}, is_example: Boolean(question.is_example), total_points: String(question.total_points ?? 0), part_id: question.part_id ?? '', part_no: question.part_no ?? 0, question_number: question.question_number }));
|
|
134
|
-
}
|
|
135
|
-
function findPartIndex(parts, questionIndex) {
|
|
136
|
-
let cursor = 0;
|
|
137
|
-
for (let index = 0; index < parts.length; index += 1) {
|
|
138
|
-
cursor += parts[index].questions.length;
|
|
139
|
-
if (questionIndex < cursor)
|
|
140
|
-
return index;
|
|
141
|
-
}
|
|
142
|
-
return 0;
|
|
143
|
-
}
|
|
144
|
-
function toCambridgeSidebar(parts, answers, currentQuestionGlobalIndex, onPartClick) {
|
|
145
|
-
const questions = parts.flatMap((part, partIndex) => part.questions.map((question, index) => ({ globalIndex: parts.slice(0, partIndex).reduce((sum, item) => sum + item.questions.length, 0) + index, partIndex, questionNumber: question.question_number, isAnswered: answers[question.id] !== undefined && answers[question.id] !== '' })));
|
|
146
|
-
return { parts: parts.map((part, partIndex) => ({ partIndex, partNo: part.partNo ?? partIndex + 1, name: part.name, category: part.template?.category, totalQuestions: part.questions.length, answeredCount: part.questions.filter((question) => answers[question.id] !== undefined && answers[question.id] !== '').length })), questions, currentQuestionGlobalIndex, onPartClick, onQuestionClick: (index) => onPartClick(findPartIndex(parts, index)) };
|
|
147
|
-
}
|
|
148
|
-
function Loading() {
|
|
149
|
-
return _jsx("div", { className: "flex h-screen items-center justify-center", children: _jsx(Loader2, { className: "h-8 w-8 animate-spin text-blue-600" }) });
|
|
150
|
-
}
|
|
151
|
-
function Empty({ onExit }) {
|
|
152
|
-
return _jsxs("div", { className: "flex h-screen flex-col items-center justify-center gap-4", children: [_jsx("p", { children: "Kh\u00F4ng c\u00F3 c\u00E2u h\u1ECFi." }), _jsx(Button, { onClick: onExit, children: "Quay l\u1EA1i" })] });
|
|
153
|
-
}
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useEffect as n,useMemo as i,useState as s}from"react";import{ArrowLeft as a,ArrowRight as r,Loader2 as o,Send as l}from"lucide-react";import{Button as u}from"../../../components/ui/button";import{CambridgeYleExamLayout as c,EnglishCertificationExamLayout as m,SummerSkyLayout as d}from"../../../components/themes";import{useToast as h}from"../../../shared/lib/hooks/useToast";import{GenericQuestionRenderer as p}from"./GenericQuestionRenderer";import{groupQuestions as x,unwrap as g,unwrapAttempt as f}from"./exam-taking.utils";export function ExamTakingPageContainer({examId:t,api:a,exitPath:r="/student/exams",onNavigate:o,onSubmitted:l}){const{error:u,success:p}=h(),[S,E]=s(null),[P,_]=s([]),[M,A]=s(null),[k,Q]=s(0),[T,G]=s({}),[L,j]=s(!0),[R,D]=s(!1);n(()=>{let e=!1;return j(!0),async function(e,t){const n=g(await e.getActiveAttempt(t));return n||f(g(await e.startAttempt(t)))}(a,t).then(async t=>{const n=g(await a.getQuestions(t.id));e||(E(t),A(n),_(x(n)))}).catch(e=>u({message:"Không tải được bài thi",description:e instanceof Error?e.message:void 0})).finally(()=>{e||j(!1)}),()=>{e=!0}},[a,t,u]);const F=P[k],U=i(()=>P.flatMap(e=>e.questions),[P]),K=i(()=>U.findIndex(e=>F?.questions[0]?.id===e.id),[F?.questions,U]),Y=i(()=>Object.values(T).filter(e=>""!==e&&null!=e).length,[T]),B=U.length,O=function(e){return"ENGLISH_CERTIFICATION"===e||"CAMBRIDGE_YLE"===e||"SUMMER_SKY"===e?e:"DEFAULT"}(M?.examTemplate?.theme),H=M?.examTemplate?.title??"Làm bài thi",$=function(e){if(!e)return 0;const t=new Date(e.startedAt).getTime()+6e4*e.durationMinutes;return Math.max(0,Math.floor((t-Date.now())/1e3))}(S),z=e=>{o?o(e):"undefined"!=typeof window&&(window.location.href=e)},J=async()=>{if(S){D(!0);try{await a.submitAttempt(S.id),p({message:"Đã nộp bài"}),l?.(S.id)}catch(e){u({message:"Không nộp được bài",description:e instanceof Error?e.message:void 0})}finally{D(!1)}}};if(L)return e(q,{});if(!S||!F)return e(I,{onExit:()=>z(r)});const V=e(b,{part:F,answers:T,onAnswerChange:async(e,t)=>{G(n=>({...n,[e]:t})),S&&a.saveAnswers&&await a.saveAnswers({attemptId:S.id,answers:[{questionId:e,answer:t}]})}}),W=()=>Q(e=>Math.max(0,e-1)),X=()=>Q(e=>Math.min(P.length-1,e+1)),Z=0===k,ee=k>=P.length-1;return"ENGLISH_CERTIFICATION"===O?e(m,{headerProps:{examName:H,remainingSeconds:$,totalQuestions:B,answeredCount:Y,isSubmitting:R,onSubmit:J,onClose:()=>z(r),lastSavedAt:null,isSaving:!1,partLabel:F.name,questionRange:N(F)},navigationProps:{parts:v(P),questions:(te=U,te.map(e=>({id:e.id,question_type:e.question_type,content:e.content??{},is_example:Boolean(e.is_example),total_points:String(e.total_points??0),part_id:e.part_id??"",part_no:e.part_no??0,question_number:e.question_number}))),answers:T,flaggedQuestions:new Set,currentIndex:Math.max(0,K),onQuestionClick:e=>Q(C(P,e)),onPartClick:Q},footerProps:{onPrevious:W,onNext:X,onClear:()=>{},onToggleMark:()=>{},isPreviousDisabled:Z,isNextDisabled:ee,isMarked:!1},children:V}):"CAMBRIDGE_YLE"===O?e(c,{onPrevious:W,onNext:X,onClose:()=>z(r),isFirstQuestion:Z,isLastQuestion:ee,headerProps:{examName:H,examType:"Exam",totalQuestions:B,answeredCount:Y,remainingSeconds:$,isSubmitting:R,onSubmit:J},sidebarProps:y(P,T,Math.max(0,K),Q),children:V}):"SUMMER_SKY"===O?e(d,{onExit:()=>z(r),partName:F.name,instruction:F.instructions??"",onPrev:W,onNext:X,canGoPrev:!Z,canGoNext:!ee,audioUrl:F.audioUrl??"",questionNumber:k+1,recorder:null,children:V}):e(w,{title:H,answeredCount:Y,totalQuestions:B,onExit:()=>z(r),onPrev:W,onNext:X,isFirst:Z,isLast:ee,currentPart:F,onSubmit:J,isSubmitting:R,children:V});var te}function b({part:t,answers:n,onAnswerChange:i}){return e("div",{className:"space-y-4",children:t.questions.map(t=>e(p,{question:t,value:n[t.id],onChange:i},t.id))})}function w({title:n,answeredCount:i,totalQuestions:s,onExit:c,onPrev:m,onNext:d,isFirst:h,isLast:p,currentPart:x,onSubmit:g,isSubmitting:f,children:b}){return t("div",{className:"min-h-screen bg-slate-50",children:[e("header",{className:"sticky top-0 z-10 border-b bg-white px-4 py-3 shadow-sm",children:t("div",{className:"mx-auto flex max-w-5xl items-center justify-between gap-4",children:[t("div",{children:[e("h1",{className:"font-semibold text-gray-900",children:n}),t("p",{className:"text-sm text-gray-500",children:["Đã trả lời ",i,"/",s]})]}),e(u,{variant:"outline",onClick:c,children:"Thoát"})]})}),t("main",{className:"mx-auto max-w-5xl space-y-4 p-4",children:[t("div",{className:"flex items-center justify-between rounded-lg bg-white p-4 shadow-sm",children:[t(u,{variant:"outline",disabled:h,onClick:m,children:[e(a,{className:"mr-2 h-4 w-4"}),"Phần trước"]}),e("div",{className:"text-center",children:e("h2",{className:"font-medium",children:x.name})}),t(u,{variant:"outline",disabled:p,onClick:d,children:["Phần sau",e(r,{className:"ml-2 h-4 w-4"})]})]}),b,e("div",{className:"flex justify-end",children:t(u,{onClick:g,disabled:f,className:"bg-blue-600 hover:bg-blue-700",children:[f?e(o,{className:"mr-2 h-4 w-4 animate-spin"}):e(l,{className:"mr-2 h-4 w-4"}),"Nộp bài"]})})]})]})}function N(e){const t=e.questions.map(e=>e.question_number).filter(e=>Number.isFinite(e));return 0===t.length?"":`${Math.min(...t)}–${Math.max(...t)}`}function v(e){let t=0;return e.map(e=>{const n=t;return t+=e.questions.length,{id:e.id,name:e.name,category:e.template?.category,startIndex:n,endIndex:t-1,questionCount:e.questions.length,audioUrl:e.audioUrl,isGroup:e.isGroup}})}function C(e,t){let n=0;for(let i=0;i<e.length;i+=1)if(n+=e[i].questions.length,t<n)return i;return 0}function y(e,t,n,i){const s=e.flatMap((n,i)=>n.questions.map((n,s)=>({globalIndex:e.slice(0,i).reduce((e,t)=>e+t.questions.length,0)+s,partIndex:i,questionNumber:n.question_number,isAnswered:void 0!==t[n.id]&&""!==t[n.id]})));return{parts:e.map((e,n)=>({partIndex:n,partNo:e.partNo??n+1,name:e.name,category:e.template?.category,totalQuestions:e.questions.length,answeredCount:e.questions.filter(e=>void 0!==t[e.id]&&""!==t[e.id]).length})),questions:s,currentQuestionGlobalIndex:n,onPartClick:i,onQuestionClick:t=>i(C(e,t))}}function q(){return e("div",{className:"flex h-screen items-center justify-center",children:e(o,{className:"h-8 w-8 animate-spin text-blue-600"})})}function I({onExit:n}){return t("div",{className:"flex h-screen flex-col items-center justify-center gap-4",children:[e("p",{children:"Không có câu hỏi."}),e(u,{onClick:n,children:"Quay lại"})]})}
|
|
@@ -1,14 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { Textarea } from '../../../components/ui/textarea';
|
|
4
|
-
import { Label } from '../../../components/ui/label';
|
|
5
|
-
export function GenericQuestionRenderer({ question, value, onChange }) {
|
|
6
|
-
return (_jsxs("div", { className: "rounded-lg border border-gray-200 bg-white p-4 shadow-sm", children: [_jsxs("div", { className: "mb-3 flex items-center justify-between gap-3", children: [_jsxs("h3", { className: "font-medium text-gray-900", children: ["C\u00E2u ", question.question_number] }), _jsx("span", { className: "rounded bg-gray-100 px-2 py-1 text-xs text-gray-600", children: question.question_type })] }), _jsx(QuestionContent, { content: question.content }), _jsxs("div", { className: "mt-4 space-y-2", children: [_jsx(Label, { htmlFor: `answer-${question.id}`, children: "C\u00E2u tr\u1EA3 l\u1EDDi" }), _jsx(Textarea, { id: `answer-${question.id}`, value: typeof value === 'string' ? value : value ? JSON.stringify(value) : '', onChange: (event) => onChange(question.id, event.target.value), placeholder: "Nh\u1EADp c\u00E2u tr\u1EA3 l\u1EDDi" })] })] }));
|
|
7
|
-
}
|
|
8
|
-
function QuestionContent({ content }) {
|
|
9
|
-
if (typeof content === 'string')
|
|
10
|
-
return _jsx("p", { className: "whitespace-pre-wrap text-sm text-gray-700", children: content });
|
|
11
|
-
if (typeof content === 'object' && content !== null)
|
|
12
|
-
return _jsx("pre", { className: "max-h-48 overflow-auto rounded bg-gray-50 p-3 text-xs text-gray-600", children: JSON.stringify(content, null, 2) });
|
|
13
|
-
return _jsx("p", { className: "text-sm text-gray-500", children: "Kh\u00F4ng c\u00F3 n\u1ED9i dung c\u00E2u h\u1ECFi." });
|
|
14
|
-
}
|
|
1
|
+
"use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import{Textarea as r}from"../../../components/ui/textarea";import{Label as n}from"../../../components/ui/label";export function GenericQuestionRenderer({question:s,value:i,onChange:o}){return e("div",{className:"rounded-lg border border-gray-200 bg-white p-4 shadow-sm",children:[e("div",{className:"mb-3 flex items-center justify-between gap-3",children:[e("h3",{className:"font-medium text-gray-900",children:["Câu ",s.question_number]}),t("span",{className:"rounded bg-gray-100 px-2 py-1 text-xs text-gray-600",children:s.question_type})]}),t(a,{content:s.content}),e("div",{className:"mt-4 space-y-2",children:[t(n,{htmlFor:`answer-${s.id}`,children:"Câu trả lời"}),t(r,{id:`answer-${s.id}`,value:"string"==typeof i?i:i?JSON.stringify(i):"",onChange:e=>o(s.id,e.target.value),placeholder:"Nhập câu trả lời"})]})]})}function a({content:e}){return"string"==typeof e?t("p",{className:"whitespace-pre-wrap text-sm text-gray-700",children:e}):"object"==typeof e&&null!==e?t("pre",{className:"max-h-48 overflow-auto rounded bg-gray-50 p-3 text-xs text-gray-600",children:JSON.stringify(e,null,2)}):t("p",{className:"text-sm text-gray-500",children:"Không có nội dung câu hỏi."})}
|
|
@@ -1,88 +1 @@
|
|
|
1
|
-
export function unwrap(value) {
|
|
2
|
-
return hasData(value) ? value.data : value;
|
|
3
|
-
}
|
|
4
|
-
export function unwrapAttempt(value) {
|
|
5
|
-
return 'attempt' in value ? value.attempt : value;
|
|
6
|
-
}
|
|
7
|
-
export function groupQuestions(result) {
|
|
8
|
-
const templates = result.examTemplate?.parts ?? [];
|
|
9
|
-
const parts = new Map();
|
|
10
|
-
for (const question of result.questions) {
|
|
11
|
-
const key = question.part_id ?? String(question.part_no ?? 'default');
|
|
12
|
-
parts.set(key, [...(parts.get(key) ?? []), question]);
|
|
13
|
-
}
|
|
14
|
-
return Array.from(parts.entries()).map(([id, questions]) => {
|
|
15
|
-
const template = templates.find((part) => String(part.id) === id);
|
|
16
|
-
return {
|
|
17
|
-
id,
|
|
18
|
-
name: template?.name ?? `Part ${questions[0]?.part_no ?? id}`,
|
|
19
|
-
template,
|
|
20
|
-
partId: id,
|
|
21
|
-
partNo: questions[0]?.part_no,
|
|
22
|
-
instructions: template?.instructions,
|
|
23
|
-
audioUrl: template?.audioUrl,
|
|
24
|
-
questionType: template?.questionType ?? questions[0]?.question_type,
|
|
25
|
-
isGroup: template?.isGroup,
|
|
26
|
-
group: template?.group,
|
|
27
|
-
sections: template?.sections,
|
|
28
|
-
viewMode: typeof template?.group?.viewMode === 'string' ? template.group.viewMode : undefined,
|
|
29
|
-
startIndex: template?.startIndex,
|
|
30
|
-
endIndex: template?.endIndex,
|
|
31
|
-
questions: questions.sort((a, b) => a.question_number - b.question_number),
|
|
32
|
-
};
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
export function transformAnswerTheQuestion(questions) {
|
|
36
|
-
return {
|
|
37
|
-
instruction: readString(questions[0]?.content, 'instruction'),
|
|
38
|
-
imageUrl: readString(questions[0]?.content, 'imageUrl'),
|
|
39
|
-
title: readString(questions[0]?.content, 'title'),
|
|
40
|
-
groupContent: readString(questions[0]?.content, 'groupContent'),
|
|
41
|
-
questions: questions.map((question) => ({ id: question.id, questionNumber: question.question_number, question: readString(question.content, 'question') || readString(question.content, 'text'), imageUrl: readString(question.content, 'imageUrl'), prefixText: readString(question.content, 'prefixText'), suffixText: readString(question.content, 'suffixText'), exampleAnswer: readString(question.content, 'exampleAnswer'), suggestedAnswers: readStringArray(question.content, 'suggestedAnswers'), isExample: Boolean(question.is_example) })),
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
export function transformMatchByWritingAnswer(questions) {
|
|
45
|
-
return {
|
|
46
|
-
instruction: readString(questions[0]?.content, 'instruction'),
|
|
47
|
-
groupImageUrl: readString(questions[0]?.content, 'groupImageUrl'),
|
|
48
|
-
options: readObjectArray(questions[0]?.content, 'options').map((option) => ({ answer: String(option.answer ?? option.value ?? ''), text: String(option.text ?? option.label ?? ''), content: String(option.content ?? option.text ?? option.label ?? ''), imageUrl: typeof option.imageUrl === 'string' ? option.imageUrl : undefined })),
|
|
49
|
-
questions: questions.map((question) => ({ id: question.id, questionNumber: question.question_number, question: readString(question.content, 'question') || readString(question.content, 'text'), imageUrl: readString(question.content, 'imageUrl'), exampleAnswer: readString(question.content, 'exampleAnswer'), isExample: Boolean(question.is_example) })),
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
export function transformWordFillParagraph(questions) {
|
|
53
|
-
const first = questions[0];
|
|
54
|
-
return { questionId: first?.id ?? '', paragraph: readString(first?.content, 'paragraph') || readString(first?.content, 'text'), title: readString(first?.content, 'title'), imageUrl: readString(first?.content, 'imageUrl'), wordBank: readObjectArray(first?.content, 'wordBank').map((item) => ({ word: String(item.word ?? item.text ?? ''), isExample: Boolean(item.isExample) })), viewMode: readString(first?.content, 'viewMode'), instruction: readString(first?.content, 'instruction') };
|
|
55
|
-
}
|
|
56
|
-
export function transformWriteShortLetter(question) {
|
|
57
|
-
return { prompt: readString(question?.content, 'prompt') || readString(question?.content, 'question'), requirements: readStringArray(question?.content, 'requirements'), minWords: readNumber(question?.content, 'minWords'), maxWords: readNumber(question?.content, 'maxWords'), guideImages: readStringArray(question?.content, 'guideImages') };
|
|
58
|
-
}
|
|
59
|
-
export function transformWordFillStructuredForm(questions) {
|
|
60
|
-
return { instruction: readString(questions[0]?.content, 'instruction'), groupTitle: readString(questions[0]?.content, 'groupTitle'), groupContent: readString(questions[0]?.content, 'groupContent'), groupImageUrl: readString(questions[0]?.content, 'groupImageUrl'), questions: questions.map((question) => ({ id: question.id, title: readString(question.content, 'title'), content: readString(question.content, 'content') || readString(question.content, 'html') || readString(question.content, 'text'), answers: readRecord(question.content, 'answers'), caseSensitive: Boolean(asRecord(question.content).caseSensitive), imageUrl: readString(question.content, 'imageUrl'), questionNumber: question.question_number })) };
|
|
61
|
-
}
|
|
62
|
-
function hasData(value) {
|
|
63
|
-
return typeof value === 'object' && value !== null && 'data' in value;
|
|
64
|
-
}
|
|
65
|
-
function asRecord(value) {
|
|
66
|
-
return typeof value === 'object' && value !== null ? value : {};
|
|
67
|
-
}
|
|
68
|
-
function readString(value, key) {
|
|
69
|
-
const item = asRecord(value)[key];
|
|
70
|
-
return typeof item === 'string' ? item : '';
|
|
71
|
-
}
|
|
72
|
-
function readNumber(value, key) {
|
|
73
|
-
const item = asRecord(value)[key];
|
|
74
|
-
return typeof item === 'number' ? item : undefined;
|
|
75
|
-
}
|
|
76
|
-
function readStringArray(value, key) {
|
|
77
|
-
const item = asRecord(value)[key];
|
|
78
|
-
return Array.isArray(item) ? item.filter((entry) => typeof entry === 'string') : [];
|
|
79
|
-
}
|
|
80
|
-
function readObjectArray(value, key) {
|
|
81
|
-
const item = asRecord(value)[key];
|
|
82
|
-
return Array.isArray(item) ? item.map(asRecord) : [];
|
|
83
|
-
}
|
|
84
|
-
function readRecord(value, key) {
|
|
85
|
-
const item = asRecord(value)[key];
|
|
86
|
-
const record = asRecord(item);
|
|
87
|
-
return Object.fromEntries(Object.entries(record).map(([entryKey, entryValue]) => [entryKey, String(entryValue ?? '')]));
|
|
88
|
-
}
|
|
1
|
+
export function unwrap(t){return function(t){return"object"==typeof t&&null!==t&&"data"in t}(t)?t.data:t}export function unwrapAttempt(t){return"attempt"in t?t.attempt:t}export function groupQuestions(t){const n=t.examTemplate?.parts??[],e=new Map;for(const n of t.questions){const t=n.part_id??String(n.part_no??"default");e.set(t,[...e.get(t)??[],n])}return Array.from(e.entries()).map(([t,e])=>{const o=n.find(n=>String(n.id)===t);return{id:t,name:o?.name??`Part ${e[0]?.part_no??t}`,template:o,partId:t,partNo:e[0]?.part_no,instructions:o?.instructions,audioUrl:o?.audioUrl,questionType:o?.questionType??e[0]?.question_type,isGroup:o?.isGroup,group:o?.group,sections:o?.sections,viewMode:"string"==typeof o?.group?.viewMode?o.group.viewMode:void 0,startIndex:o?.startIndex,endIndex:o?.endIndex,questions:e.sort((t,n)=>t.question_number-n.question_number)}})}export function transformAnswerTheQuestion(t){return{instruction:n(t[0]?.content,"instruction"),imageUrl:n(t[0]?.content,"imageUrl"),title:n(t[0]?.content,"title"),groupContent:n(t[0]?.content,"groupContent"),questions:t.map(t=>({id:t.id,questionNumber:t.question_number,question:n(t.content,"question")||n(t.content,"text"),imageUrl:n(t.content,"imageUrl"),prefixText:n(t.content,"prefixText"),suffixText:n(t.content,"suffixText"),exampleAnswer:n(t.content,"exampleAnswer"),suggestedAnswers:o(t.content,"suggestedAnswers"),isExample:Boolean(t.is_example)}))}}export function transformMatchByWritingAnswer(t){return{instruction:n(t[0]?.content,"instruction"),groupImageUrl:n(t[0]?.content,"groupImageUrl"),options:r(t[0]?.content,"options").map(t=>({answer:String(t.answer??t.value??""),text:String(t.text??t.label??""),content:String(t.content??t.text??t.label??""),imageUrl:"string"==typeof t.imageUrl?t.imageUrl:void 0})),questions:t.map(t=>({id:t.id,questionNumber:t.question_number,question:n(t.content,"question")||n(t.content,"text"),imageUrl:n(t.content,"imageUrl"),exampleAnswer:n(t.content,"exampleAnswer"),isExample:Boolean(t.is_example)}))}}export function transformWordFillParagraph(t){const e=t[0];return{questionId:e?.id??"",paragraph:n(e?.content,"paragraph")||n(e?.content,"text"),title:n(e?.content,"title"),imageUrl:n(e?.content,"imageUrl"),wordBank:r(e?.content,"wordBank").map(t=>({word:String(t.word??t.text??""),isExample:Boolean(t.isExample)})),viewMode:n(e?.content,"viewMode"),instruction:n(e?.content,"instruction")}}export function transformWriteShortLetter(t){return{prompt:n(t?.content,"prompt")||n(t?.content,"question"),requirements:o(t?.content,"requirements"),minWords:e(t?.content,"minWords"),maxWords:e(t?.content,"maxWords"),guideImages:o(t?.content,"guideImages")}}export function transformWordFillStructuredForm(e){return{instruction:n(e[0]?.content,"instruction"),groupTitle:n(e[0]?.content,"groupTitle"),groupContent:n(e[0]?.content,"groupContent"),groupImageUrl:n(e[0]?.content,"groupImageUrl"),questions:e.map(e=>({id:e.id,title:n(e.content,"title"),content:n(e.content,"content")||n(e.content,"html")||n(e.content,"text"),answers:i(e.content,"answers"),caseSensitive:Boolean(t(e.content).caseSensitive),imageUrl:n(e.content,"imageUrl"),questionNumber:e.question_number}))}}function t(t){return"object"==typeof t&&null!==t?t:{}}function n(n,e){const o=t(n)[e];return"string"==typeof o?o:""}function e(n,e){const o=t(n)[e];return"number"==typeof o?o:void 0}function o(n,e){const o=t(n)[e];return Array.isArray(o)?o.filter(t=>"string"==typeof t):[]}function r(n,e){const o=t(n)[e];return Array.isArray(o)?o.map(t):[]}function i(n,e){const o=t(n)[e],r=t(o);return Object.fromEntries(Object.entries(r).map(([t,n])=>[t,String(n??"")]))}
|
|
@@ -1,24 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { useRef, useState } from 'react';
|
|
3
|
-
export function useSpeakingRecorder(_options) {
|
|
4
|
-
const mediaRecorderRef = useRef(null);
|
|
5
|
-
const chunksRef = useRef([]);
|
|
6
|
-
const [status, setStatus] = useState('idle');
|
|
7
|
-
const [previewUrl, setPreviewUrl] = useState(null);
|
|
8
|
-
const startRecording = async () => {
|
|
9
|
-
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
10
|
-
chunksRef.current = [];
|
|
11
|
-
const recorder = new MediaRecorder(stream);
|
|
12
|
-
mediaRecorderRef.current = recorder;
|
|
13
|
-
recorder.ondataavailable = (event) => chunksRef.current.push(event.data);
|
|
14
|
-
recorder.onstop = () => {
|
|
15
|
-
stream.getTracks().forEach((track) => track.stop());
|
|
16
|
-
setPreviewUrl(URL.createObjectURL(new Blob(chunksRef.current, { type: 'audio/webm' })));
|
|
17
|
-
setStatus('recorded');
|
|
18
|
-
};
|
|
19
|
-
recorder.start();
|
|
20
|
-
setStatus('recording');
|
|
21
|
-
};
|
|
22
|
-
const stopRecording = () => mediaRecorderRef.current?.stop();
|
|
23
|
-
return { status, previewUrl, remainingSeconds: 0, startRecording, stopRecording };
|
|
24
|
-
}
|
|
1
|
+
"use client";import{useRef as e,useState as r}from"react";export function useSpeakingRecorder(t){const n=e(null),a=e([]),[o,c]=r("idle"),[i,s]=r(null);return{status:o,previewUrl:i,remainingSeconds:0,startRecording:async()=>{const e=await navigator.mediaDevices.getUserMedia({audio:!0});a.current=[];const r=new MediaRecorder(e);n.current=r,r.ondataavailable=e=>a.current.push(e.data),r.onstop=()=>{e.getTracks().forEach(e=>e.stop()),s(URL.createObjectURL(new Blob(a.current,{type:"audio/webm"}))),c("recorded")},r.start(),c("recording")},stopRecording:()=>n.current?.stop()}}
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export { GenericQuestionRenderer } from './GenericQuestionRenderer';
|
|
1
|
+
export{ExamTakingPageContainer}from"./ExamTakingPageContainer";export{GenericQuestionRenderer}from"./GenericQuestionRenderer";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export{};
|
package/dist/components/index.js
CHANGED
|
@@ -1,42 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export * from './exams';
|
|
3
|
-
export * from './themes';
|
|
4
|
-
export * from './results';
|
|
5
|
-
export * from './ui/alert-dialog';
|
|
6
|
-
export * from './ui/alert';
|
|
7
|
-
export * from './ui/avatar';
|
|
8
|
-
export * from './ui/badge';
|
|
9
|
-
export * from './ui/button';
|
|
10
|
-
export * from './ui/calendar';
|
|
11
|
-
export * from './ui/card';
|
|
12
|
-
export * from './ui/carousel';
|
|
13
|
-
export * from './ui/checkbox';
|
|
14
|
-
export * from './ui/collapsible';
|
|
15
|
-
export * from './ui/command';
|
|
16
|
-
export * from './ui/confirm-dialog';
|
|
17
|
-
export * from './ui/dialog';
|
|
18
|
-
export * from './ui/drawer';
|
|
19
|
-
export * from './ui/dropdown-menu';
|
|
20
|
-
export * from './ui/file-upload';
|
|
21
|
-
export * from './ui/form';
|
|
22
|
-
export * from './ui/hover-card';
|
|
23
|
-
export * from './ui/image-preview';
|
|
24
|
-
export * from './ui/input';
|
|
25
|
-
export * from './ui/label';
|
|
26
|
-
export * from './ui/language-switcher';
|
|
27
|
-
export * from './ui/multi-select';
|
|
28
|
-
export * from './ui/points-input';
|
|
29
|
-
export * from './ui/popover';
|
|
30
|
-
export * from './ui/progress';
|
|
31
|
-
export * from './ui/radio-group';
|
|
32
|
-
export * from './ui/scroll-area';
|
|
33
|
-
export * from './ui/select';
|
|
34
|
-
export * from './ui/separator';
|
|
35
|
-
export * from './ui/sheet';
|
|
36
|
-
export * from './ui/single-select';
|
|
37
|
-
export * from './ui/skeleton';
|
|
38
|
-
export * from './ui/switch';
|
|
39
|
-
export * from './ui/table';
|
|
40
|
-
export * from './ui/tabs';
|
|
41
|
-
export * from './ui/textarea';
|
|
42
|
-
export * from './ui/tooltip';
|
|
1
|
+
export*from"./CueCardEditor";export*from"./exams";export*from"./themes";export*from"./results";export*from"./ui/alert-dialog";export*from"./ui/alert";export*from"./ui/avatar";export*from"./ui/badge";export*from"./ui/button";export*from"./ui/calendar";export*from"./ui/card";export*from"./ui/carousel";export*from"./ui/checkbox";export*from"./ui/collapsible";export*from"./ui/command";export*from"./ui/confirm-dialog";export*from"./ui/dialog";export*from"./ui/drawer";export*from"./ui/dropdown-menu";export*from"./ui/file-upload";export*from"./ui/form";export*from"./ui/hover-card";export*from"./ui/image-preview";export*from"./ui/input";export*from"./ui/label";export*from"./ui/language-switcher";export*from"./ui/multi-select";export*from"./ui/points-input";export*from"./ui/popover";export*from"./ui/progress";export*from"./ui/radio-group";export*from"./ui/scroll-area";export*from"./ui/select";export*from"./ui/separator";export*from"./ui/sheet";export*from"./ui/single-select";export*from"./ui/skeleton";export*from"./ui/switch";export*from"./ui/table";export*from"./ui/tabs";export*from"./ui/textarea";export*from"./ui/tooltip";
|