@tinyweb_dev/oe-exam-sdk 0.1.27 → 0.1.29
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/README.md +79 -6
- package/dist/api/contest-rooms.js +54 -1
- package/dist/api/contest-rooms.types.js +1 -1
- package/dist/api/exam-create.js +179 -1
- package/dist/api/exam-create.types.js +1 -1
- package/dist/api/exam-entry.js +68 -1
- package/dist/api/exam-entry.types.js +1 -1
- package/dist/api/exam-questions.js +149 -1
- package/dist/api/exam-questions.types.js +1 -1
- package/dist/api/exam-taking.js +84 -1
- package/dist/api/exam-taking.types.d.ts +7 -0
- package/dist/api/exam-taking.types.js +1 -1
- package/dist/api/index.js +8 -1
- package/dist/api/result-review.js +62 -1
- package/dist/api/result-review.types.js +16 -1
- package/dist/components/CueCardEditor.js +58 -1
- package/dist/components/common/ResolvedImage.js +15 -1
- package/dist/components/exams/CompletionDialog.js +8 -1
- package/dist/components/exams/CreateExamInfoForm.js +84 -1
- package/dist/components/exams/CreateExamPageContainer.js +110 -1
- package/dist/components/exams/ExamCreator.js +287 -1
- package/dist/components/exams/ExamPartTabs.js +138 -1
- package/dist/components/exams/ExamPreviewDialog.d.ts +6 -7
- package/dist/components/exams/ExamPreviewDialog.js +121 -1
- package/dist/components/exams/ExamPreviewPartContent.d.ts +18 -0
- package/dist/components/exams/ExamPreviewPartContent.js +27 -0
- package/dist/components/exams/ExamPreviewSidebar.d.ts +17 -0
- package/dist/components/exams/ExamPreviewSidebar.js +37 -0
- package/dist/components/exams/ExamQuestionGrid.js +37 -1
- package/dist/components/exams/ExamQuestionsPageContainer.js +112 -1
- package/dist/components/exams/ExamViewDialog.js +61 -1
- package/dist/components/exams/PartAudioUploader.js +9 -1
- package/dist/components/exams/TemplateSelector.js +76 -1
- package/dist/components/exams/UnsavedChangesDialog.js +7 -1
- package/dist/components/exams/api.js +3 -1
- package/dist/components/exams/create-exam.texts.js +1 -1
- package/dist/components/exams/create-exam.validation.js +18 -1
- package/dist/components/exams/entry/EntryRestartDialog.js +11 -1
- package/dist/components/exams/entry/StudentExamEntryPageContainer.js +358 -1
- package/dist/components/exams/entry/exam-entry.states.js +26 -1
- package/dist/components/exams/entry/exam-entry.utils.js +55 -1
- package/dist/components/exams/entry/fullscreen-loading.js +18 -1
- package/dist/components/exams/entry/index.js +4 -1
- package/dist/components/exams/exam-preview.types.d.ts +30 -0
- package/dist/components/exams/exam-preview.types.js +62 -0
- package/dist/components/exams/exam-question-status.js +45 -1
- package/dist/components/exams/exam-template.utils.js +18 -1
- package/dist/components/exams/index.d.ts +1 -0
- package/dist/components/exams/index.js +19 -1
- package/dist/components/exams/rooms/StudentContestRoomsPageContainer.js +183 -1
- package/dist/components/exams/rooms/contest-rooms.utils.js +93 -1
- package/dist/components/exams/rooms/index.js +2 -1
- package/dist/components/exams/take/ExamTakingApiContext.js +25 -1
- package/dist/components/exams/take/ExamTakingPageContainer.js +955 -1
- package/dist/components/exams/take/GenericQuestionRenderer.js +14 -1
- package/dist/components/exams/take/components/QuestionRenderer.js +207 -1
- package/dist/components/exams/take/components/index.js +11 -1
- package/dist/components/exams/take/components/question-renderers/ArticlesViewer.js +8 -1
- package/dist/components/exams/take/components/question-renderers/MoversAnswerTheQuestionRenderer.js +30 -1
- package/dist/components/exams/take/components/question-renderers/MoversChooseAdjectiveRenderer.js +63 -1
- package/dist/components/exams/take/components/question-renderers/MoversChooseBestAnswerRenderer.js +136 -1
- package/dist/components/exams/take/components/question-renderers/MoversColoringRenderer.js +379 -1
- package/dist/components/exams/take/components/question-renderers/MoversCrossOutWordGroupRenderer.d.ts +20 -0
- package/dist/components/exams/take/components/question-renderers/MoversCrossOutWordGroupRenderer.js +141 -0
- package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.js +131 -1
- package/dist/components/exams/take/components/question-renderers/MoversGridFillRenderer.js +76 -1
- package/dist/components/exams/take/components/question-renderers/MoversLabelThePictureRenderer.js +68 -1
- package/dist/components/exams/take/components/question-renderers/MoversListenAndWriteRenderer.js +42 -1
- package/dist/components/exams/take/components/question-renderers/MoversMatchByWritingAnswerRenderer.js +131 -1
- package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.js +76 -1
- package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.js +68 -1
- package/dist/components/exams/take/components/question-renderers/MoversReadingPassageRenderer.js +62 -1
- package/dist/components/exams/take/components/question-renderers/MoversTrueFalseRenderer.d.ts +1 -1
- package/dist/components/exams/take/components/question-renderers/MoversTrueFalseRenderer.js +51 -1
- package/dist/components/exams/take/components/question-renderers/MoversWordFillParagraphRenderer.js +171 -1
- package/dist/components/exams/take/components/question-renderers/MoversWordFillStructuredFormRenderer.js +198 -1
- package/dist/components/exams/take/components/question-renderers/MoversWordOrderAndMatchGroupRenderer.d.ts +15 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordOrderAndMatchGroupRenderer.js +36 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordOrderingRenderer.js +92 -1
- package/dist/components/exams/take/components/question-renderers/MoversWriteSentencesRenderer.js +11 -1
- package/dist/components/exams/take/components/question-renderers/MoversWritingRenderer.js +56 -1
- package/dist/components/exams/take/components/question-renderers/index.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/index.js +25 -1
- package/dist/components/exams/take/components/speaking/SpeakingAudioPlayer.js +85 -1
- package/dist/components/exams/take/components/speaking/SpeakingContentFrame.js +10 -1
- package/dist/components/exams/take/components/speaking/SpeakingExamLayout.js +15 -1
- package/dist/components/exams/take/components/speaking/SpeakingHeader.js +6 -1
- package/dist/components/exams/take/components/speaking/SpeakingInstructionBar.js +8 -1
- package/dist/components/exams/take/components/speaking/SpeakingMicButton.js +59 -1
- package/dist/components/exams/take/components/speaking/SpeakingNavButton.js +7 -1
- package/dist/components/exams/take/components/speaking/SpeakingPartBadge.js +5 -1
- package/dist/components/exams/take/components/speaking/SpeakingReadDisplayedContent.module.css +120 -0
- package/dist/components/exams/take/components/speaking/SpeakingRecordingPreview.js +73 -1
- package/dist/components/exams/take/components/speaking/SpeakingReportErrorButton.js +8 -1
- package/dist/components/exams/take/components/speaking/SpeakingSpontaneousQA.module.css +344 -0
- package/dist/components/exams/take/components/speaking/SpeakingVideoIntro.js +32 -1
- package/dist/components/exams/take/components/speaking/index.js +1 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingChooseAnswerGroupRenderer.js +63 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingChooseObjectsRenderer.js +95 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingCompareImagesRenderer.js +35 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingConversationRenderer.js +147 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingCueCardRenderer.js +232 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingDescribeImageRenderer.js +193 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingDragObjectsRenderer.js +155 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.js +212 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingInfoExchangeRenderer.js +77 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingListenAndSpeakAnswerRenderer.js +64 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingOddOneOutRenderer.js +69 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionListRenderer.js +64 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionRenderer.js +92 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingReadDisplayedContentRenderer.js +202 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingSpontaneousQARenderer.js +339 -1
- package/dist/components/exams/take/components/speaking/renderers/SpeakingSpontaneousQaGroupRenderer.d.ts +19 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingSpontaneousQaGroupRenderer.js +76 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingStoryImagesRenderer.js +56 -1
- package/dist/components/exams/take/components/speaking/renderers/SpontaneousQACambridgeLayout.d.ts +24 -0
- package/dist/components/exams/take/components/speaking/renderers/SpontaneousQACambridgeLayout.js +120 -0
- package/dist/components/exams/take/components/speaking/renderers/SpontaneousQAInlineAudioPlayer.d.ts +8 -0
- package/dist/components/exams/take/components/speaking/renderers/SpontaneousQAInlineAudioPlayer.js +94 -0
- package/dist/components/exams/take/components/speaking/renderers/SpontaneousQASummerSkyAudioPlayer.d.ts +8 -0
- package/dist/components/exams/take/components/speaking/renderers/SpontaneousQASummerSkyAudioPlayer.js +101 -0
- package/dist/components/exams/take/components/speaking/renderers/index.d.ts +1 -0
- package/dist/components/exams/take/components/speaking/renderers/index.js +14 -1
- package/dist/components/exams/take/exam-taking.utils.d.ts +13 -0
- package/dist/components/exams/take/exam-taking.utils.js +203 -1
- package/dist/components/exams/take/hooks/index.js +2 -1
- package/dist/components/exams/take/hooks/useAnswerAutosave.js +71 -1
- package/dist/components/exams/take/hooks/useAttemptSubmit.js +38 -1
- package/dist/components/exams/take/hooks/useAutoSave.js +83 -1
- package/dist/components/exams/take/hooks/useExamCountdown.js +35 -1
- package/dist/components/exams/take/hooks/useExamTimer.js +97 -1
- package/dist/components/exams/take/hooks/useProctoringCamera.js +118 -1
- package/dist/components/exams/take/hooks/useProctoringSnapshot.js +76 -1
- package/dist/components/exams/take/hooks/useSpeakingConversationAudio.js +178 -1
- package/dist/components/exams/take/hooks/useSpeakingNavigation.js +51 -1
- package/dist/components/exams/take/hooks/useSpeakingRecorder.js +406 -1
- package/dist/components/exams/take/hooks/useSpeakingRendererSetup.js +136 -1
- package/dist/components/exams/take/hooks/useSpontaneousQaGroupRecorder.d.ts +11 -0
- package/dist/components/exams/take/hooks/useSpontaneousQaGroupRecorder.js +352 -0
- package/dist/components/exams/take/hooks/useSpontaneousQaGroupRendererSetup.d.ts +42 -0
- package/dist/components/exams/take/hooks/useSpontaneousQaGroupRendererSetup.js +166 -0
- package/dist/components/exams/take/hooks/useToeicAudio.js +35 -1
- package/dist/components/exams/take/index.js +6 -1
- package/dist/components/exams/take/types/speaking-cue-card.types.js +1 -1
- package/dist/components/exams/take/types/speaking.types.js +7 -1
- package/dist/components/exams/take/types.js +4 -1
- package/dist/components/exams/take/utils/answer-transformers.js +452 -1
- package/dist/components/exams/take/utils/cambridge-yle-inline-speaking.d.ts +21 -0
- package/dist/components/exams/take/utils/cambridge-yle-inline-speaking.js +44 -0
- package/dist/components/exams/take/utils/coloring-assignments.js +40 -1
- package/dist/components/exams/take/utils/cross-out-word-group.transformer.d.ts +21 -0
- package/dist/components/exams/take/utils/cross-out-word-group.transformer.js +83 -0
- package/dist/components/exams/take/utils/question-transformers.d.ts +43 -2
- package/dist/components/exams/take/utils/question-transformers.js +1137 -1
- package/dist/components/features/exam-entry/entry-state-cards.js +19 -1
- package/dist/components/features/exam-entry/index.js +2 -1
- package/dist/components/features/exam-entry/themed/CambridgeYleWaitingRoom.js +121 -1
- package/dist/components/features/exam-entry/themed/ThemedWaitingRoom.js +37 -1
- package/dist/components/features/exam-entry/themed/ToeicWaitingRoom.js +15 -1
- package/dist/components/features/exam-entry/themed/cambridge-yle-waiting-parts.js +80 -1
- package/dist/components/features/exam-entry/themed/components/CloseButton.js +6 -1
- package/dist/components/features/exam-entry/themed/components/ExamInfoPanel.js +17 -1
- package/dist/components/features/exam-entry/themed/components/ModeSelector.js +6 -1
- package/dist/components/features/exam-entry/themed/components/StartButton.js +12 -1
- package/dist/components/features/exam-entry/themed/components/index.js +4 -1
- package/dist/components/features/exam-entry/themed/index.js +3 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +43 -1
- package/dist/components/questions/_shared/config/question-types.config.js +362 -1
- package/dist/components/questions/_shared/constants/color-palette.js +21 -1
- package/dist/components/questions/_shared/hooks/useAnswerGroupQuestionGroup.js +105 -1
- package/dist/components/questions/_shared/hooks/useBasicQuestionGroup.js +222 -1
- package/dist/components/questions/_shared/hooks/useCompareImagesGroup.js +140 -1
- package/dist/components/questions/_shared/hooks/useImageQuestionGroup.js +123 -1
- package/dist/components/questions/_shared/hooks/useInfoExchangeGroup.js +50 -1
- package/dist/components/questions/_shared/hooks/useQuestionFormState.js +54 -1
- package/dist/components/questions/_shared/hooks/useQuestionInitialization.js +123 -1
- package/dist/components/questions/_shared/hooks/useQuestionListGroup.js +121 -1
- package/dist/components/questions/_shared/hooks/useQuestionOnChange.js +70 -1
- package/dist/components/questions/_shared/hooks/useSceneQuestionGroup.js +194 -1
- package/dist/components/questions/_shared/index.js +7 -1
- 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 +3 -1
- package/dist/components/questions/_shared/types/choose-the-correct-answer-group.type.d.ts +1 -0
- package/dist/components/questions/_shared/types/choose-the-correct-answer-group.type.js +1 -1
- package/dist/components/questions/_shared/types/color-region.config.js +1 -1
- package/dist/components/questions/_shared/types/cross-out-word-group.type.d.ts +2 -0
- package/dist/components/questions/_shared/types/cross-out-word-group.type.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.d.ts +1 -0
- package/dist/components/questions/_shared/types/index.js +14 -1
- 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 +3 -1
- 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 +3 -1
- 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.d.ts +5 -0
- package/dist/components/questions/_shared/types/multiple-choice.type.js +1 -1
- package/dist/components/questions/_shared/types/question-group.type.js +11 -1
- 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-group.type.d.ts +37 -0
- package/dist/components/questions/_shared/types/spontaneous-qa-group.type.js +1 -0
- package/dist/components/questions/_shared/types/spontaneous-qa.type.js +1 -1
- package/dist/components/questions/_shared/types/true-false-group.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.d.ts +20 -11
- package/dist/components/questions/_shared/types/word-fill-structured-form.type.js +1 -1
- package/dist/components/questions/_shared/types/word-order-and-match-group.type.d.ts +38 -0
- package/dist/components/questions/_shared/types/word-order-and-match-group.type.js +1 -0
- 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 +3 -1
- 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 +79 -1
- package/dist/components/questions/_shared/utils/createColorRegionRegistration.js +39 -1
- package/dist/components/questions/_shared/utils/id-generator.js +3 -1
- package/dist/components/questions/_shared/utils/parseFillBlankStem.d.ts +30 -0
- package/dist/components/questions/_shared/utils/parseFillBlankStem.js +69 -0
- package/dist/components/questions/_shared/utils/question-validation.js +21 -1
- package/dist/components/questions/components/ColorNode.js +85 -1
- package/dist/components/questions/components/ColorRegionClient.js +545 -1
- package/dist/components/questions/components/ColorRegionCreator.js +420 -1
- package/dist/components/questions/components/ColorRegionNode.js +59 -1
- package/dist/components/questions/components/CreatorGuide.js +103 -1
- package/dist/components/questions/components/NameNode.js +26 -1
- package/dist/components/questions/components/QuestionBankOption.js +46 -1
- package/dist/components/questions/components/QuestionBasicInfoForm.js +9 -1
- package/dist/components/questions/components/QuestionCommonFields.js +33 -1
- package/dist/components/questions/components/QuestionSearchDropdown.js +258 -1
- package/dist/components/questions/components/QuestionTypeSelector.js +32 -1
- package/dist/components/questions/components/QuestionTypeSpecificForms.js +6 -1
- package/dist/components/questions/components/RegionNode.js +94 -1
- package/dist/components/questions/components/index.js +14 -1
- package/dist/components/questions/creator/QuestionCreator.js +90 -1
- package/dist/components/questions/creator/QuestionGroupCreator.js +119 -1
- package/dist/components/questions/creator/dedicated-component-router.js +79 -1
- package/dist/components/questions/creator/index.js +3 -1
- package/dist/components/questions/creator/question-type-registry.js +90 -1
- package/dist/components/questions/groups/ArticlesGroupCard.js +121 -1
- package/dist/components/questions/groups/BasicQuestionGroupCard.js +50 -1
- package/dist/components/questions/groups/DocumentGroupCard.js +114 -1
- package/dist/components/questions/groups/MatchAnswerGroupCard.js +25 -1
- package/dist/components/questions/index.d.ts +1 -0
- package/dist/components/questions/index.js +11 -1
- package/dist/components/questions/question-bank/EditQuestionBankDialog.d.ts +2 -0
- package/dist/components/questions/question-bank/EditQuestionBankDialog.js +114 -0
- package/dist/components/questions/question-bank/QuestionEditorRenderer.d.ts +23 -0
- package/dist/components/questions/question-bank/QuestionEditorRenderer.js +75 -0
- package/dist/components/questions/question-bank/difficulty.d.ts +15 -0
- package/dist/components/questions/question-bank/difficulty.js +33 -0
- package/dist/components/questions/question-bank/editor-adapters/choice-adapters.d.ts +5 -0
- package/dist/components/questions/question-bank/editor-adapters/choice-adapters.js +101 -0
- package/dist/components/questions/question-bank/editor-adapters/index.d.ts +5 -0
- package/dist/components/questions/question-bank/editor-adapters/index.js +4 -0
- package/dist/components/questions/question-bank/editor-adapters/media-adapters.d.ts +6 -0
- package/dist/components/questions/question-bank/editor-adapters/media-adapters.js +140 -0
- package/dist/components/questions/question-bank/editor-adapters/types.d.ts +1 -0
- package/dist/components/questions/question-bank/editor-adapters/types.js +1 -0
- package/dist/components/questions/question-bank/editor-adapters/unsupported-fallback.d.ts +8 -0
- package/dist/components/questions/question-bank/editor-adapters/unsupported-fallback.js +6 -0
- package/dist/components/questions/question-bank/editor-adapters/writing-adapters.d.ts +5 -0
- package/dist/components/questions/question-bank/editor-adapters/writing-adapters.js +114 -0
- package/dist/components/questions/question-bank/index.d.ts +4 -0
- package/dist/components/questions/question-bank/index.js +3 -0
- package/dist/components/questions/question-bank/types.d.ts +59 -0
- package/dist/components/questions/question-bank/types.js +1 -0
- package/dist/components/questions/types/answer-the-question/AnswerTheQuestionClient.js +37 -1
- package/dist/components/questions/types/answer-the-question/AnswerTheQuestionCreator.js +351 -1
- package/dist/components/questions/types/answer-the-question/register.js +67 -1
- package/dist/components/questions/types/answer-the-question/transform.js +36 -1
- package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsClient.js +141 -1
- package/dist/components/questions/types/arrange-letters-into-words/ArrangeLettersIntoWordsCreator.js +118 -1
- package/dist/components/questions/types/arrange-letters-into-words/index.js +2 -1
- package/dist/components/questions/types/arrange-letters-into-words/register.js +4 -1
- package/dist/components/questions/types/arrange-letters-into-words/transform.js +24 -1
- package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveClient.js +74 -1
- package/dist/components/questions/types/choose-correct-adjective/ChooseCorrectAdjectiveCreator.js +169 -1
- package/dist/components/questions/types/choose-correct-adjective/index.js +2 -1
- package/dist/components/questions/types/choose-correct-adjective/register.js +55 -1
- package/dist/components/questions/types/choose-correct-adjective/transform.js +16 -1
- package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerClient.js +149 -1
- package/dist/components/questions/types/choose-the-correct-answer/ChooseTheCorrectAnswerCreator.js +568 -1
- package/dist/components/questions/types/choose-the-correct-answer/index.js +3 -1
- package/dist/components/questions/types/choose-the-correct-answer/normalize.d.ts +9 -0
- package/dist/components/questions/types/choose-the-correct-answer/normalize.js +88 -1
- package/dist/components/questions/types/choose-the-correct-answer/register.js +99 -1
- package/dist/components/questions/types/choose-the-correct-answer/transform.js +70 -1
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupClient.js +22 -1
- package/dist/components/questions/types/choose-the-correct-answer-group/ChooseTheCorrectAnswerGroupCreator.js +163 -1
- package/dist/components/questions/types/choose-the-correct-answer-group/index.d.ts +1 -0
- package/dist/components/questions/types/choose-the-correct-answer-group/index.js +3 -1
- package/dist/components/questions/types/choose-the-correct-answer-group/map-choose-the-correct-answer-group-data.d.ts +4 -0
- package/dist/components/questions/types/choose-the-correct-answer-group/map-choose-the-correct-answer-group-data.js +94 -0
- package/dist/components/questions/types/choose-the-correct-answer-group/register.js +36 -1
- package/dist/components/questions/types/choose-the-correct-answer-group/transform.js +55 -1
- package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupClient.js +27 -1
- package/dist/components/questions/types/cross-out-word-group/CrossOutWordGroupCreator.js +231 -1
- package/dist/components/questions/types/cross-out-word-group/index.d.ts +1 -0
- package/dist/components/questions/types/cross-out-word-group/index.js +5 -1
- package/dist/components/questions/types/cross-out-word-group/map-cross-out-word-group-data.d.ts +6 -0
- package/dist/components/questions/types/cross-out-word-group/map-cross-out-word-group-data.js +110 -0
- package/dist/components/questions/types/cross-out-word-group/register.js +36 -1
- package/dist/components/questions/types/cross-out-word-group/transform.js +67 -1
- package/dist/components/questions/types/fill-in-blank/FillInBlankClient.js +275 -1
- package/dist/components/questions/types/fill-in-blank/FillInBlankCreator.js +464 -1
- package/dist/components/questions/types/fill-in-blank/index.js +2 -1
- package/dist/components/questions/types/fill-in-blank/register.js +148 -1
- package/dist/components/questions/types/fill-in-blank/transform.js +88 -1
- package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridClient.js +117 -1
- package/dist/components/questions/types/fill-missing-words-in-grid/FillMissingWordsInGridCreator.js +671 -1
- package/dist/components/questions/types/fill-missing-words-in-grid/index.js +2 -1
- package/dist/components/questions/types/fill-missing-words-in-grid/register.js +37 -1
- package/dist/components/questions/types/fill-missing-words-in-grid/transform.js +15 -1
- package/dist/components/questions/types/gn-speaking-interview/GNSpeakingInterviewCreator.js +262 -1
- package/dist/components/questions/types/gn-speaking-interview/register.js +121 -1
- package/dist/components/questions/types/gn-speaking-interview/transform.js +48 -1
- package/dist/components/questions/types/image-object-matching/ImageObjectMatchingClient.js +16 -1
- package/dist/components/questions/types/image-object-matching/ImageObjectMatchingCreator.js +27 -1
- package/dist/components/questions/types/image-object-matching/index.js +2 -1
- package/dist/components/questions/types/image-object-matching/register.js +3 -1
- package/dist/components/questions/types/image-object-matching/transform.js +2 -1
- package/dist/components/questions/types/label-the-picture/LabelThePictureClient.js +102 -1
- package/dist/components/questions/types/label-the-picture/LabelThePictureCreator.js +344 -1
- package/dist/components/questions/types/label-the-picture/index.js +2 -1
- package/dist/components/questions/types/label-the-picture/register.js +54 -1
- package/dist/components/questions/types/label-the-picture/transform.js +28 -1
- package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupClient.js +78 -1
- package/dist/components/questions/types/listen-and-choose-from-answer-group/ListenAndChooseFromAnswerGroupCreator.js +232 -1
- package/dist/components/questions/types/listen-and-choose-from-answer-group/index.js +2 -1
- package/dist/components/questions/types/listen-and-choose-from-answer-group/register.js +82 -1
- package/dist/components/questions/types/listen-and-choose-from-answer-group/transform.js +27 -1
- package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneClient.js +70 -1
- package/dist/components/questions/types/listen-and-choose-objects-in-scene/ListenAndChooseObjectsInSceneCreator.js +386 -1
- package/dist/components/questions/types/listen-and-choose-objects-in-scene/index.js +2 -1
- package/dist/components/questions/types/listen-and-choose-objects-in-scene/register.js +100 -1
- package/dist/components/questions/types/listen-and-choose-objects-in-scene/transform.js +33 -1
- package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneClient.js +106 -1
- package/dist/components/questions/types/listen-and-drag-objects-into-scene/ListenAndDragObjectsIntoSceneCreator.js +457 -1
- package/dist/components/questions/types/listen-and-drag-objects-into-scene/index.js +2 -1
- package/dist/components/questions/types/listen-and-drag-objects-into-scene/register.js +110 -1
- package/dist/components/questions/types/listen-and-drag-objects-into-scene/transform.js +35 -1
- package/dist/components/questions/types/listen-and-speak-answer/ArrowIndicator.js +8 -1
- package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerClient.js +22 -1
- package/dist/components/questions/types/listen-and-speak-answer/ListenAndSpeakAnswerCreator.js +291 -1
- package/dist/components/questions/types/listen-and-speak-answer/index.js +2 -1
- package/dist/components/questions/types/listen-and-speak-answer/register.js +84 -1
- package/dist/components/questions/types/listen-and-speak-answer/transform.js +27 -1
- package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesClient.js +32 -1
- package/dist/components/questions/types/listen-and-speak-compare-images/ListenAndSpeakCompareImagesCreator.js +295 -1
- package/dist/components/questions/types/listen-and-speak-compare-images/register.js +79 -1
- package/dist/components/questions/types/listen-and-speak-compare-images/transform.js +27 -1
- package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupClient.js +34 -1
- package/dist/components/questions/types/listen-and-speak-image-group/ListenAndSpeakImageGroupCreator.js +285 -1
- package/dist/components/questions/types/listen-and-speak-image-group/register.js +81 -1
- package/dist/components/questions/types/listen-and-speak-image-group/transform.js +26 -1
- package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeClient.js +38 -1
- package/dist/components/questions/types/listen-and-speak-info-exchange/ListenAndSpeakInfoExchangeCreator.js +385 -1
- package/dist/components/questions/types/listen-and-speak-info-exchange/register.js +87 -1
- package/dist/components/questions/types/listen-and-speak-info-exchange/transform.js +32 -1
- package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutClient.js +26 -1
- package/dist/components/questions/types/listen-and-speak-odd-one-out/ListenAndSpeakOddOneOutCreator.js +247 -1
- package/dist/components/questions/types/listen-and-speak-odd-one-out/register.js +59 -1
- package/dist/components/questions/types/listen-and-speak-odd-one-out/transform.js +18 -1
- package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListClient.js +26 -1
- package/dist/components/questions/types/listen-and-speak-question-list/ListenAndSpeakQuestionListCreator.js +256 -1
- package/dist/components/questions/types/listen-and-speak-question-list/register.js +81 -1
- package/dist/components/questions/types/listen-and-speak-question-list/transform.js +26 -1
- package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesClient.js +26 -1
- package/dist/components/questions/types/listen-and-speak-with-story-images/ListenAndSpeakWithStoryImagesCreator.js +230 -1
- package/dist/components/questions/types/listen-and-speak-with-story-images/register.js +56 -1
- package/dist/components/questions/types/listen-and-speak-with-story-images/transform.js +16 -1
- package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerClient.js +72 -1
- package/dist/components/questions/types/look-picture-choose-correct-answer/LookPictureChooseCorrectAnswerCreator.js +230 -1
- 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 +66 -1
- package/dist/components/questions/types/look-picture-choose-correct-answer/transform.js +42 -1
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerClient.js +96 -1
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/LookPictureFillBlankChooseAnswerCreator.js +238 -1
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/index.js +2 -1
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/register.js +76 -1
- package/dist/components/questions/types/look-picture-fill-blank-choose-answer/transform.js +19 -1
- package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintClient.js +134 -1
- package/dist/components/questions/types/look-picture-fill-word-hint/LookPictureFillWordHintCreator.js +617 -1
- package/dist/components/questions/types/look-picture-fill-word-hint/index.js +2 -1
- package/dist/components/questions/types/look-picture-fill-word-hint/register.js +82 -1
- package/dist/components/questions/types/look-picture-fill-word-hint/transform.js +29 -1
- package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerClient.js +38 -1
- package/dist/components/questions/types/match-by-writing-answer/MatchByWritingAnswerCreator.js +359 -1
- package/dist/components/questions/types/match-by-writing-answer/index.js +3 -1
- package/dist/components/questions/types/match-by-writing-answer/register.js +58 -1
- package/dist/components/questions/types/match-by-writing-answer/transform.js +61 -1
- package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsClient.js +16 -1
- package/dist/components/questions/types/read-and-color-objects/ReadAndColorObjectsCreator.js +23 -1
- package/dist/components/questions/types/read-and-color-objects/index.js +2 -1
- package/dist/components/questions/types/read-and-color-objects/register.js +3 -1
- package/dist/components/questions/types/read-and-color-objects/transform.js +36 -1
- package/dist/components/questions/types/read-displayed-content/ReadDisplayedContentCreator.js +125 -1
- package/dist/components/questions/types/read-displayed-content/register.js +64 -1
- package/dist/components/questions/types/read-displayed-content/transform.js +12 -1
- package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsClient.js +65 -1
- package/dist/components/questions/types/read-passage-and-answer-questions/ReadPassageAndAnswerQuestionsCreator.js +511 -1
- package/dist/components/questions/types/read-passage-and-answer-questions/index.js +2 -1
- package/dist/components/questions/types/read-passage-and-answer-questions/register.js +58 -1
- package/dist/components/questions/types/read-passage-and-answer-questions/transform.js +28 -1
- package/dist/components/questions/types/speaking-conversation/SpeakingConversationCreator.js +373 -1
- package/dist/components/questions/types/speaking-conversation/SpeakingConversationPreviewClient.js +41 -1
- package/dist/components/questions/types/speaking-conversation/register.js +110 -1
- package/dist/components/questions/types/speaking-conversation/transform.js +34 -1
- package/dist/components/questions/types/speaking-cue-card/SpeakingCueCardCreator.js +74 -1
- package/dist/components/questions/types/speaking-cue-card/register.js +52 -1
- package/dist/components/questions/types/speaking-cue-card/transform.js +12 -1
- package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageClient.js +10 -1
- package/dist/components/questions/types/speaking-describe-image/SpeakingDescribeImageCreator.js +161 -1
- package/dist/components/questions/types/speaking-describe-image/index.js +2 -1
- package/dist/components/questions/types/speaking-describe-image/register.js +69 -1
- package/dist/components/questions/types/speaking-describe-image/transform.js +16 -1
- package/dist/components/questions/types/spontaneous-qa/SpontaneousQACreator.js +234 -1
- package/dist/components/questions/types/spontaneous-qa/register.js +93 -1
- package/dist/components/questions/types/spontaneous-qa/transform.js +34 -1
- package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupClient.d.ts +2 -0
- package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupClient.js +9 -0
- package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupCreator.d.ts +2 -0
- package/dist/components/questions/types/spontaneous-qa-group/SpontaneousQaGroupCreator.js +179 -0
- package/dist/components/questions/types/spontaneous-qa-group/creator-helpers.d.ts +5 -0
- package/dist/components/questions/types/spontaneous-qa-group/creator-helpers.js +43 -0
- package/dist/components/questions/types/spontaneous-qa-group/flatten.d.ts +14 -0
- package/dist/components/questions/types/spontaneous-qa-group/flatten.js +69 -0
- package/dist/components/questions/types/spontaneous-qa-group/index.d.ts +2 -0
- package/dist/components/questions/types/spontaneous-qa-group/index.js +2 -0
- package/dist/components/questions/types/spontaneous-qa-group/register.d.ts +2 -0
- package/dist/components/questions/types/spontaneous-qa-group/register.js +139 -0
- package/dist/components/questions/types/spontaneous-qa-group/transform.d.ts +2 -0
- package/dist/components/questions/types/spontaneous-qa-group/transform.js +52 -0
- package/dist/components/questions/types/true-false/TrueFalseClient.js +75 -1
- package/dist/components/questions/types/true-false/TrueFalseCreator.js +244 -1
- package/dist/components/questions/types/true-false/index.js +2 -1
- package/dist/components/questions/types/true-false/register.js +77 -1
- package/dist/components/questions/types/true-false/transform.js +32 -1
- package/dist/components/questions/types/true-false-group/TrueFalseGroupClient.js +25 -1
- package/dist/components/questions/types/true-false-group/TrueFalseGroupCreator.js +129 -1
- package/dist/components/questions/types/true-false-group/index.d.ts +1 -0
- package/dist/components/questions/types/true-false-group/index.js +5 -1
- package/dist/components/questions/types/true-false-group/map-true-false-group-data.d.ts +4 -0
- package/dist/components/questions/types/true-false-group/map-true-false-group-data.js +69 -0
- package/dist/components/questions/types/true-false-group/register.js +36 -1
- package/dist/components/questions/types/true-false-group/transform.js +43 -1
- package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphClient.js +233 -1
- package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphCreator.js +631 -1
- package/dist/components/questions/types/word-fill-paragraph/WordFillParagraphWrapper.js +28 -1
- package/dist/components/questions/types/word-fill-paragraph/index.js +2 -1
- package/dist/components/questions/types/word-fill-paragraph/register.js +136 -1
- package/dist/components/questions/types/word-fill-paragraph/transform.js +56 -1
- package/dist/components/questions/types/word-fill-structured-form/WfsfWordBankEditor.js +86 -1
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormClient.js +246 -1
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.d.ts +2 -0
- package/dist/components/questions/types/word-fill-structured-form/WordFillStructuredFormCreator.js +484 -1
- package/dist/components/questions/types/word-fill-structured-form/index.d.ts +1 -0
- package/dist/components/questions/types/word-fill-structured-form/index.js +3 -1
- package/dist/components/questions/types/word-fill-structured-form/map-wfsf-question-data.d.ts +7 -0
- package/dist/components/questions/types/word-fill-structured-form/map-wfsf-question-data.js +113 -0
- package/dist/components/questions/types/word-fill-structured-form/register.js +36 -1
- package/dist/components/questions/types/word-fill-structured-form/transform.js +77 -1
- package/dist/components/questions/types/word-fill-structured-form/wfsf-word-bank.utils.js +110 -1
- package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupClient.d.ts +3 -0
- package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupClient.js +190 -0
- package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupCreator.d.ts +3 -0
- package/dist/components/questions/types/word-order-and-match-group/WordOrderAndMatchGroupCreator.js +182 -0
- package/dist/components/questions/types/word-order-and-match-group/index.d.ts +4 -0
- package/dist/components/questions/types/word-order-and-match-group/index.js +4 -0
- package/dist/components/questions/types/word-order-and-match-group/register.d.ts +2 -0
- package/dist/components/questions/types/word-order-and-match-group/register.js +121 -0
- package/dist/components/questions/types/word-order-and-match-group/transform.d.ts +2 -0
- package/dist/components/questions/types/word-order-and-match-group/transform.js +70 -0
- package/dist/components/questions/types/word-ordering/WordOrderingClient.js +84 -1
- package/dist/components/questions/types/word-ordering/WordOrderingCreator.js +192 -1
- package/dist/components/questions/types/word-ordering/index.js +2 -1
- package/dist/components/questions/types/word-ordering/register.js +46 -1
- package/dist/components/questions/types/word-ordering/transform.js +24 -1
- package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterClient.js +99 -1
- package/dist/components/questions/types/write-a-short-letter/WriteAShortLetterCreator.js +320 -1
- package/dist/components/questions/types/write-a-short-letter/index.js +2 -1
- package/dist/components/questions/types/write-a-short-letter/register.js +68 -1
- package/dist/components/questions/types/write-a-short-letter/transform.js +25 -1
- package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormClient.js +61 -1
- package/dist/components/questions/types/write-correct-verb-form/WriteCorrectVerbFormCreator.js +196 -1
- package/dist/components/questions/types/write-correct-verb-form/index.js +2 -1
- package/dist/components/questions/types/write-correct-verb-form/register.js +62 -1
- package/dist/components/questions/types/write-correct-verb-form/transform.js +17 -1
- package/dist/components/questions/types/write-sentences/WriteSentencesClient.js +22 -1
- package/dist/components/questions/types/write-sentences/WriteSentencesCreator.js +174 -1
- package/dist/components/questions/types/write-sentences/index.js +2 -1
- package/dist/components/questions/types/write-sentences/register.js +58 -1
- package/dist/components/questions/types/write-sentences/transform.js +28 -1
- package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphClient.js +96 -1
- package/dist/components/questions/types/write-short-paragraph/WriteShortParagraphCreator.js +161 -1
- package/dist/components/questions/types/write-short-paragraph/index.js +2 -1
- package/dist/components/questions/types/write-short-paragraph/register.js +4 -1
- package/dist/components/questions/types/write-short-paragraph/transform.js +21 -1
- package/dist/components/questions/viewer/ChooseTheCorrectAnswerGroupViewer.d.ts +8 -0
- package/dist/components/questions/viewer/ChooseTheCorrectAnswerGroupViewer.js +11 -0
- package/dist/components/questions/viewer/CrossOutWordGroupViewer.d.ts +7 -0
- package/dist/components/questions/viewer/CrossOutWordGroupViewer.js +8 -0
- package/dist/components/questions/viewer/QuestionGroupViewer.js +36 -1
- package/dist/components/questions/viewer/QuestionViewer.js +692 -1
- package/dist/components/questions/viewer/SpontaneousQaGroupViewer.d.ts +5 -0
- package/dist/components/questions/viewer/SpontaneousQaGroupViewer.js +82 -0
- package/dist/components/questions/viewer/TrueFalseGroupViewer.d.ts +8 -0
- package/dist/components/questions/viewer/TrueFalseGroupViewer.js +11 -0
- package/dist/components/questions/viewer/WordFillStructuredFormViewer.d.ts +9 -0
- package/dist/components/questions/viewer/WordFillStructuredFormViewer.js +14 -0
- package/dist/components/questions/viewer/WordOrderAndMatchGroupViewer.d.ts +6 -0
- package/dist/components/questions/viewer/WordOrderAndMatchGroupViewer.js +95 -0
- package/dist/components/questions/viewer/index.d.ts +6 -0
- package/dist/components/questions/viewer/index.js +8 -1
- package/dist/components/results/ResultReviewPageContainer.js +220 -1
- package/dist/components/results/ReviewQuestionRenderer.js +55 -1
- package/dist/components/results/hooks/useResultReviewPolling.js +76 -1
- package/dist/components/results/index.js +22 -1
- package/dist/components/results/renderers/QuestionExplanations.js +19 -1
- package/dist/components/results/renderers/ReviewChooseAdjectiveRenderer.js +94 -1
- package/dist/components/results/renderers/ReviewChooseBestAnswerRenderer.js +75 -1
- package/dist/components/results/renderers/ReviewColoringRenderer.js +110 -1
- package/dist/components/results/renderers/ReviewListenAndWriteRenderer.js +48 -1
- package/dist/components/results/renderers/ReviewListenChooseAnswerGroupRenderer.js +87 -1
- package/dist/components/results/renderers/ReviewListenChooseObjectsRenderer.js +104 -1
- package/dist/components/results/renderers/ReviewListenDragObjectsRenderer.js +123 -1
- package/dist/components/results/renderers/ReviewListeningHeader.js +104 -1
- package/dist/components/results/renderers/ReviewSpeakingAIPanel.js +116 -1
- package/dist/components/results/renderers/ReviewSpeakingMedia.js +48 -1
- package/dist/components/results/renderers/ReviewSpeakingQuestionItem.js +42 -1
- package/dist/components/results/renderers/ReviewSpeakingRenderer.js +12 -1
- package/dist/components/results/renderers/ReviewSpeakingRenderer.types.js +85 -1
- package/dist/components/results/renderers/review-question-body-dedicated.js +104 -1
- package/dist/components/results/renderers/review-question-body-movers.js +148 -1
- package/dist/components/results/renderers/review-speaking-map.js +226 -1
- package/dist/components/results/renderers/review-spontaneous-qa-group.d.ts +4 -0
- package/dist/components/results/renderers/review-spontaneous-qa-group.js +74 -0
- package/dist/components/results/report/BadgeTitle.js +5 -1
- package/dist/components/results/report/ExamSkillRow.js +20 -1
- package/dist/components/results/report/OceanEduExamReport.js +58 -1
- package/dist/components/results/report/OceanEduSpeakingReport.js +62 -1
- package/dist/components/results/report/OverallAssessmentSection.js +17 -1
- package/dist/components/results/report/ResultErrorState.js +18 -1
- package/dist/components/results/report/ResultLoadingState.js +10 -1
- package/dist/components/results/report/ResultNotPublicState.js +27 -1
- package/dist/components/results/report/SpeakingReportParts.js +14 -1
- package/dist/components/results/report/SpeakingReportShared.js +86 -1
- package/dist/components/results/report/SpeakingRubricSection.js +171 -1
- package/dist/components/results/report/speaking-report.utils.js +198 -1
- package/dist/components/results/result-review.utils.js +6 -1
- package/dist/components/results/review-data.js +222 -1
- package/dist/components/results/review-renderer.utils.js +97 -1
- package/dist/components/results/review-status.utils.js +36 -1
- package/dist/components/results/review-types.js +1 -1
- package/dist/components/results/speaking/SpeakingResultAudioPlayer.js +77 -1
- package/dist/components/results/speaking/SpeakingReviewResult.js +48 -1
- package/dist/components/results/utils/review-score.utils.js +72 -1
- package/dist/components/results/utils/speaking-summary.js +224 -1
- package/dist/components/results/utils/transform-speaking-review.js +183 -1
- package/dist/components/shared/RichTextEditor.d.ts +9 -0
- package/dist/components/shared/RichTextEditor.js +47 -0
- package/dist/components/shared/audio/SpeakingAudioPlayer.js +100 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleAudioPlayer.js +140 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleBottomNav.js +10 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleExamLayout.d.ts +1 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleExamLayout.js +18 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleExampleText.js +11 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleHeader.js +11 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleInstructionBanner.d.ts +2 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleInstructionBanner.js +19 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleNavButton.js +13 -1
- package/dist/components/themes/cambridge-yle/CambridgeYlePartBanner.d.ts +1 -1
- package/dist/components/themes/cambridge-yle/CambridgeYlePartBanner.js +3 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleProgressBar.js +6 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCard.js +5 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleQuestionCardFullWidth.js +9 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.d.ts +2 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleSidebar.js +61 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleTimer.d.ts +1 -1
- package/dist/components/themes/cambridge-yle/CambridgeYleTimer.js +25 -1
- package/dist/components/themes/cambridge-yle/index.js +13 -1
- package/dist/components/themes/english-certification/EcAnswerTheQuestion.js +25 -1
- package/dist/components/themes/english-certification/EcMatchByWritingAnswer.js +89 -1
- package/dist/components/themes/english-certification/EcWordFillParagraph.js +56 -1
- package/dist/components/themes/english-certification/EcWordFillStructuredForm.js +192 -1
- package/dist/components/themes/english-certification/EcWritingTask.js +60 -1
- package/dist/components/themes/english-certification/EnglishCertificationAudioPlayer.js +108 -1
- package/dist/components/themes/english-certification/EnglishCertificationBrand.js +11 -1
- package/dist/components/themes/english-certification/EnglishCertificationExamLayout.js +34 -1
- package/dist/components/themes/english-certification/EnglishCertificationFlagButton.js +15 -1
- package/dist/components/themes/english-certification/EnglishCertificationFooterBar.js +19 -1
- package/dist/components/themes/english-certification/EnglishCertificationGroupedQuestion.js +166 -1
- package/dist/components/themes/english-certification/EnglishCertificationHeader.js +31 -1
- package/dist/components/themes/english-certification/EnglishCertificationInstructionBanner.js +79 -1
- package/dist/components/themes/english-certification/EnglishCertificationNavigationPanel.js +71 -1
- package/dist/components/themes/english-certification/EnglishCertificationOptionSelector.js +79 -1
- package/dist/components/themes/english-certification/EnglishCertificationPartHeader.js +47 -1
- package/dist/components/themes/english-certification/EnglishCertificationPassagePanel.js +77 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionCard.js +25 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionItem.js +36 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +81 -1
- package/dist/components/themes/english-certification/EnglishCertificationReadingSection.js +95 -1
- package/dist/components/themes/english-certification/EnglishCertificationSingleQuestion.js +18 -1
- package/dist/components/themes/english-certification/EnglishCertificationSingleQuestionList.js +32 -1
- package/dist/components/themes/english-certification/english-cert-scroll.js +163 -1
- package/dist/components/themes/english-certification/english-certification-theme.js +58 -1
- package/dist/components/themes/english-certification/grouped-question-utils.js +243 -1
- package/dist/components/themes/english-certification/index.js +24 -1
- package/dist/components/themes/index.js +25 -1
- package/dist/components/themes/summer-sky/SummerSkyAudioPlayer.js +170 -1
- package/dist/components/themes/summer-sky/SummerSkyExitModal.js +21 -1
- package/dist/components/themes/summer-sky/SummerSkyLayout.js +221 -1
- package/dist/components/themes/summer-sky/SummerSkySubmitModal.js +18 -1
- package/dist/components/themes/summer-sky/SummerSkyWaitingRoom.js +193 -1
- package/dist/components/themes/types.js +1 -1
- package/dist/components/ui/alert-dialog.js +26 -1
- package/dist/components/ui/alert.js +22 -1
- package/dist/components/ui/avatar.js +12 -1
- package/dist/components/ui/badge.js +38 -1
- package/dist/components/ui/button.js +35 -1
- package/dist/components/ui/calendar.js +76 -1
- package/dist/components/ui/card.js +16 -1
- package/dist/components/ui/carousel.js +91 -1
- package/dist/components/ui/checkbox.js +9 -1
- package/dist/components/ui/collapsible.js +13 -1
- package/dist/components/ui/command.js +34 -1
- package/dist/components/ui/confirm-dialog.js +49 -1
- package/dist/components/ui/dialog.js +23 -1
- package/dist/components/ui/drawer.js +35 -1
- package/dist/components/ui/dropdown-menu.js +33 -1
- package/dist/components/ui/file-upload.js +155 -1
- package/dist/components/ui/form.js +62 -1
- package/dist/components/ui/hover-card.js +10 -1
- package/dist/components/ui/image-preview.js +29 -1
- package/dist/components/ui/input.js +8 -1
- package/dist/components/ui/label.js +9 -1
- package/dist/components/ui/language-switcher.js +15 -1
- package/dist/components/ui/multi-select.js +90 -1
- package/dist/components/ui/points-input.js +33 -1
- package/dist/components/ui/popover.js +26 -1
- package/dist/components/ui/progress.js +16 -1
- package/dist/components/ui/radio-group.js +12 -1
- package/dist/components/ui/scroll-area.js +11 -1
- package/dist/components/ui/select.js +38 -1
- package/dist/components/ui/separator.js +8 -1
- package/dist/components/ui/sheet.js +40 -1
- package/dist/components/ui/single-select.js +76 -1
- package/dist/components/ui/skeleton.js +6 -1
- package/dist/components/ui/switch.js +8 -1
- package/dist/components/ui/table.js +20 -1
- package/dist/components/ui/tabs.js +17 -1
- package/dist/components/ui/textarea.js +8 -1
- package/dist/components/ui/tooltip.js +11 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +24 -1
- package/dist/shared/constants/ApiConstant.d.ts +1 -0
- package/dist/shared/constants/ApiConstant.js +278 -1
- package/dist/shared/constants/QueryKeyConstant.js +112 -1
- package/dist/shared/constants/exam-level.enum.js +41 -1
- package/dist/shared/constants/landings/placement-test.constants.js +431 -1
- package/dist/shared/constants/question-skills.js +277 -1
- package/dist/shared/constants/routes.js +81 -1
- package/dist/shared/index.js +10 -1
- package/dist/shared/lib/hooks/index.js +10 -1
- package/dist/shared/lib/hooks/useAlertDialog.js +57 -1
- package/dist/shared/lib/hooks/useAudioPlayCounter.js +30 -1
- package/dist/shared/lib/hooks/useAudioPreview.js +81 -1
- package/dist/shared/lib/hooks/useAudioUpload.js +24 -1
- package/dist/shared/lib/hooks/useConfirmDialog.js +89 -1
- package/dist/shared/lib/hooks/useDebouncedCallback.js +32 -1
- package/dist/shared/lib/hooks/useDelayedAutoPlay.js +12 -1
- package/dist/shared/lib/hooks/useFileUpload.js +24 -1
- package/dist/shared/lib/hooks/useImageUrl.js +5 -1
- package/dist/shared/lib/hooks/usePresignedFileUrl.js +108 -1
- package/dist/shared/lib/hooks/useReactHookForm.js +31 -1
- package/dist/shared/lib/hooks/useToast.js +62 -1
- package/dist/shared/lib/html-content.js +22 -1
- package/dist/shared/lib/i18n/index.js +54 -1
- package/dist/shared/lib/i18n/messages/en/admin.d.ts +11 -4
- package/dist/shared/lib/i18n/messages/en/admin.js +2111 -1
- package/dist/shared/lib/i18n/messages/en/auth.js +86 -1
- package/dist/shared/lib/i18n/messages/en/common.js +140 -1
- package/dist/shared/lib/i18n/messages/en/file-upload.js +18 -1
- package/dist/shared/lib/i18n/messages/en/student.js +133 -1
- package/dist/shared/lib/i18n/messages/en/terms.js +37 -1
- package/dist/shared/lib/i18n/messages/en.d.ts +11 -4
- package/dist/shared/lib/i18n/messages/en.js +15 -1
- package/dist/shared/lib/i18n/messages/vi/admin.d.ts +11 -4
- package/dist/shared/lib/i18n/messages/vi/admin.js +2111 -1
- package/dist/shared/lib/i18n/messages/vi/auth.js +86 -1
- package/dist/shared/lib/i18n/messages/vi/common.js +140 -1
- package/dist/shared/lib/i18n/messages/vi/file-upload.js +18 -1
- package/dist/shared/lib/i18n/messages/vi/student.js +133 -1
- package/dist/shared/lib/i18n/messages/vi/terms.js +37 -1
- package/dist/shared/lib/i18n/messages/vi.d.ts +11 -4
- package/dist/shared/lib/i18n/messages/vi.js +15 -1
- package/dist/shared/lib/i18n/types.js +1 -1
- package/dist/shared/lib/stores/examQuestionStore.js +212 -1
- package/dist/shared/lib/stores/examTakingStore.js +240 -1
- package/dist/shared/lib/stores/gradingTransientStore.js +39 -1
- package/dist/shared/lib/stores/localeStore.js +10 -1
- package/dist/shared/lib/themes/config/starters.config.js +71 -1
- package/dist/shared/lib/themes/index.js +49 -1
- package/dist/shared/lib/themes/types.js +2 -1
- package/dist/shared/lib/toast.js +43 -1
- package/dist/shared/lib/utils/public-page.js +44 -1
- package/dist/shared/lib/utils/question-reverse-transform.js +438 -1
- package/dist/shared/lib/utils/question-transform-types.js +1 -1
- package/dist/shared/lib/utils/question-transform-validation.js +194 -1
- package/dist/shared/lib/utils/question-transform.js +199 -1
- package/dist/shared/lib/utils.js +168 -1
- package/dist/shared/lib/validation/choose-correct-answer.validation.js +111 -1
- package/dist/shared/lib/validation/label-the-picture.validation.js +19 -1
- package/dist/shared/lib/validation/listen-and-choose-from-answer-group.validation.js +46 -1
- package/dist/shared/lib/validation/listen-and-choose-objects-in-scene.validation.js +21 -1
- package/dist/shared/lib/validation/listen-and-drag-objects-into-scene.validation.js +34 -1
- package/dist/shared/lib/validation/listen-and-speak-answer.validation.js +40 -1
- package/dist/shared/lib/validation/listen-and-speak-compare-images.validation.js +45 -1
- package/dist/shared/lib/validation/listen-and-speak-image-group.validation.js +19 -1
- package/dist/shared/lib/validation/listen-and-speak-info-exchange.validation.js +39 -1
- package/dist/shared/lib/validation/listen-and-speak-odd-one-out.validation.js +32 -1
- package/dist/shared/lib/validation/listen-and-speak-question-list.validation.js +19 -1
- package/dist/shared/lib/validation/listen-and-speak-with-story-images.validation.js +28 -1
- package/dist/shared/lib/validation/look-picture-choose-correct-answer.validation.js +12 -1
- package/dist/shared/lib/validation/look-picture-fill-blank-choose-answer.validation.js +47 -1
- package/dist/shared/lib/validation/read-and-color-objects.validation.js +29 -1
- package/dist/shared/lib/validation/read-displayed-content.validation.js +28 -1
- package/dist/shared/lib/validation/speaking-conversation.validation.js +75 -1
- package/dist/shared/lib/validation/speaking-describe-image.validation.js +31 -1
- package/dist/shared/lib/validation/spontaneous-qa.validation.js +48 -1
- package/dist/shared/lib/validation/word-fill-paragraph-default.validation.js +38 -1
- package/dist/shared/lib/validation/word-fill-paragraph-with-options.validation.js +39 -1
- package/dist/shared/lib/validation/word-fill-paragraph.validation.js +43 -1
- package/dist/shared/lib/validation/word-ordering.validation.js +33 -1
- package/dist/shared/types/branch.types.js +6 -1
- package/dist/shared/types/common.types.d.ts +1 -1
- package/dist/shared/types/common.types.js +49 -1
- package/dist/shared/types/entities/exam-schedule.types.js +5 -1
- package/dist/shared/types/entities/exam.types.js +1 -1
- package/dist/shared/types/entities/question.types.js +4 -1
- package/dist/shared/types/entities/result.types.js +4 -1
- package/dist/shared/types/entities/user.types.js +4 -1
- package/dist/shared/types/exam-taking.types.js +2 -1
- package/dist/shared/types/history.types.js +34 -1
- package/dist/shared/types/index.js +1 -1
- package/dist/shared/types/questions/choose-correct-adjective.js +4 -1
- package/dist/shared/types/questions/choose-the-correct-answer-group.d.ts +1 -0
- package/dist/shared/types/questions/choose-the-correct-answer-group.js +1 -1
- package/dist/shared/types/questions/choose-the-correct-answer.js +9 -1
- package/dist/shared/types/questions/cross-out-word-group.d.ts +2 -0
- package/dist/shared/types/questions/cross-out-word-group.js +1 -1
- package/dist/shared/types/questions/fill-missing-words-in-grid.js +11 -1
- package/dist/shared/types/questions/index.d.ts +1 -0
- package/dist/shared/types/questions/index.js +46 -1
- 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 +3 -1
- package/dist/shared/types/questions/listen-and-speak-odd-one-out.js +3 -1
- 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 +3 -1
- package/dist/shared/types/questions/look-picture-choose-correct-answer.js +5 -1
- package/dist/shared/types/questions/look-picture-fill-blank-choose-answer.js +9 -1
- package/dist/shared/types/questions/look-picture-fill-word-hint.js +7 -1
- package/dist/shared/types/questions/read-displayed-content.js +1 -1
- package/dist/shared/types/questions/speaking-conversation.js +7 -1
- 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/word-order-and-match-group.d.ts +33 -0
- package/dist/shared/types/questions/word-order-and-match-group.js +1 -0
- package/dist/shared/types/questions/write-correct-verb-form.js +12 -1
- package/dist/shared/types/role.types.js +1 -1
- package/dist/shared/types/structure-management.js +28 -1
- package/dist/shared/types/student.types.js +57 -1
- package/dist/shared/types/teacher-dashboard-rooms.js +2 -1
- package/package.json +184 -165
- package/dist/mcp/config.d.ts +0 -12
- package/dist/mcp/config.js +0 -1
- package/dist/mcp/http-client.d.ts +0 -6
- package/dist/mcp/http-client.js +0 -1
- package/dist/mcp/index.d.ts +0 -6
- package/dist/mcp/index.js +0 -2
- package/dist/mcp/tools/_helpers.d.ts +0 -4
- package/dist/mcp/tools/_helpers.js +0 -1
- package/dist/mcp/tools/exams.d.ts +0 -2
- package/dist/mcp/tools/exams.js +0 -1
- package/dist/mcp/tools/index.d.ts +0 -2
- package/dist/mcp/tools/index.js +0 -1
- package/dist/mcp/tools/results.d.ts +0 -2
- package/dist/mcp/tools/results.js +0 -1
|
@@ -1 +1,166 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { FileText, Info } from 'lucide-react';
|
|
4
|
+
import { EnglishCertificationQuestionCard } from './EnglishCertificationQuestionCard';
|
|
5
|
+
import { EnglishCertificationPassagePanel } from './EnglishCertificationPassagePanel';
|
|
6
|
+
import { EnglishCertificationReadingSection } from './EnglishCertificationReadingSection';
|
|
7
|
+
import { EnglishCertificationAudioPlayer } from './EnglishCertificationAudioPlayer';
|
|
8
|
+
import { EnglishCertificationInstructionBanner } from './EnglishCertificationInstructionBanner';
|
|
9
|
+
import { EnglishCertificationPartHeader } from './EnglishCertificationPartHeader';
|
|
10
|
+
import { ENGLISH_CERT_CONTENT_WIDTH_CLASS } from './english-certification-theme';
|
|
11
|
+
import { ENGLISH_CERT_STICKY_AUDIO_ATTR, englishCertQuestionDomId, } from './english-cert-scroll';
|
|
12
|
+
import { isHtmlContent, stripInstruction } from './grouped-question-utils';
|
|
13
|
+
import { ResolvedImage } from '../../../components/common/ResolvedImage';
|
|
14
|
+
/** Fixed split layout: equal-width passage / questions columns. */
|
|
15
|
+
const SPLIT_VIEW_GRID = 'minmax(0, 1fr) minmax(0, 1fr)';
|
|
16
|
+
/** Extracts the article list from a group payload (empty when absent). */
|
|
17
|
+
function extractArticles(payload) {
|
|
18
|
+
const raw = payload.articles;
|
|
19
|
+
return Array.isArray(raw) ? raw : [];
|
|
20
|
+
}
|
|
21
|
+
/** True when any article carries body text or an image worth displaying. */
|
|
22
|
+
function articlesHaveContent(articles) {
|
|
23
|
+
return articles.some((article) => Boolean(article?.content?.trim()) || Boolean(article?.imageUrl));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Splits a grouped reading part into its individual document groups while
|
|
27
|
+
* preserving the original question order. Each document keeps its own passage
|
|
28
|
+
* payload so the layout can stack them vertically on a single screen.
|
|
29
|
+
*/
|
|
30
|
+
function buildDocumentGroups(part, sharedInstruction) {
|
|
31
|
+
const order = [];
|
|
32
|
+
const byGroup = new Map();
|
|
33
|
+
part.questions.forEach((question) => {
|
|
34
|
+
const groupId = question.group_id ?? question.id;
|
|
35
|
+
if (!byGroup.has(groupId)) {
|
|
36
|
+
byGroup.set(groupId, []);
|
|
37
|
+
order.push(groupId);
|
|
38
|
+
}
|
|
39
|
+
byGroup.get(groupId).push(question);
|
|
40
|
+
});
|
|
41
|
+
return order.map((groupId) => {
|
|
42
|
+
const questions = byGroup.get(groupId);
|
|
43
|
+
const payload = questions[0]?.questionGroup?.payload ?? {};
|
|
44
|
+
const rawPassage = payload.content ?? payload.passage ?? '';
|
|
45
|
+
const passage = stripInstruction(rawPassage, sharedInstruction);
|
|
46
|
+
const passageImageUrl = payload.imageUrl ?? payload.passageImageUrl ?? '';
|
|
47
|
+
const articles = extractArticles(payload);
|
|
48
|
+
return {
|
|
49
|
+
groupId,
|
|
50
|
+
questions,
|
|
51
|
+
passage,
|
|
52
|
+
// API exposes the group heading as `title`; older Reading payloads use
|
|
53
|
+
// `passageTitle`. Fall back to `title` so grouped MCQ headings show.
|
|
54
|
+
passageTitle: payload.passageTitle ?? payload.title ?? '',
|
|
55
|
+
passageSubtitle: payload.subtitle ?? '',
|
|
56
|
+
passageImageUrl,
|
|
57
|
+
articles,
|
|
58
|
+
hasPassageContent: Boolean(passage.trim()) || Boolean(passageImageUrl) || articlesHaveContent(articles),
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Resolves the shared part instruction.
|
|
64
|
+
*
|
|
65
|
+
* Priority:
|
|
66
|
+
* 1. `questionGroup.payload.instructions` — used by some grouped question types.
|
|
67
|
+
* 2. `partInstructions` — the template-level instruction from the QuestionPart
|
|
68
|
+
* (e.g. Part 6 TOEIC where the instruction lives on the template part).
|
|
69
|
+
* 3. `content.question` of the first question — legacy fallback.
|
|
70
|
+
*/
|
|
71
|
+
function resolveSharedInstruction(part, partInstructions) {
|
|
72
|
+
const first = part.questions[0];
|
|
73
|
+
return (first?.questionGroup?.payload?.instructions ??
|
|
74
|
+
(partInstructions?.trim() || undefined) ??
|
|
75
|
+
first?.content?.question ??
|
|
76
|
+
'').trim();
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Ocean Edu branded split-view renderer for grouped reading parts.
|
|
80
|
+
*
|
|
81
|
+
* Renders every document of the part stacked vertically. Each document shows a
|
|
82
|
+
* reading passage (title, optional image, body, source bar) on the left and its
|
|
83
|
+
* MCQ questions on the right in a balanced 50/50 split.
|
|
84
|
+
*/
|
|
85
|
+
export function EnglishCertificationGroupedQuestion({ part, partConfig, answers, flaggedQuestions, onAnswerChange, onToggleFlag, isReviewMode = false, isListeningPart = false, partAudioUrl, isAudioLocked = false, onAudioFirstPlay, }) {
|
|
86
|
+
const startIndex = partConfig.startIndex ?? 0;
|
|
87
|
+
// Part-level instruction (e.g. "Read the texts that follow…") is shared by
|
|
88
|
+
// every document. Render it once at the top and strip it from each passage
|
|
89
|
+
// (the API prepends it to every document's content) to avoid duplication.
|
|
90
|
+
// Prefer part.instructions (set by groupQuestionsByPart from the template)
|
|
91
|
+
// which covers TOEIC Part 6 where the instruction lives on the template part
|
|
92
|
+
// rather than inside the question group payload.
|
|
93
|
+
const sharedInstruction = resolveSharedInstruction(part, part.instructions ?? partConfig.instructions);
|
|
94
|
+
// When the part carries template sections, render every question in a single
|
|
95
|
+
// document so the section loop in renderQuestions runs once and stacks each
|
|
96
|
+
// sub-section. Splitting by group_id here would duplicate the section headings
|
|
97
|
+
// and break per-section dispatch.
|
|
98
|
+
//
|
|
99
|
+
// The document still carries the shared passage when present: IELTS Reading
|
|
100
|
+
// parts ship a DOCUMENT group whose passage lives on each question's
|
|
101
|
+
// `questionGroup.payload` (content/title/subtitle). Surfacing it flips
|
|
102
|
+
// `hasPassageContent` to true so the split branch shows passage-left /
|
|
103
|
+
// questions-right (TOEIC Part 7 style). Mixed Listening parts (SECTION 2:
|
|
104
|
+
// CHOOSE + MATCH + WORD_FILL) carry no passage, so this stays false and the
|
|
105
|
+
// full-width no-passage branch is preserved.
|
|
106
|
+
const buildSectionedDocument = () => {
|
|
107
|
+
const payload = (part.questions[0]?.questionGroup?.payload ?? {});
|
|
108
|
+
const rawPassage = (payload.content ?? payload.passage ?? '');
|
|
109
|
+
const passage = stripInstruction(rawPassage, sharedInstruction);
|
|
110
|
+
const passageImageUrl = (payload.imageUrl ?? payload.passageImageUrl ?? '');
|
|
111
|
+
const articles = extractArticles(payload);
|
|
112
|
+
return {
|
|
113
|
+
groupId: part.partId,
|
|
114
|
+
questions: part.questions,
|
|
115
|
+
passage,
|
|
116
|
+
passageTitle: (payload.passageTitle ?? payload.title ?? ''),
|
|
117
|
+
passageSubtitle: (payload.subtitle ?? ''),
|
|
118
|
+
passageImageUrl,
|
|
119
|
+
articles,
|
|
120
|
+
hasPassageContent: Boolean(passage.trim()) || Boolean(passageImageUrl) || articlesHaveContent(articles),
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
const documents = part.sections?.length
|
|
124
|
+
? [buildSectionedDocument()]
|
|
125
|
+
: buildDocumentGroups(part, sharedInstruction);
|
|
126
|
+
if (!documents.length) {
|
|
127
|
+
return (_jsx("div", { className: "flex h-full items-center justify-center rounded-xl border border-red-200 bg-red-50 p-8 text-red-600", children: "No questions found for this part" }));
|
|
128
|
+
}
|
|
129
|
+
const isFullWidth = documents.some((doc) => doc.hasPassageContent);
|
|
130
|
+
const showAudio = isListeningPart && Boolean(partAudioUrl);
|
|
131
|
+
/** Renders a document's question list (used by both split and full-width layouts). */
|
|
132
|
+
const renderQuestions = (document) => {
|
|
133
|
+
if (part.sections?.length) {
|
|
134
|
+
return (_jsx("div", { className: "flex-1 space-y-6 px-4 py-4", children: part.sections.map((section, sectionIdx) => {
|
|
135
|
+
const sectionQuestions = document.questions.filter((question) => {
|
|
136
|
+
const pos = part.questions.indexOf(question);
|
|
137
|
+
return (pos >= section.startIndex - startIndex &&
|
|
138
|
+
pos <= section.endIndex - startIndex);
|
|
139
|
+
});
|
|
140
|
+
if (!sectionQuestions.length)
|
|
141
|
+
return null;
|
|
142
|
+
return (_jsx(EnglishCertificationReadingSection, { part: part, section: section, questions: sectionQuestions, startIndex: startIndex, answers: answers, flaggedQuestions: flaggedQuestions, onAnswerChange: onAnswerChange, onToggleFlag: onToggleFlag, isReviewMode: isReviewMode }, `${document.groupId}-section-${sectionIdx}`));
|
|
143
|
+
}) }));
|
|
144
|
+
}
|
|
145
|
+
return (_jsx("div", { className: "flex-1 space-y-3 px-4 py-4", children: document.questions.map((question) => {
|
|
146
|
+
const questionNumber = part.questions.indexOf(question) + 1;
|
|
147
|
+
const globalQuestionNumber = startIndex + questionNumber;
|
|
148
|
+
return (_jsx(EnglishCertificationQuestionCard, { question: question, globalQuestionNumber: globalQuestionNumber, answer: answers[question.id], isFlagged: flaggedQuestions.has(question.id), sharedInstruction: sharedInstruction, onAnswerChange: onAnswerChange, onToggleFlag: onToggleFlag, isReviewMode: isReviewMode, domId: englishCertQuestionDomId(question.id) }, question.id));
|
|
149
|
+
}) }));
|
|
150
|
+
};
|
|
151
|
+
return (_jsxs("div", { className: "flex h-full flex-col gap-6 overflow-y-auto pb-4", children: [_jsx(EnglishCertificationPartHeader, { partName: part.name, partNo: part.partNo, skill: partConfig.category, isFullWidth: isFullWidth }), _jsx(EnglishCertificationInstructionBanner, { instruction: sharedInstruction, isListeningPart: isListeningPart, isFullWidth: isFullWidth }), showAudio && (_jsx("div", { [ENGLISH_CERT_STICKY_AUDIO_ATTR]: '', className: `sticky top-0 z-20 ${ENGLISH_CERT_CONTENT_WIDTH_CLASS} w-full self-center`, children: _jsx(EnglishCertificationAudioPlayer, { audioUrl: partAudioUrl, partNumber: part.partNo, isLocked: isAudioLocked, onFirstPlay: onAudioFirstPlay }) })), documents.map((document) => {
|
|
152
|
+
const firstNumber = part.questions.indexOf(document.questions[0]) + startIndex + 1;
|
|
153
|
+
const lastNumber = part.questions.indexOf(document.questions[document.questions.length - 1]) +
|
|
154
|
+
startIndex +
|
|
155
|
+
1;
|
|
156
|
+
const passageIsHtml = isHtmlContent(document.passage);
|
|
157
|
+
// No-passage group (e.g. Listening grouped MCQ that only carries a
|
|
158
|
+
// heading like "Choose the correct letter, A, B or C"): hide the empty
|
|
159
|
+
// passage panel and render the group title as a banner above the
|
|
160
|
+
// full-width questions.
|
|
161
|
+
if (!document.hasPassageContent) {
|
|
162
|
+
return (_jsxs("div", { className: `${ENGLISH_CERT_CONTENT_WIDTH_CLASS} flex w-full flex-col gap-3 self-center`, children: [_jsxs("div", { className: "flex items-center gap-4 rounded-xl border border-[#d9e4f2] bg-white/90 px-5 py-4 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md", children: [_jsx("span", { className: "grid h-12 w-12 shrink-0 place-items-center rounded-xl bg-[#eaf2ff] text-[#1167e8]", children: _jsx(FileText, { className: "h-6 w-6" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("span", { className: "inline-flex items-center gap-1.5 rounded-md border border-[#bfd8f8] bg-[#eaf2ff] px-2.5 py-1 text-xs font-bold text-[#0b57d0]", children: ["Questions ", firstNumber, "\u2013", lastNumber] }), document.passageTitle && (_jsx("p", { className: "mt-2 text-lg font-bold leading-tight text-[#0f1730]", children: document.passageTitle })), document.passageSubtitle && (_jsx("p", { className: "mt-1 text-[15px] font-medium text-[#475569]", children: document.passageSubtitle }))] }), document.passageImageUrl && (_jsx(ResolvedImage, { src: document.passageImageUrl, alt: document.passageTitle || 'Illustration', className: "h-20 w-32 shrink-0 rounded-lg object-contain" }))] }), _jsx("section", { className: "flex flex-col overflow-hidden rounded-xl border border-[#d9e4f2] bg-white/90 shadow-[0_14px_35px_rgba(13,71,161,0.12)] backdrop-blur-md", children: renderQuestions(document) })] }, document.groupId));
|
|
163
|
+
}
|
|
164
|
+
return (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsx("div", { className: "flex flex-wrap items-center gap-3 rounded-xl border border-[#d9e4f2] bg-white/85 px-4 py-3 shadow-[0_5px_16px_rgba(13,71,161,0.08)] backdrop-blur-md", children: _jsxs("div", { className: "flex items-center gap-2.5 rounded-md border border-[#bfd8f8] bg-white/70 px-3 py-1.5 text-base font-bold text-[#0b57d0]", children: [_jsx("span", { className: "grid h-[18px] w-[18px] place-items-center rounded-full bg-[#1167e8] text-white", children: _jsx(Info, { className: "h-3 w-3" }) }), "Questions ", firstNumber, "\u2013", lastNumber, " refer to the following passage."] }) }), _jsxs("div", { className: "grid gap-4", style: { gridTemplateColumns: SPLIT_VIEW_GRID }, children: [_jsx("div", { className: "h-full max-h-[calc(100vh-220px)] min-h-0 overflow-y-auto", children: _jsx(EnglishCertificationPassagePanel, { passage: document.passage, passageTitle: document.passageTitle, passageSubtitle: document.passageSubtitle, passageImageUrl: document.passageImageUrl, articles: document.articles, passageIsHtml: passageIsHtml }) }), _jsx("section", { className: "flex max-h-[calc(100vh-220px)] min-h-0 flex-col overflow-y-auto rounded-xl border border-[#d9e4f2] bg-white/90 shadow-[0_14px_35px_rgba(13,71,161,0.12)] backdrop-blur-md", children: renderQuestions(document) })] })] }, document.groupId));
|
|
165
|
+
})] }));
|
|
166
|
+
}
|
|
@@ -1 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { Loader2 } from 'lucide-react';
|
|
4
|
+
import { cn } from '../../../shared/lib/utils';
|
|
5
|
+
import { EnglishCertificationBrand } from './EnglishCertificationBrand';
|
|
6
|
+
/**
|
|
7
|
+
* Formats seconds into HH:MM:SS string.
|
|
8
|
+
* Always shows hours for the 2-hour standardized exams.
|
|
9
|
+
*/
|
|
10
|
+
function formatTime(seconds) {
|
|
11
|
+
const h = Math.floor(seconds / 3600);
|
|
12
|
+
const m = Math.floor((seconds % 3600) / 60);
|
|
13
|
+
const s = seconds % 60;
|
|
14
|
+
return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Formats a Date into HH:MM local time string.
|
|
18
|
+
*/
|
|
19
|
+
function formatSavedAt(date) {
|
|
20
|
+
return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false });
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Branded Ocean Edu top header bar for English Certification exam taking.
|
|
24
|
+
*
|
|
25
|
+
* Layout (desktop): brand block · test name · part/range meta · timer · submit.
|
|
26
|
+
*/
|
|
27
|
+
export function EnglishCertificationHeader({ examName, remainingSeconds, totalQuestions, answeredCount, isSubmitting, onSubmit, lastSavedAt, isSaving, partLabel, partSubLabel, questionRange, }) {
|
|
28
|
+
const isWarning = remainingSeconds <= 900 && remainingSeconds > 300; // 5-15 min
|
|
29
|
+
const isCritical = remainingSeconds <= 300; // ≤5 min
|
|
30
|
+
return (_jsxs("header", { className: cn('sticky top-0 z-50 flex h-[74px] items-center gap-4 border-b border-[#d9e4f2] px-4 lg:px-6', 'bg-white/95 shadow-[0_8px_26px_rgba(10,61,154,0.08)] backdrop-blur-md'), children: [_jsx("div", { className: "flex shrink-0 items-center gap-3", children: _jsx("div", { className: "hidden border-r border-[#d9e4f2] pr-4 sm:block", children: _jsx(EnglishCertificationBrand, {}) }) }), _jsxs("div", { className: "hidden min-w-0 lg:block", children: [_jsx("strong", { className: "block truncate text-[17px] font-semibold leading-tight text-[#0f1730]", children: examName }), _jsx("span", { className: "mt-1 block text-sm font-bold text-[#64748b]", children: "English Certification" })] }), _jsxs("div", { className: "flex flex-1 items-center justify-center gap-5 text-center", children: [partLabel && (_jsxs("div", { className: "leading-tight text-[#0b57d0]", children: [_jsx("div", { className: "text-sm font-black tracking-wide", children: partLabel }), partSubLabel && (_jsx("div", { className: "mt-1 text-xs font-semibold text-[#27324a]", children: partSubLabel }))] })), questionRange && (_jsxs("div", { className: "whitespace-nowrap text-[15px] font-bold text-[#0f1730]", children: ["Questions ", _jsx("span", { className: "text-[#0b57d0]", children: questionRange })] }))] }), _jsxs("div", { className: "flex shrink-0 flex-col items-center border-l border-[#d9e4f2] pl-4", children: [_jsx("span", { className: cn('font-mono text-xl font-black leading-none tracking-wide tabular-nums lg:text-2xl', !isWarning && !isCritical && 'text-[#0b57d0]', isWarning && 'text-orange-500', isCritical && 'animate-pulse text-red-500'), "aria-live": "polite", "aria-label": `Time remaining: ${formatTime(remainingSeconds)}`, children: formatTime(remainingSeconds) }), _jsx("span", { className: "mt-1 text-[11px] font-semibold text-[#64748b]", children: "Time Remaining" }), (isSaving || lastSavedAt) && (_jsx("span", { className: "mt-0.5 flex items-center gap-1 text-[10px] text-slate-400", children: isSaving ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "h-2.5 w-2.5 animate-spin" }), "Saving..."] })) : lastSavedAt ? (_jsxs(_Fragment, { children: ["Saved ", formatSavedAt(lastSavedAt)] })) : null }))] }), _jsxs("div", { className: "flex shrink-0 items-center gap-3", children: [_jsxs("div", { className: "hidden text-right sm:block", children: [_jsxs("div", { className: "text-sm font-semibold text-[#0f1730]", children: [_jsx("span", { className: "text-[#0b57d0]", children: answeredCount }), _jsxs("span", { className: "text-slate-400", children: ["/", totalQuestions] })] }), _jsx("div", { className: "text-[11px] text-slate-400", children: "Answered" })] }), _jsx("button", { type: "button", onClick: onSubmit, disabled: isSubmitting, className: cn('inline-flex h-12 items-center gap-1.5 rounded-lg px-5 text-sm font-black tracking-wide text-white', 'bg-gradient-to-b from-[#ffad31] to-[#ff8a00] shadow-[0_12px_24px_rgba(255,138,0,0.3)]', 'transition-all hover:-translate-y-0.5 hover:brightness-[0.98]', 'disabled:cursor-not-allowed disabled:opacity-60'), children: isSubmitting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), "Submitting..."] })) : ('SUBMIT TEST') })] })] }));
|
|
31
|
+
}
|
package/dist/components/themes/english-certification/EnglishCertificationInstructionBanner.js
CHANGED
|
@@ -1 +1,79 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Headphones, Info } from 'lucide-react';
|
|
4
|
+
import { ENGLISH_CERT_COLORS, ENGLISH_CERT_CONTENT_WIDTH_CLASS, ENGLISH_CERT_PRIMARY_GRADIENT, } from './english-certification-theme';
|
|
5
|
+
import { isHtmlContent } from './grouped-question-utils';
|
|
6
|
+
/**
|
|
7
|
+
* Drops a leading "Directions:" prefix (legacy plain-text format) so it isn't
|
|
8
|
+
* repeated below the styled "Directions" header. Only applied to plain text —
|
|
9
|
+
* HTML instructions (which may include a worked "Example:" section after the
|
|
10
|
+
* directions paragraph) are rendered as-is, since safely stripping just the
|
|
11
|
+
* leading label from arbitrary rich markup isn't reliable.
|
|
12
|
+
*/
|
|
13
|
+
function stripDirectionsPrefix(text) {
|
|
14
|
+
return text.replace(/^\s*directions\s*[:.\\-–]?\s*/i, '').trim() || text;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Premium branded "Directions" callout block.
|
|
18
|
+
*
|
|
19
|
+
* Design:
|
|
20
|
+
* - Gradient header strip with icon + "DIRECTIONS" label — clear visual anchor.
|
|
21
|
+
* - Cream-white body with generous padding for readability.
|
|
22
|
+
* - HTML instructions rendered as rich prose with "Example:" sections styled
|
|
23
|
+
* as an inset callout for TOEIC-style worked examples.
|
|
24
|
+
* - Plain-text instructions get the same header but a simple prose paragraph.
|
|
25
|
+
*/
|
|
26
|
+
export function EnglishCertificationInstructionBanner({ instruction, isListeningPart = false, isFullWidth = false, }) {
|
|
27
|
+
if (!instruction)
|
|
28
|
+
return null;
|
|
29
|
+
const Icon = isListeningPart ? Headphones : Info;
|
|
30
|
+
const htmlInstruction = isHtmlContent(instruction);
|
|
31
|
+
const body = htmlInstruction ? instruction : stripDirectionsPrefix(instruction);
|
|
32
|
+
return (_jsxs("div", { className: isFullWidth ? 'w-full' : `${ENGLISH_CERT_CONTENT_WIDTH_CLASS} w-full self-center`, children: [_jsxs("div", { className: "overflow-hidden rounded-2xl", style: {
|
|
33
|
+
boxShadow: '0 4px 6px -1px rgba(11,87,208,0.08), 0 12px_28px rgba(11,87,208,0.10)',
|
|
34
|
+
border: `1px solid ${ENGLISH_CERT_COLORS.blue600}26`,
|
|
35
|
+
}, children: [_jsxs("div", { className: "flex items-center gap-3 px-5 py-3", style: { background: ENGLISH_CERT_PRIMARY_GRADIENT }, children: [_jsx("span", { className: "grid h-8 w-8 shrink-0 place-items-center rounded-lg", style: { background: 'rgba(255,255,255,0.18)' }, children: _jsx(Icon, { className: "h-4 w-4 text-white", strokeWidth: 2.5 }) }), _jsx("span", { className: "text-[11px] font-black uppercase tracking-[0.22em] text-white/90", children: "Directions" }), _jsx("div", { className: "ml-auto flex items-center gap-1", "aria-hidden": true, children: [0.5, 0.35, 0.2].map((op, i) => (_jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-white", style: { opacity: op } }, i))) })] }), _jsx("div", { className: "px-6 py-5", style: {
|
|
36
|
+
background: 'linear-gradient(160deg, #f8fbff 0%, #eef5ff 100%)',
|
|
37
|
+
}, children: htmlInstruction ? (
|
|
38
|
+
/* ── Rich HTML (TOEIC-style with Example block) ────── */
|
|
39
|
+
_jsx("div", { className: "ec-instruction-html text-[15px] leading-[1.8] text-[#0f1730]",
|
|
40
|
+
// The instruction HTML comes from the exam CMS and is
|
|
41
|
+
// not user-generated, so dangerouslySetInnerHTML is safe here.
|
|
42
|
+
dangerouslySetInnerHTML: { __html: body } })) : (
|
|
43
|
+
/* ── Plain text ─────────────────────────────────────── */
|
|
44
|
+
_jsx("p", { className: "text-[15px] font-semibold leading-[1.8] text-[#0f1730]", children: body })) })] }), _jsx("style", { children: `
|
|
45
|
+
/* Base paragraphs */
|
|
46
|
+
.ec-instruction-html p {
|
|
47
|
+
margin-bottom: 0.5rem;
|
|
48
|
+
font-size: 15px;
|
|
49
|
+
font-weight: 600;
|
|
50
|
+
color: #0f1730;
|
|
51
|
+
}
|
|
52
|
+
.ec-instruction-html p:last-child {
|
|
53
|
+
margin-bottom: 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* Bold labels ("Directions:", "Example:") */
|
|
57
|
+
.ec-instruction-html strong {
|
|
58
|
+
font-weight: 700;
|
|
59
|
+
color: ${ENGLISH_CERT_COLORS.blue700};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* "Example:" paragraph — inset callout block */
|
|
63
|
+
.ec-instruction-html p:has(> strong:first-child):not(:first-child) {
|
|
64
|
+
margin-top: 1rem;
|
|
65
|
+
padding: 0.7rem 1rem;
|
|
66
|
+
background: rgba(11, 87, 208, 0.06);
|
|
67
|
+
border-left: 3px solid ${ENGLISH_CERT_COLORS.blue600};
|
|
68
|
+
border-radius: 0 8px 8px 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* Lines that follow inside an inset callout */
|
|
72
|
+
.ec-instruction-html p:has(> strong:first-child) ~ p {
|
|
73
|
+
padding-left: 1rem;
|
|
74
|
+
font-size: 14.5px;
|
|
75
|
+
font-weight: 500;
|
|
76
|
+
color: #1e2d4d;
|
|
77
|
+
}
|
|
78
|
+
` })] }));
|
|
79
|
+
}
|
|
@@ -1 +1,71 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useRef, useEffect, useMemo } from 'react';
|
|
4
|
+
import { cn } from '../../../shared/lib/utils';
|
|
5
|
+
/** Returns true when an answer entry counts as "answered". */
|
|
6
|
+
function isAnswered(answer) {
|
|
7
|
+
if (answer === undefined || answer === null || answer === '')
|
|
8
|
+
return false;
|
|
9
|
+
if (typeof answer === 'object' && 'optionId' in answer) {
|
|
10
|
+
return Boolean(answer.optionId);
|
|
11
|
+
}
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Branded Ocean Edu "Answer Sheet" navigation panel.
|
|
16
|
+
*
|
|
17
|
+
* Shows an Answered / Unanswered / Marked summary, a per-part question grid
|
|
18
|
+
* (answered, current, marked states) and a legend, bound to real store data.
|
|
19
|
+
*/
|
|
20
|
+
export function EnglishCertificationNavigationPanel({ parts, questions, answers, flaggedQuestions, currentIndex, onQuestionClick, onPartClick, }) {
|
|
21
|
+
const buttonRefs = useRef(new Map());
|
|
22
|
+
// Scroll current button into view when currentIndex changes.
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const btn = buttonRefs.current.get(currentIndex);
|
|
25
|
+
btn?.scrollIntoView({ block: 'center', behavior: 'smooth' });
|
|
26
|
+
}, [currentIndex]);
|
|
27
|
+
const { answeredCount, markedCount, unansweredCount } = useMemo(() => {
|
|
28
|
+
const answered = questions.filter((q) => isAnswered(answers[q.id])).length;
|
|
29
|
+
const marked = questions.filter((q) => flaggedQuestions.has(q.id)).length;
|
|
30
|
+
return {
|
|
31
|
+
answeredCount: answered,
|
|
32
|
+
markedCount: marked,
|
|
33
|
+
unansweredCount: questions.length - answered,
|
|
34
|
+
};
|
|
35
|
+
}, [questions, answers, flaggedQuestions]);
|
|
36
|
+
return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "grid grid-cols-3 gap-3 p-4 pb-2", children: [_jsx(SummaryBox, { label: "Answered", value: answeredCount, variant: "answered" }), _jsx(SummaryBox, { label: "Unanswered", value: unansweredCount, variant: "unanswered" }), _jsx(SummaryBox, { label: "Marked", value: markedCount, variant: "marked" })] }), _jsxs("div", { className: "flex-1 overflow-y-auto px-4 pb-4", children: [parts.map((part, partIdx) => {
|
|
37
|
+
const startGlobal = part.startIndex ?? 0;
|
|
38
|
+
const endGlobal = part.endIndex ?? startGlobal;
|
|
39
|
+
const totalInPart = endGlobal - startGlobal + 1;
|
|
40
|
+
return (_jsxs("section", { className: "mb-5", children: [_jsx("button", { type: "button", onClick: () => onPartClick(partIdx), className: cn('mb-3 w-full text-left text-[15px] font-black text-[#17213a] transition-colors hover:text-[#0b57d0]', currentIndex >= startGlobal &&
|
|
41
|
+
currentIndex <= endGlobal &&
|
|
42
|
+
'text-[#0b57d0]'), children: part.name || `Part ${partIdx + 1}` }), _jsx("div", { className: "grid grid-cols-5 gap-2.5", children: Array.from({ length: totalInPart }, (_, i) => {
|
|
43
|
+
const globalIdx = startGlobal + i;
|
|
44
|
+
const question = questions[globalIdx];
|
|
45
|
+
if (!question)
|
|
46
|
+
return null;
|
|
47
|
+
const answered = isAnswered(answers[question.id]);
|
|
48
|
+
const flagged = flaggedQuestions.has(question.id);
|
|
49
|
+
const current = globalIdx === currentIndex;
|
|
50
|
+
const displayNum = globalIdx + 1;
|
|
51
|
+
return (_jsxs("button", { ref: (el) => {
|
|
52
|
+
if (el)
|
|
53
|
+
buttonRefs.current.set(globalIdx, el);
|
|
54
|
+
else
|
|
55
|
+
buttonRefs.current.delete(globalIdx);
|
|
56
|
+
}, type: "button", onClick: () => onQuestionClick(globalIdx), className: cn('relative flex h-[50px] items-center justify-center rounded-md border text-[15px] font-bold transition-all', 'focus-visible:ring-2 focus-visible:ring-[#1167e8] focus-visible:ring-offset-1', answered
|
|
57
|
+
? 'border-[#b9edc8] bg-[#ddf8e7] text-[#111827]'
|
|
58
|
+
: 'border-[#d9e4f2] bg-white text-[#111827]', current &&
|
|
59
|
+
'border-[#1167e8] text-[#0b57d0] shadow-[inset_0_0_0_1px_#1167e8]'), "aria-label": `Question ${displayNum}${answered ? ', answered' : ', unanswered'}${flagged ? ', marked' : ''}`, "aria-current": current ? 'true' : undefined, children: [displayNum, flagged && (_jsx("span", { className: "absolute -top-px right-2 h-[18px] w-[9px] bg-[#ff8a00]", style: {
|
|
60
|
+
clipPath: 'polygon(0 0, 100% 0, 100% 100%, 50% 70%, 0 100%)',
|
|
61
|
+
}, "aria-hidden": "true" }))] }, question.id));
|
|
62
|
+
}) })] }, partIdx));
|
|
63
|
+
}), _jsxs("div", { className: "mt-2 rounded-md border border-[#d9e4f2] bg-white/70 p-4", children: [_jsx(LegendRow, { variant: "current", children: "Current Question" }), _jsx(LegendRow, { variant: "answered", children: "Answered" }), _jsx(LegendRow, { variant: "none", children: "Not Answered" }), _jsx(LegendRow, { variant: "marked", children: "Marked for Review" })] })] })] }));
|
|
64
|
+
}
|
|
65
|
+
function SummaryBox({ label, value, variant, }) {
|
|
66
|
+
return (_jsx("div", { className: "grid min-h-[78px] place-items-center rounded-md border border-[#d9e4f2] bg-white text-center", children: _jsxs("div", { children: [_jsx("span", { className: cn('block text-[11px] font-black uppercase tracking-wide', variant === 'answered' && 'text-[#0a3d9a]', variant === 'unanswered' && 'text-[#17213a]', variant === 'marked' && 'text-[#f97316]'), children: label }), _jsx("strong", { className: cn('mt-2 block text-[28px] leading-none', variant === 'answered' && 'text-[#0b57d0]', variant === 'unanswered' && 'text-[#17213a]', variant === 'marked' && 'text-[#f97316]'), children: value })] }) }));
|
|
67
|
+
}
|
|
68
|
+
function LegendRow({ variant, children, }) {
|
|
69
|
+
return (_jsxs("div", { className: "my-3 flex items-center gap-3.5 text-sm font-semibold text-[#334155]", children: [variant === 'marked' ? (_jsx("span", { className: "h-[18px] w-2.5 bg-[#ff8a00]", style: { clipPath: 'polygon(0 0, 100% 0, 100% 100%, 50% 70%, 0 100%)' } })) : (_jsx("span", { className: cn('h-[22px] w-[22px] rounded border border-[#d9e4f2] bg-white', variant === 'current' &&
|
|
70
|
+
'border-[#1167e8] shadow-[inset_0_0_0_1px_#1167e8]', variant === 'answered' && 'border-[#b9edc8] bg-[#ddf8e7]') })), children] }));
|
|
71
|
+
}
|
|
@@ -1 +1,79 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useRef } from 'react';
|
|
4
|
+
import { cn } from '../../../shared/lib/utils';
|
|
5
|
+
import { Check, CheckCircle2, X, XCircle } from 'lucide-react';
|
|
6
|
+
/**
|
|
7
|
+
* Shared A–D answer selector for all English Certification question types.
|
|
8
|
+
*
|
|
9
|
+
* Renders either large branded cards or compact rows, and shows
|
|
10
|
+
* correct/incorrect indicators in review mode.
|
|
11
|
+
*/
|
|
12
|
+
export function EnglishCertificationOptionSelector({ options, selectedOptionId, onSelect, disabled = false, isReviewMode = false, correctOptionId, variant = 'cards', }) {
|
|
13
|
+
const buttonRefs = useRef([]);
|
|
14
|
+
// Roving tabindex: only the selected option (or the first, if none selected)
|
|
15
|
+
// is in the tab order; arrow keys move focus + selection between options,
|
|
16
|
+
// matching native <input type="radio"> group behavior.
|
|
17
|
+
const selectedIndex = options.findIndex((option) => option.id === selectedOptionId);
|
|
18
|
+
const tabbableIndex = selectedIndex >= 0 ? selectedIndex : 0;
|
|
19
|
+
const handleKeyDown = (event, index) => {
|
|
20
|
+
if (disabled)
|
|
21
|
+
return;
|
|
22
|
+
let nextIndex;
|
|
23
|
+
switch (event.key) {
|
|
24
|
+
case 'ArrowRight':
|
|
25
|
+
case 'ArrowDown':
|
|
26
|
+
nextIndex = (index + 1) % options.length;
|
|
27
|
+
break;
|
|
28
|
+
case 'ArrowLeft':
|
|
29
|
+
case 'ArrowUp':
|
|
30
|
+
nextIndex = (index - 1 + options.length) % options.length;
|
|
31
|
+
break;
|
|
32
|
+
default:
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
event.preventDefault();
|
|
36
|
+
const nextOption = options[nextIndex];
|
|
37
|
+
onSelect(nextOption.id);
|
|
38
|
+
buttonRefs.current[nextIndex]?.focus();
|
|
39
|
+
};
|
|
40
|
+
if (variant === 'compact') {
|
|
41
|
+
return (_jsx("div", { className: "flex flex-col gap-1", role: "radiogroup", children: options.map((option, index) => {
|
|
42
|
+
const isSelected = option.id === selectedOptionId;
|
|
43
|
+
const isCorrect = isReviewMode && option.id === correctOptionId;
|
|
44
|
+
const isWrong = isReviewMode && isSelected && option.id !== correctOptionId;
|
|
45
|
+
return (_jsxs("button", { ref: (el) => {
|
|
46
|
+
buttonRefs.current[index] = el;
|
|
47
|
+
}, type: "button", role: "radio", "aria-checked": isSelected, disabled: disabled, tabIndex: index === tabbableIndex ? 0 : -1, onClick: () => !disabled && onSelect(option.id), onKeyDown: (event) => handleKeyDown(event, index), className: cn('flex items-center gap-2.5 rounded-md border border-transparent px-2.5 py-1.5 text-left text-base transition-all', 'hover:border-[#c8def7] hover:bg-[#f4f9ff]', isSelected &&
|
|
48
|
+
!isReviewMode &&
|
|
49
|
+
'border-[#99c5f8] bg-[#eff7ff] shadow-[inset_0_0_0_1px_rgba(17,103,232,0.08)]', isCorrect && 'border-[#b9edc8] bg-[#ddf8e7]', isWrong && 'border-red-300 bg-red-50', disabled && 'cursor-not-allowed opacity-60'), children: [_jsx("span", { className: cn('grid h-4 w-4 shrink-0 place-items-center rounded-full border-2 border-[#94a3b8]', isSelected && !isReviewMode && 'border-[#0b57d0]', isCorrect && 'border-[#22c55e]', isWrong && 'border-red-500'), children: isSelected && (_jsx("span", { className: cn('h-2 w-2 rounded-full bg-[#0b57d0]', isCorrect && 'bg-[#22c55e]', isWrong && 'bg-red-500') })) }), _jsx("span", { className: "font-bold text-[#23304c]", children: option.label }), _jsx("span", { className: "flex-1 leading-snug text-[#1e293b]", children: option.text }), isReviewMode && isCorrect && (_jsx(CheckCircle2, { className: "h-4 w-4 shrink-0 text-[#22c55e]", "aria-label": "Correct" })), isReviewMode && isWrong && (_jsx(XCircle, { className: "h-4 w-4 shrink-0 text-red-500", "aria-label": "Incorrect" }))] }, option.id));
|
|
50
|
+
}) }));
|
|
51
|
+
}
|
|
52
|
+
if (variant === 'list') {
|
|
53
|
+
return (_jsx("div", { className: "flex flex-col gap-3", role: "radiogroup", children: options.map((option, index) => {
|
|
54
|
+
const isSelected = option.id === selectedOptionId;
|
|
55
|
+
const isCorrect = isReviewMode && option.id === correctOptionId;
|
|
56
|
+
const isWrong = isReviewMode && isSelected && option.id !== correctOptionId;
|
|
57
|
+
const isActive = isSelected && !isReviewMode;
|
|
58
|
+
return (_jsxs("button", { ref: (el) => {
|
|
59
|
+
buttonRefs.current[index] = el;
|
|
60
|
+
}, type: "button", role: "radio", "aria-checked": isSelected, disabled: disabled, tabIndex: index === tabbableIndex ? 0 : -1, onClick: () => !disabled && onSelect(option.id), onKeyDown: (event) => handleKeyDown(event, index), className: cn('flex items-center gap-4 rounded-2xl border-2 p-4 text-left transition-all', 'border-[#e5eefb] bg-white shadow-[0_5px_16px_rgba(13,71,161,0.08)]', 'hover:border-[#bfd8f8] hover:bg-[#fbfdff] hover:shadow-[0_10px_22px_rgba(13,71,161,0.14)]', isActive &&
|
|
61
|
+
'border-transparent text-white shadow-[0_16px_30px_rgba(11,87,208,0.25)]', isCorrect && 'border-[#22c55e] bg-[#ddf8e7]', isWrong && 'border-red-400 bg-red-50', disabled && 'cursor-not-allowed opacity-60'), style: isActive
|
|
62
|
+
? { background: 'linear-gradient(180deg, #1f7cff, #0b57d0)' }
|
|
63
|
+
: undefined, children: [_jsx("span", { className: cn('grid h-11 w-11 shrink-0 place-items-center rounded-full border-2 text-lg font-black transition-colors', 'border-[#bfd8f8] bg-[#eef5ff] text-[#0b57d0]', isActive && 'border-white/70 bg-white/15 text-white', isCorrect && 'border-[#22c55e] bg-white text-[#22c55e]', isWrong && 'border-red-500 bg-white text-red-500'), children: option.label }), _jsx("span", { className: cn('flex-1 text-[15px] font-semibold leading-relaxed text-[#0f1730]', isActive && 'text-white', isCorrect && 'text-[#15803d]', isWrong && 'text-red-700'), children: option.text }), (isActive || isCorrect) && (_jsx("span", { className: "grid h-7 w-7 shrink-0 place-items-center rounded-full bg-white text-[#0b57d0] shadow-[0_2px_6px_rgba(11,87,208,0.25)]", children: _jsx(Check, { className: "h-4 w-4", strokeWidth: 3 }) })), isWrong && (_jsx("span", { className: "grid h-7 w-7 shrink-0 place-items-center rounded-full bg-white text-red-500 shadow-[0_2px_6px_rgba(239,68,68,0.25)]", children: _jsx(X, { className: "h-4 w-4", strokeWidth: 3 }) }))] }, option.id));
|
|
64
|
+
}) }));
|
|
65
|
+
}
|
|
66
|
+
// 'cards' variant — large A–D answer cards.
|
|
67
|
+
return (_jsx("div", { className: "grid gap-4 sm:gap-5", style: { gridTemplateColumns: `repeat(${Math.min(options.length, 4)}, minmax(0, 1fr))` }, role: "radiogroup", children: options.map((option, index) => {
|
|
68
|
+
const isSelected = option.id === selectedOptionId;
|
|
69
|
+
const isCorrect = isReviewMode && option.id === correctOptionId;
|
|
70
|
+
const isWrong = isReviewMode && isSelected && option.id !== correctOptionId;
|
|
71
|
+
const isActive = isSelected && !isReviewMode;
|
|
72
|
+
return (_jsxs("button", { ref: (el) => {
|
|
73
|
+
buttonRefs.current[index] = el;
|
|
74
|
+
}, type: "button", role: "radio", "aria-checked": isSelected, disabled: disabled, tabIndex: index === tabbableIndex ? 0 : -1, onClick: () => !disabled && onSelect(option.id), onKeyDown: (event) => handleKeyDown(event, index), className: cn('relative flex min-h-[104px] flex-col items-center justify-center rounded-2xl border-2 p-3 transition-all', 'border-[#e5eefb] bg-white shadow-[0_5px_16px_rgba(13,71,161,0.08)]', 'hover:-translate-y-0.5 hover:border-[#bfd8f8] hover:shadow-[0_10px_22px_rgba(13,71,161,0.14)]', isActive &&
|
|
75
|
+
'border-transparent text-white shadow-[0_16px_30px_rgba(11,87,208,0.25)] hover:-translate-y-0.5', isCorrect && 'border-[#22c55e] bg-[#ddf8e7]', isWrong && 'border-red-400 bg-red-50', disabled && 'cursor-not-allowed opacity-60 hover:translate-y-0'), style: isActive
|
|
76
|
+
? { background: 'linear-gradient(180deg, #1f7cff, #0b57d0)' }
|
|
77
|
+
: undefined, children: [_jsx("span", { className: cn('grid h-[52px] w-[52px] place-items-center rounded-full border-2 text-2xl font-black transition-colors', 'border-[#bfd8f8] bg-[#eef5ff] text-[#0b57d0]', isActive && 'border-white/70 bg-white/15 text-white', isCorrect && 'border-[#22c55e] bg-white text-[#22c55e]', isWrong && 'border-red-500 bg-white text-red-500'), children: option.label }), option.text && (_jsx("span", { className: cn('mt-2 text-center text-sm font-semibold leading-snug text-[#0f1730]', isActive && 'text-white', isCorrect && 'text-[#15803d]', isWrong && 'text-red-700'), children: option.text })), (isActive || isCorrect) && (_jsx("span", { className: "absolute right-2.5 top-2.5 grid h-6 w-6 place-items-center rounded-full bg-white text-[#0b57d0] shadow-[0_2px_6px_rgba(11,87,208,0.25)]", children: _jsx(Check, { className: "h-3.5 w-3.5", strokeWidth: 3 }) })), isWrong && (_jsx("span", { className: "absolute right-2.5 top-2.5 grid h-6 w-6 place-items-center rounded-full bg-white text-red-500 shadow-[0_2px_6px_rgba(239,68,68,0.25)]", children: _jsx(X, { className: "h-3.5 w-3.5", strokeWidth: 3 }) }))] }, option.id));
|
|
78
|
+
}) }));
|
|
79
|
+
}
|
|
@@ -1 +1,47 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { BookOpen, Headphones, Pencil, Mic } from 'lucide-react';
|
|
4
|
+
import { ENGLISH_CERT_COLORS, ENGLISH_CERT_CONTENT_WIDTH_CLASS, ENGLISH_CERT_PRIMARY_GRADIENT, } from './english-certification-theme';
|
|
5
|
+
function skillMeta(skill) {
|
|
6
|
+
switch ((skill ?? '').toUpperCase()) {
|
|
7
|
+
case 'LISTENING':
|
|
8
|
+
return { Icon: Headphones, label: 'Listening', color: '#0b57d0' };
|
|
9
|
+
case 'READING':
|
|
10
|
+
return { Icon: BookOpen, label: 'Reading', color: '#0f6cbf' };
|
|
11
|
+
case 'WRITING':
|
|
12
|
+
return { Icon: Pencil, label: 'Writing', color: '#1255a0' };
|
|
13
|
+
case 'SPEAKING':
|
|
14
|
+
return { Icon: Mic, label: 'Speaking', color: '#0d4fa3' };
|
|
15
|
+
default:
|
|
16
|
+
return { Icon: BookOpen, label: null, color: ENGLISH_CERT_COLORS.blue700 };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Premium standalone Part title header for English Certification exams.
|
|
21
|
+
*
|
|
22
|
+
* Design decisions:
|
|
23
|
+
* - Full-bleed gradient card matching the brand palette (never plain text).
|
|
24
|
+
* - Large ghost number in the background gives spatial identity.
|
|
25
|
+
* - Skill badge + icon communicate exam section at a glance.
|
|
26
|
+
* - Decorative wave SVG and a thin accent bar at the bottom tie it
|
|
27
|
+
* to the footer / audio-player language.
|
|
28
|
+
*/
|
|
29
|
+
export function EnglishCertificationPartHeader({ partName, partNo, skill, subtitle, isFullWidth = false, }) {
|
|
30
|
+
if (!partName && partNo === undefined)
|
|
31
|
+
return null;
|
|
32
|
+
const { Icon, label } = skillMeta(skill);
|
|
33
|
+
// Normalise display: strip leading "PART " so we can control formatting.
|
|
34
|
+
const displayName = partName
|
|
35
|
+
? partName.replace(/^part\s*/i, '').toUpperCase()
|
|
36
|
+
: String(partNo ?? '');
|
|
37
|
+
const bigNumber = partNo ?? (partName?.match(/\d+/)?.[0] ?? '');
|
|
38
|
+
return (_jsx("div", { className: isFullWidth ? 'w-full' : `${ENGLISH_CERT_CONTENT_WIDTH_CLASS} w-full self-center`, children: _jsxs("div", { className: "relative overflow-hidden rounded-2xl", style: {
|
|
39
|
+
background: ENGLISH_CERT_PRIMARY_GRADIENT,
|
|
40
|
+
boxShadow: '0 8px 32px rgba(11,87,208,0.28), 0 2px 8px rgba(11,87,208,0.16)',
|
|
41
|
+
}, children: [_jsx("span", { "aria-hidden": true, className: "pointer-events-none absolute -right-4 -top-3 select-none font-black leading-none text-white/10", style: { fontSize: 'clamp(80px, 12vw, 110px)' }, children: bigNumber }), _jsx("div", { "aria-hidden": true, className: "pointer-events-none absolute -left-12 -top-12 h-48 w-48 rounded-full", style: {
|
|
42
|
+
background: 'radial-gradient(circle, rgba(255,255,255,0.12) 0%, transparent 70%)',
|
|
43
|
+
} }), _jsxs("div", { className: "relative flex items-center gap-5 px-7 py-5", children: [_jsx("div", { className: "grid h-14 w-14 shrink-0 place-items-center rounded-2xl shadow-[0_4px_16px_rgba(0,0,0,0.20)]", style: { background: 'rgba(255,255,255,0.18)', backdropFilter: 'blur(8px)' }, children: _jsx(Icon, { className: "h-6 w-6 text-white", strokeWidth: 2 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [label && (_jsx("span", { className: "mb-1.5 inline-flex items-center gap-1.5 rounded-full px-3 py-0.5 text-[10px] font-black uppercase tracking-[0.2em]", style: {
|
|
44
|
+
background: 'rgba(255,255,255,0.20)',
|
|
45
|
+
color: 'rgba(255,255,255,0.90)',
|
|
46
|
+
}, children: label })), _jsxs("p", { className: "text-2xl font-black leading-none tracking-tight text-white drop-shadow-sm", children: ["Part", ' ', _jsx("span", { className: "rounded-lg px-2.5 py-0.5 text-[22px] font-black", style: { background: 'rgba(255,255,255,0.22)' }, children: displayName })] }), subtitle && (_jsx("p", { className: "mt-1 text-[13px] font-medium text-white/75", children: subtitle }))] })] }), _jsx("svg", { "aria-hidden": true, className: "block w-full", height: "18", viewBox: "0 0 940 18", preserveAspectRatio: "none", fill: "none", children: _jsx("path", { d: "M0 8C160 0 300 16 470 8C640 0 780 16 940 8V18H0V8Z", fill: "rgba(255,255,255,0.10)" }) })] }) }));
|
|
47
|
+
}
|