@tinyweb_dev/oe-exam-sdk 0.1.3 → 0.1.5
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 +112 -13
- package/dist/api/contest-rooms.d.ts +13 -0
- package/dist/api/contest-rooms.js +1 -0
- package/dist/api/contest-rooms.types.d.ts +47 -0
- package/dist/api/contest-rooms.types.js +1 -0
- package/dist/api/exam-entry.d.ts +14 -0
- package/dist/api/exam-entry.js +1 -0
- package/dist/api/exam-entry.types.d.ts +93 -0
- package/dist/api/exam-entry.types.js +1 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +1 -1
- package/dist/api/result-review.d.ts +2 -1
- package/dist/api/result-review.js +1 -1
- package/dist/api/result-review.types.d.ts +69 -3
- package/dist/api/result-review.types.js +1 -1
- package/dist/components/exams/entry/EntryRestartDialog.d.ts +12 -0
- package/dist/components/exams/entry/EntryRestartDialog.js +1 -0
- package/dist/components/exams/entry/StudentExamEntryPageContainer.d.ts +31 -0
- package/dist/components/exams/entry/StudentExamEntryPageContainer.js +1 -0
- package/dist/components/exams/entry/exam-entry.states.d.ts +22 -0
- package/dist/components/exams/entry/exam-entry.states.js +1 -0
- package/dist/components/exams/entry/exam-entry.utils.d.ts +16 -0
- package/dist/components/exams/entry/exam-entry.utils.js +1 -0
- package/dist/components/exams/entry/fullscreen-loading.d.ts +5 -0
- package/dist/components/exams/entry/fullscreen-loading.js +1 -0
- package/dist/components/exams/entry/index.d.ts +7 -0
- package/dist/components/exams/entry/index.js +1 -0
- package/dist/components/exams/index.d.ts +8 -0
- package/dist/components/exams/index.js +1 -1
- package/dist/components/exams/rooms/StudentContestRoomsPageContainer.d.ts +18 -0
- package/dist/components/exams/rooms/StudentContestRoomsPageContainer.js +1 -0
- package/dist/components/exams/rooms/contest-rooms.utils.d.ts +32 -0
- package/dist/components/exams/rooms/contest-rooms.utils.js +1 -0
- package/dist/components/exams/rooms/index.d.ts +3 -0
- package/dist/components/exams/rooms/index.js +1 -0
- package/dist/components/exams/take/ExamTakingApiContext.d.ts +10 -0
- package/dist/components/exams/take/ExamTakingApiContext.js +1 -0
- package/dist/components/exams/take/ExamTakingPageContainer.d.ts +28 -4
- package/dist/components/exams/take/ExamTakingPageContainer.js +1 -1
- package/dist/components/exams/take/components/QuestionRenderer.d.ts +25 -0
- package/dist/components/exams/take/components/QuestionRenderer.js +1 -0
- package/dist/components/exams/take/components/index.d.ts +10 -0
- package/dist/components/exams/take/components/index.js +1 -0
- package/dist/components/exams/take/components/question-renderers/ArticlesViewer.d.ts +7 -0
- package/dist/components/exams/take/components/question-renderers/ArticlesViewer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversAnswerTheQuestionRenderer.d.ts +22 -0
- package/dist/components/exams/take/components/question-renderers/MoversAnswerTheQuestionRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversChooseAdjectiveRenderer.d.ts +14 -0
- package/dist/components/exams/take/components/question-renderers/MoversChooseAdjectiveRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversChooseBestAnswerRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversChooseBestAnswerRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversColoringRenderer.d.ts +3 -0
- package/dist/components/exams/take/components/question-renderers/MoversColoringRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversGridFillRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversGridFillRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversLabelThePictureRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversLabelThePictureRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversListenAndWriteRenderer.d.ts +21 -0
- package/dist/components/exams/take/components/question-renderers/MoversListenAndWriteRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversMatchByWritingAnswerRenderer.d.ts +19 -0
- package/dist/components/exams/take/components/question-renderers/MoversMatchByWritingAnswerRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversPictureChooseRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversPictureFillBlankChooseRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversReadingPassageRenderer.d.ts +2 -0
- package/dist/components/exams/take/components/question-renderers/MoversReadingPassageRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversTrueFalseRenderer.d.ts +20 -0
- package/dist/components/exams/take/components/question-renderers/MoversTrueFalseRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordFillParagraphRenderer.d.ts +32 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordFillParagraphRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordFillStructuredFormRenderer.d.ts +18 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordFillStructuredFormRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordOrderingRenderer.d.ts +19 -0
- package/dist/components/exams/take/components/question-renderers/MoversWordOrderingRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversWriteSentencesRenderer.d.ts +22 -0
- package/dist/components/exams/take/components/question-renderers/MoversWriteSentencesRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/MoversWritingRenderer.d.ts +18 -0
- package/dist/components/exams/take/components/question-renderers/MoversWritingRenderer.js +1 -0
- package/dist/components/exams/take/components/question-renderers/index.d.ts +19 -0
- package/dist/components/exams/take/components/question-renderers/index.js +1 -0
- package/dist/components/exams/take/components/speaking/FindObjectInPicture.module.css +133 -0
- package/dist/components/exams/take/components/speaking/SpeakingAudioPlayer.d.ts +9 -0
- package/dist/components/exams/take/components/speaking/SpeakingAudioPlayer.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingCompareImages.module.css +153 -0
- package/dist/components/exams/take/components/speaking/SpeakingContentFrame.d.ts +7 -0
- package/dist/components/exams/take/components/speaking/SpeakingContentFrame.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingDragObjects.module.css +238 -0
- package/dist/components/exams/take/components/speaking/SpeakingExamLayout.d.ts +27 -0
- package/dist/components/exams/take/components/speaking/SpeakingExamLayout.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingHeader.d.ts +6 -0
- package/dist/components/exams/take/components/speaking/SpeakingHeader.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingInfoExchange.module.css +193 -0
- package/dist/components/exams/take/components/speaking/SpeakingInfoExchangeSummerSky.module.css +238 -0
- package/dist/components/exams/take/components/speaking/SpeakingInstructionBar.d.ts +5 -0
- package/dist/components/exams/take/components/speaking/SpeakingInstructionBar.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingMicButton.d.ts +14 -0
- package/dist/components/exams/take/components/speaking/SpeakingMicButton.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingNavButton.d.ts +7 -0
- package/dist/components/exams/take/components/speaking/SpeakingNavButton.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingPartBadge.d.ts +6 -0
- package/dist/components/exams/take/components/speaking/SpeakingPartBadge.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingReadDisplayedContent.module.css +115 -0
- package/dist/components/exams/take/components/speaking/SpeakingRecordingPreview.d.ts +11 -0
- package/dist/components/exams/take/components/speaking/SpeakingRecordingPreview.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingReportErrorButton.d.ts +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingReportErrorButton.js +1 -0
- package/dist/components/exams/take/components/speaking/SpeakingStoryImages.module.css +231 -0
- package/dist/components/exams/take/components/speaking/SpeakingVideoIntro.d.ts +13 -0
- package/dist/components/exams/take/components/speaking/SpeakingVideoIntro.js +1 -0
- package/dist/components/exams/take/components/speaking/index.d.ts +1 -0
- package/dist/components/exams/take/components/speaking/index.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingChooseAnswerGroupRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingChooseAnswerGroupRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingChooseObjectsRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingChooseObjectsRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingCompareImagesRenderer.d.ts +17 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingCompareImagesRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingConversationRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingConversationRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingCueCardRenderer.d.ts +17 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingCueCardRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingDescribeImageRenderer.d.ts +18 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingDescribeImageRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingDragObjectsRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingDragObjectsRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingGNInterviewRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingInfoExchangeRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingInfoExchangeRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingListenAndSpeakAnswerRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingListenAndSpeakAnswerRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingOddOneOutRenderer.d.ts +16 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingOddOneOutRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionListRenderer.d.ts +26 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionListRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionRenderer.d.ts +32 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingQuestionRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingReadDisplayedContentRenderer.d.ts +17 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingReadDisplayedContentRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingSpontaneousQARenderer.d.ts +17 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingSpontaneousQARenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingStoryImagesRenderer.d.ts +17 -0
- package/dist/components/exams/take/components/speaking/renderers/SpeakingStoryImagesRenderer.js +1 -0
- package/dist/components/exams/take/components/speaking/renderers/index.d.ts +13 -0
- package/dist/components/exams/take/components/speaking/renderers/index.js +1 -0
- package/dist/components/exams/take/hooks/index.d.ts +2 -0
- package/dist/components/exams/take/hooks/index.js +1 -0
- package/dist/components/exams/take/hooks/useAnswerAutosave.d.ts +27 -0
- package/dist/components/exams/take/hooks/useAnswerAutosave.js +1 -0
- package/dist/components/exams/take/hooks/useAttemptSubmit.d.ts +29 -0
- package/dist/components/exams/take/hooks/useAttemptSubmit.js +1 -0
- package/dist/components/exams/take/hooks/useAutoSave.d.ts +20 -0
- package/dist/components/exams/take/hooks/useAutoSave.js +1 -0
- package/dist/components/exams/take/hooks/useExamCountdown.d.ts +22 -0
- package/dist/components/exams/take/hooks/useExamCountdown.js +1 -0
- package/dist/components/exams/take/hooks/useExamTimer.d.ts +21 -0
- package/dist/components/exams/take/hooks/useExamTimer.js +1 -0
- package/dist/components/exams/take/hooks/useProctoringCamera.d.ts +19 -0
- package/dist/components/exams/take/hooks/useProctoringCamera.js +1 -0
- package/dist/components/exams/take/hooks/useProctoringSnapshot.d.ts +25 -0
- package/dist/components/exams/take/hooks/useProctoringSnapshot.js +1 -0
- package/dist/components/exams/take/hooks/useSpeakingConversationAudio.d.ts +19 -0
- package/dist/components/exams/take/hooks/useSpeakingConversationAudio.js +1 -0
- package/dist/components/exams/take/hooks/useSpeakingNavigation.d.ts +37 -0
- package/dist/components/exams/take/hooks/useSpeakingNavigation.js +1 -0
- package/dist/components/exams/take/hooks/useSpeakingRecorder.d.ts +45 -5
- package/dist/components/exams/take/hooks/useSpeakingRecorder.js +1 -1
- package/dist/components/exams/take/hooks/useSpeakingRendererSetup.d.ts +39 -0
- package/dist/components/exams/take/hooks/useSpeakingRendererSetup.js +1 -0
- package/dist/components/exams/take/hooks/useToeicAudio.d.ts +17 -0
- package/dist/components/exams/take/hooks/useToeicAudio.js +1 -0
- package/dist/components/exams/take/index.d.ts +9 -1
- package/dist/components/exams/take/index.js +1 -1
- package/dist/components/exams/take/types/speaking-cue-card.types.d.ts +10 -0
- package/dist/components/exams/take/types/speaking-cue-card.types.js +1 -0
- package/dist/components/exams/take/types/speaking.types.d.ts +153 -0
- package/dist/components/exams/take/types/speaking.types.js +1 -0
- package/dist/components/exams/take/types.d.ts +286 -1
- package/dist/components/exams/take/utils/answer-transformers.d.ts +26 -0
- package/dist/components/exams/take/utils/answer-transformers.js +1 -0
- package/dist/components/exams/take/utils/coloring-assignments.d.ts +5 -0
- package/dist/components/exams/take/utils/coloring-assignments.js +1 -0
- package/dist/components/exams/take/utils/question-transformers.d.ts +362 -0
- package/dist/components/exams/take/utils/question-transformers.js +1 -0
- package/dist/components/features/exam-entry/entry-state-cards.d.ts +19 -0
- package/dist/components/features/exam-entry/entry-state-cards.js +1 -0
- package/dist/components/features/exam-entry/index.d.ts +2 -0
- package/dist/components/features/exam-entry/index.js +1 -0
- package/dist/components/features/exam-entry/themed/CambridgeYleWaitingRoom.d.ts +12 -0
- package/dist/components/features/exam-entry/themed/CambridgeYleWaitingRoom.js +1 -0
- package/dist/components/features/exam-entry/themed/ThemedWaitingRoom.d.ts +14 -0
- package/dist/components/features/exam-entry/themed/ThemedWaitingRoom.js +1 -0
- package/dist/components/features/exam-entry/themed/ToeicWaitingRoom.d.ts +16 -0
- package/dist/components/features/exam-entry/themed/ToeicWaitingRoom.js +1 -0
- package/dist/components/features/exam-entry/themed/components/CloseButton.d.ts +9 -0
- package/dist/components/features/exam-entry/themed/components/CloseButton.js +1 -0
- package/dist/components/features/exam-entry/themed/components/ExamInfoPanel.d.ts +13 -0
- package/dist/components/features/exam-entry/themed/components/ExamInfoPanel.js +1 -0
- package/dist/components/features/exam-entry/themed/components/ModeSelector.d.ts +7 -0
- package/dist/components/features/exam-entry/themed/components/ModeSelector.js +1 -0
- package/dist/components/features/exam-entry/themed/components/StartButton.d.ts +11 -0
- package/dist/components/features/exam-entry/themed/components/StartButton.js +1 -0
- package/dist/components/features/exam-entry/themed/components/index.d.ts +4 -0
- package/dist/components/features/exam-entry/themed/components/index.js +1 -0
- package/dist/components/features/exam-entry/themed/index.d.ts +1 -0
- package/dist/components/features/exam-entry/themed/index.js +1 -0
- package/dist/components/results/ResultReviewPageContainer.d.ts +16 -2
- package/dist/components/results/ResultReviewPageContainer.js +1 -1
- package/dist/components/results/ReviewQuestionRenderer.d.ts +11 -1
- package/dist/components/results/ReviewQuestionRenderer.js +1 -1
- package/dist/components/results/hooks/useResultReviewPolling.d.ts +37 -0
- package/dist/components/results/hooks/useResultReviewPolling.js +1 -0
- package/dist/components/results/index.d.ts +36 -1
- package/dist/components/results/index.js +1 -1
- package/dist/components/results/renderers/QuestionExplanations.d.ts +22 -0
- package/dist/components/results/renderers/QuestionExplanations.js +1 -0
- package/dist/components/results/renderers/ReviewChooseAdjectiveRenderer.d.ts +13 -0
- package/dist/components/results/renderers/ReviewChooseAdjectiveRenderer.js +1 -0
- package/dist/components/results/renderers/ReviewChooseBestAnswerRenderer.d.ts +22 -0
- package/dist/components/results/renderers/ReviewChooseBestAnswerRenderer.js +1 -0
- package/dist/components/results/renderers/ReviewColoringRenderer.d.ts +16 -0
- package/dist/components/results/renderers/ReviewColoringRenderer.js +1 -0
- package/dist/components/results/renderers/ReviewListenAndWriteRenderer.d.ts +18 -0
- package/dist/components/results/renderers/ReviewListenAndWriteRenderer.js +1 -0
- package/dist/components/results/renderers/ReviewListenChooseAnswerGroupRenderer.d.ts +25 -0
- package/dist/components/results/renderers/ReviewListenChooseAnswerGroupRenderer.js +1 -0
- package/dist/components/results/renderers/ReviewListenChooseObjectsRenderer.d.ts +25 -0
- package/dist/components/results/renderers/ReviewListenChooseObjectsRenderer.js +1 -0
- package/dist/components/results/renderers/ReviewListenDragObjectsRenderer.d.ts +25 -0
- package/dist/components/results/renderers/ReviewListenDragObjectsRenderer.js +1 -0
- package/dist/components/results/renderers/ReviewListeningHeader.d.ts +44 -0
- package/dist/components/results/renderers/ReviewListeningHeader.js +1 -0
- package/dist/components/results/renderers/ReviewSpeakingAIPanel.d.ts +17 -0
- package/dist/components/results/renderers/ReviewSpeakingAIPanel.js +1 -0
- package/dist/components/results/renderers/ReviewSpeakingMedia.d.ts +39 -0
- package/dist/components/results/renderers/ReviewSpeakingMedia.js +1 -0
- package/dist/components/results/renderers/ReviewSpeakingQuestionItem.d.ts +5 -0
- package/dist/components/results/renderers/ReviewSpeakingQuestionItem.js +1 -0
- package/dist/components/results/renderers/ReviewSpeakingRenderer.d.ts +3 -0
- package/dist/components/results/renderers/ReviewSpeakingRenderer.js +1 -0
- package/dist/components/results/renderers/ReviewSpeakingRenderer.types.d.ts +80 -0
- package/dist/components/results/renderers/ReviewSpeakingRenderer.types.js +1 -0
- package/dist/components/results/renderers/review-question-body-dedicated.d.ts +15 -0
- package/dist/components/results/renderers/review-question-body-dedicated.js +1 -0
- package/dist/components/results/renderers/review-question-body-movers.d.ts +17 -0
- package/dist/components/results/renderers/review-question-body-movers.js +1 -0
- package/dist/components/results/renderers/review-speaking-map.d.ts +7 -0
- package/dist/components/results/renderers/review-speaking-map.js +1 -0
- package/dist/components/results/report/BadgeTitle.d.ts +5 -0
- package/dist/components/results/report/BadgeTitle.js +1 -0
- package/dist/components/results/report/ExamSkillRow.d.ts +14 -0
- package/dist/components/results/report/ExamSkillRow.js +1 -0
- package/dist/components/results/report/OceanEduExamReport.d.ts +31 -0
- package/dist/components/results/report/OceanEduExamReport.js +1 -0
- package/dist/components/results/report/OceanEduSpeakingReport.d.ts +26 -0
- package/dist/components/results/report/OceanEduSpeakingReport.js +1 -0
- package/dist/components/results/report/OverallAssessmentSection.d.ts +24 -0
- package/dist/components/results/report/OverallAssessmentSection.js +1 -0
- package/dist/components/results/report/ResultErrorState.d.ts +14 -0
- package/dist/components/results/report/ResultErrorState.js +1 -0
- package/dist/components/results/report/ResultLoadingState.d.ts +11 -0
- package/dist/components/results/report/ResultLoadingState.js +1 -0
- package/dist/components/results/report/ResultNotPublicState.d.ts +16 -0
- package/dist/components/results/report/ResultNotPublicState.js +1 -0
- package/dist/components/results/report/SpeakingReportParts.d.ts +4 -0
- package/dist/components/results/report/SpeakingReportParts.js +1 -0
- package/dist/components/results/report/SpeakingReportShared.d.ts +36 -0
- package/dist/components/results/report/SpeakingReportShared.js +1 -0
- package/dist/components/results/report/SpeakingRubricSection.d.ts +21 -0
- package/dist/components/results/report/SpeakingRubricSection.js +1 -0
- package/dist/components/results/report/assets/dofu2.png +0 -0
- package/dist/components/results/report/assets/dofu4.png +0 -0
- package/dist/components/results/report/assets/logo-ocean.png +0 -0
- package/dist/components/results/report/assets/penguin-main.png +0 -0
- package/dist/components/results/report/assets/penguin-small.png +0 -0
- package/dist/components/results/report/speaking-report.utils.d.ts +37 -0
- package/dist/components/results/report/speaking-report.utils.js +1 -0
- package/dist/components/results/review-data.d.ts +1 -0
- package/dist/components/results/review-data.js +1 -1
- package/dist/components/results/review-status.utils.d.ts +12 -0
- package/dist/components/results/review-status.utils.js +1 -0
- package/dist/components/results/review-types.d.ts +14 -0
- package/dist/components/results/speaking/SpeakingResultAudioPlayer.d.ts +17 -0
- package/dist/components/results/speaking/SpeakingResultAudioPlayer.js +1 -0
- package/dist/components/results/speaking/SpeakingReviewResult.d.ts +30 -0
- package/dist/components/results/speaking/SpeakingReviewResult.js +1 -0
- package/dist/components/results/utils/review-score.utils.d.ts +21 -0
- package/dist/components/results/utils/review-score.utils.js +1 -0
- package/dist/components/results/utils/speaking-summary.d.ts +41 -0
- package/dist/components/results/utils/speaking-summary.js +1 -0
- package/dist/components/results/utils/transform-speaking-review.d.ts +62 -0
- package/dist/components/results/utils/transform-speaking-review.js +1 -0
- package/dist/components/shared/audio/SpeakingAudioPlayer.d.ts +12 -0
- package/dist/components/shared/audio/SpeakingAudioPlayer.js +1 -0
- package/dist/components/shared/audio/SpeakingAudioPlayer.module.css +115 -0
- package/dist/components/shared/audio/assets/fr-image-part1-border.png +0 -0
- package/dist/components/shared/audio/assets/ic-speaker.webp +0 -0
- package/dist/components/themes/english-certification/EnglishCertificationAudioPlayer.d.ts +11 -3
- package/dist/components/themes/english-certification/EnglishCertificationAudioPlayer.js +1 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.d.ts +5 -1
- package/dist/components/themes/english-certification/EnglishCertificationQuestionRenderer.js +1 -1
- package/dist/components/themes/index.d.ts +11 -0
- package/dist/components/themes/index.js +1 -1
- package/dist/components/themes/spaceship/SpaceshipAudioPlayer.d.ts +8 -0
- package/dist/components/themes/spaceship/SpaceshipAudioPlayer.js +1 -0
- package/dist/components/themes/spaceship/SpaceshipLayout.d.ts +2 -0
- package/dist/components/themes/spaceship/SpaceshipLayout.js +1 -0
- package/dist/components/themes/spaceship/assets/images/X-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/X.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/audio-bar.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/background.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/bg_sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/big-blue-badge-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/big-blue-badge.png +0 -0
- package/dist/components/themes/spaceship/assets/images/big-blue-badge.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/bingo.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/blue-badge-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/blue-badge.png +0 -0
- package/dist/components/themes/spaceship/assets/images/blue-wrapper-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/blue-wrapper.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/board_red.png +0 -0
- package/dist/components/themes/spaceship/assets/images/button_feedback_vi.png +0 -0
- package/dist/components/themes/spaceship/assets/images/circle-btn-right-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/circle-btn-right.png +0 -0
- package/dist/components/themes/spaceship/assets/images/circle-btn-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/circle-btn.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/focus-vector.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/head-phone_red.png +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-mute-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-mute.png +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-play-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-play-violet.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/ic-play.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/micro.png +0 -0
- package/dist/components/themes/spaceship/assets/images/next-small.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/next-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/next.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/purple-circle.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/question-badge-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/question-badge.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/red-badge-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/red-badge.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/red-wrapper-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/red-wrapper.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/robot-avatar.png +0 -0
- package/dist/components/themes/spaceship/assets/images/sound_red.png +0 -0
- package/dist/components/themes/spaceship/assets/images/student-avatar.png +0 -0
- package/dist/components/themes/spaceship/assets/images/teacher-play-sunset.png +0 -0
- package/dist/components/themes/spaceship/assets/images/teacher-play.webp +0 -0
- package/dist/components/themes/spaceship/assets/images/timer-badge.png +0 -0
- package/dist/components/themes/spaceship/assets/styles/SpaceshipLayout.module.css +347 -0
- package/dist/components/themes/spaceship/assets/styles/SpaceshipWaitingRoom.module.css +395 -0
- package/dist/components/ui/badge.d.ts +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/shared/lib/stores/examTakingStore.d.ts +54 -0
- package/dist/shared/lib/stores/examTakingStore.js +1 -0
- package/dist/shared/lib/stores/gradingTransientStore.d.ts +23 -0
- package/dist/shared/lib/stores/gradingTransientStore.js +1 -0
- package/dist/shared/lib/themes/config/starters.config.d.ts +3 -0
- package/dist/shared/lib/themes/config/starters.config.js +1 -0
- package/dist/shared/lib/themes/index.d.ts +18 -0
- package/dist/shared/lib/themes/index.js +1 -0
- package/dist/shared/lib/themes/types.d.ts +39 -0
- package/dist/shared/lib/themes/types.js +1 -0
- package/dist/shared/lib/toast.d.ts +19 -0
- package/dist/shared/lib/toast.js +1 -0
- package/package.json +12 -2
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ApiData, ExamEntryAttempt, ExamEntryRoom } from '../../../api/exam-entry.types';
|
|
2
|
+
/** Entry screen state machine, mirrors the host app's EntryState. */
|
|
3
|
+
export type ExamEntryState = 'LOADING' | 'BEFORE_START' | 'WITHIN_WINDOW' | 'EXPIRED' | 'ALREADY_SUBMITTED' | 'NO_EXAM' | 'NO_ACCESS' | 'REGISTRATION_REQUIRED';
|
|
4
|
+
export declare function unwrap<T>(value: ApiData<T> | T): T;
|
|
5
|
+
export declare function unwrapAttempt(value: ExamEntryAttempt | {
|
|
6
|
+
attempt: ExamEntryAttempt;
|
|
7
|
+
}): ExamEntryAttempt;
|
|
8
|
+
/**
|
|
9
|
+
* Determine the entry state from room + attempt data. Ported from the host
|
|
10
|
+
* app's `determineState`, including the `allowMultipleSubmissions` handling.
|
|
11
|
+
*/
|
|
12
|
+
export declare function determineEntryState(room: ExamEntryRoom, attempt: ExamEntryAttempt | null): ExamEntryState;
|
|
13
|
+
/** Seconds remaining until a room's start time (clamped at 0). */
|
|
14
|
+
export declare function getSecondsUntilStart(room: ExamEntryRoom): number;
|
|
15
|
+
/** Human-friendly countdown string (days/hours/minutes/seconds). */
|
|
16
|
+
export declare function formatCountdown(seconds: number): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const t=new Set(["SUBMITTED","GRADED","PUBLISHED"]);export function unwrap(t){return function(t){return"object"==typeof t&&null!==t&&"data"in t}(t)?t.data:t}export function unwrapAttempt(t){return"attempt"in t?t.attempt:t}export function determineEntryState(e,n){const r=!0===e.allowMultipleSubmissions;if(n){const e=n.status??"";if(t.has(e))return r?"WITHIN_WINDOW":"ALREADY_SUBMITTED";if("IN_PROGRESS"===e)return"WITHIN_WINDOW"}const a=Date.now(),o=e.startDatetime?new Date(e.startDatetime).getTime():null,i=e.endDatetime?new Date(e.endDatetime).getTime():null;return!r&&i&&a>i?"EXPIRED":o&&a<o?"BEFORE_START":"WITHIN_WINDOW"}export function getSecondsUntilStart(t){if(!t.startDatetime)return 0;const e=new Date(t.startDatetime).getTime();return Math.max(0,Math.floor((e-Date.now())/1e3))}export function formatCountdown(t){const e=Math.floor(t/86400),n=Math.floor(t%86400/3600),r=Math.floor(t%3600/60),a=t%60;return e>0?`${e} ngày ${n} giờ ${r} phút`:n>0?`${n} giờ ${r} phút ${a} giây`:r>0?`${r} phút ${a} giây`:`${a} giây`}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{Loader2 as s}from"lucide-react";import{getTheme as a}from"../../../shared/lib/themes";export function FullscreenLoading(){const r=a(),i=r.visuals?.backgroundFilter??"grayscale(1) blur(8px) saturate(0.85) brightness(0.9)",l=r.visuals?.backgroundOverlay??"linear-gradient(to bottom, rgba(0, 0, 0, 0.1), transparent, rgba(0, 0, 0, 0.2))";return t("div",{className:"fixed inset-0 z-50 flex items-center justify-center overflow-hidden",children:[e("div",{className:"absolute inset-0 scale-110 bg-cover bg-center",style:{backgroundImage:`url(${r.assets.background})`,filter:i}}),e("div",{className:"absolute inset-0",style:{background:l}}),t("div",{className:"relative z-10 flex flex-col items-center gap-4",children:[e(s,{className:"h-12 w-12 animate-spin text-white drop-shadow-lg"}),e("p",{className:"text-lg font-medium text-white drop-shadow-lg",children:"Đang tải..."})]})]})}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { StudentExamEntryPageContainer } from './StudentExamEntryPageContainer';
|
|
2
|
+
export type { StudentExamEntryPageContainerProps } from './StudentExamEntryPageContainer';
|
|
3
|
+
export { EntryRestartDialog } from './EntryRestartDialog';
|
|
4
|
+
export type { EntryRestartDialogProps } from './EntryRestartDialog';
|
|
5
|
+
export { EntryLoading, EntryMessage, EntryWaitingRoom } from './exam-entry.states';
|
|
6
|
+
export { determineEntryState, formatCountdown, getSecondsUntilStart, unwrap, unwrapAttempt, } from './exam-entry.utils';
|
|
7
|
+
export type { ExamEntryState } from './exam-entry.utils';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{StudentExamEntryPageContainer}from"./StudentExamEntryPageContainer";export{EntryRestartDialog}from"./EntryRestartDialog";export{EntryLoading,EntryMessage,EntryWaitingRoom}from"./exam-entry.states";export{determineEntryState,formatCountdown,getSecondsUntilStart,unwrap,unwrapAttempt}from"./exam-entry.utils";
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
export * from './take';
|
|
2
|
+
export { StudentExamEntryPageContainer } from './entry';
|
|
3
|
+
export type { StudentExamEntryPageContainerProps } from './entry';
|
|
4
|
+
export { EntryRestartDialog, EntryLoading, EntryMessage, EntryWaitingRoom } from './entry';
|
|
5
|
+
export type { EntryRestartDialogProps } from './entry';
|
|
6
|
+
export { determineEntryState, formatCountdown, getSecondsUntilStart } from './entry';
|
|
7
|
+
export type { ExamEntryState } from './entry';
|
|
8
|
+
export { StudentContestRoomsPageContainer } from './rooms';
|
|
9
|
+
export type { StudentContestRoomsPageContainerProps } from './rooms';
|
|
2
10
|
export { CreateExamPageContainer } from './CreateExamPageContainer';
|
|
3
11
|
export type { CreateExamPageContainerProps } from './CreateExamPageContainer';
|
|
4
12
|
export { CreateExamInfoForm } from './CreateExamInfoForm';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./take";export{CreateExamPageContainer}from"./CreateExamPageContainer";export{CreateExamInfoForm}from"./CreateExamInfoForm";export{TemplateSelector}from"./TemplateSelector";export{ExamCreator}from"./ExamCreator";export{ExamPartTabs}from"./ExamPartTabs";export{ExamQuestionGrid}from"./ExamQuestionGrid";export{PartAudioUploader}from"./PartAudioUploader";export{createExamQuestionsApi,createExamQuestionsFetchApi,createMockExamQuestionsApi}from"./api";export{ExamQuestionsPageContainer}from"./ExamQuestionsPageContainer";export{UnsavedChangesDialog}from"./UnsavedChangesDialog";export{CompletionDialog}from"./CompletionDialog";export{EXAM_DIFFICULTY,ExamViewDialog}from"./ExamViewDialog";export{ExamPreviewDialog}from"./ExamPreviewDialog";export{QuestionStatus,clearQuestionStatuses,getQuestionStatus,initializeQuestionStatusesFromAPI,setQuestionStatus}from"./exam-question-status";
|
|
1
|
+
export*from"./take";export{StudentExamEntryPageContainer}from"./entry";export{EntryRestartDialog,EntryLoading,EntryMessage,EntryWaitingRoom}from"./entry";export{determineEntryState,formatCountdown,getSecondsUntilStart}from"./entry";export{StudentContestRoomsPageContainer}from"./rooms";export{CreateExamPageContainer}from"./CreateExamPageContainer";export{CreateExamInfoForm}from"./CreateExamInfoForm";export{TemplateSelector}from"./TemplateSelector";export{ExamCreator}from"./ExamCreator";export{ExamPartTabs}from"./ExamPartTabs";export{ExamQuestionGrid}from"./ExamQuestionGrid";export{PartAudioUploader}from"./PartAudioUploader";export{createExamQuestionsApi,createExamQuestionsFetchApi,createMockExamQuestionsApi}from"./api";export{ExamQuestionsPageContainer}from"./ExamQuestionsPageContainer";export{UnsavedChangesDialog}from"./UnsavedChangesDialog";export{CompletionDialog}from"./CompletionDialog";export{EXAM_DIFFICULTY,ExamViewDialog}from"./ExamViewDialog";export{ExamPreviewDialog}from"./ExamPreviewDialog";export{QuestionStatus,clearQuestionStatuses,getQuestionStatus,initializeQuestionStatusesFromAPI,setQuestionStatus}from"./exam-question-status";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ContestRoomsSdkApi } from '../../../api/contest-rooms.types';
|
|
2
|
+
export interface StudentContestRoomsPageContainerProps {
|
|
3
|
+
/** Contest id from the route (`/student/contests/:contestId/rooms`). */
|
|
4
|
+
contestId: string;
|
|
5
|
+
/** API adapter; create one via `createContestRoomsApi`. */
|
|
6
|
+
api: ContestRoomsSdkApi;
|
|
7
|
+
/** Navigation callback; falls back to `window.location.href` when omitted. */
|
|
8
|
+
onNavigate?: (href: string) => void;
|
|
9
|
+
/** Build the exam-entry path from a roomId. */
|
|
10
|
+
enterPath?: (roomId: string) => string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Renders the student contest rooms-list screen
|
|
14
|
+
* (`/student/contests/:contestId/rooms`). Fetches rooms + contest detail via
|
|
15
|
+
* the injected `api`, handles search/filter, room registration and
|
|
16
|
+
* cancellation, and navigates to the exam-entry screen on room selection.
|
|
17
|
+
*/
|
|
18
|
+
export declare function StudentContestRoomsPageContainer({ contestId, api, onNavigate, enterPath, }: StudentContestRoomsPageContainerProps): import("react").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as t,Fragment as a}from"react/jsx-runtime";import{useEffect as r,useMemo as s,useState as l}from"react";import{Building2 as n,CheckCircle2 as i,ClipboardCheck as d,Clock as o,DoorOpen as c,Globe as m,Loader2 as h,Lock as x,PlayCircle as g,Search as b,Timer as f,Users as p,XCircle as u}from"lucide-react";import{Badge as N}from"../../../components/ui/badge";import{Button as y}from"../../../components/ui/button";import{Input as w}from"../../../components/ui/input";import{Skeleton as v}from"../../../components/ui/skeleton";import{useConfirm as k}from"../../../components/ui/confirm-dialog";import{canCancelRegistration as C,canEnterRoom as D,canRetakeRoom as S,getCountdownParts as E,getRoomSortPriority as R,hasRegistrationStatus as P,isUserEngaged as T,needsRegisterAndEnter as j,needsRegistration as A,unwrap as I}from"./contest-rooms.utils";function L({targetDate:s}){const[n,i]=l(()=>E(s));return r(()=>{const e=setInterval(()=>i(E(s)),1e3);return()=>clearInterval(e)},[s]),n?t("div",{className:"flex items-center gap-1.5",children:[n.days>0&&t(a,{children:[t("div",{className:"flex min-w-[36px] flex-col items-center rounded-md bg-white/80 px-1.5 py-1 shadow-sm",children:[e("span",{className:"text-sm font-bold leading-none text-[#07aff0]",children:n.days}),e("span",{className:"text-[9px] text-gray-400",children:"ngày"})]}),e("span",{className:"text-sm font-bold text-[#07aff0]/40",children:":"})]}),t("div",{className:"flex min-w-[36px] flex-col items-center rounded-md bg-white/80 px-1.5 py-1 shadow-sm",children:[e("span",{className:"text-sm font-bold leading-none text-[#07aff0]",children:String(n.hours).padStart(2,"0")}),e("span",{className:"text-[9px] text-gray-400",children:"giờ"})]}),e("span",{className:"text-sm font-bold text-[#07aff0]/40",children:":"}),t("div",{className:"flex min-w-[36px] flex-col items-center rounded-md bg-white/80 px-1.5 py-1 shadow-sm",children:[e("span",{className:"text-sm font-bold leading-none text-[#07aff0]",children:String(n.minutes).padStart(2,"0")}),e("span",{className:"text-[9px] text-gray-400",children:"phút"})]}),e("span",{className:"text-sm font-bold text-[#07aff0]/40",children:":"}),t("div",{className:"flex min-w-[36px] flex-col items-center rounded-md bg-white/80 px-1.5 py-1 shadow-sm",children:[e("span",{className:"text-sm font-bold leading-none text-[#07aff0]",children:String(n.seconds).padStart(2,"0")}),e("span",{className:"text-[9px] text-gray-400",children:"giây"})]})]}):null}function O({room:a,contest:r}){const s=function(e,t){const a=S(e,t);return e.isCompleted&&!a?{label:"Đã hoàn thành",icon:i,className:"border-emerald-200 bg-emerald-50 text-emerald-700"}:e.hasAttempt&&"COMPLETED"===e.status?{label:"Đã thi",icon:i,className:"border-emerald-200 bg-emerald-50 text-emerald-700"}:e.hasAttempt&&"IN_PROGRESS"===e.attemptStatus?{label:"Đang thi",icon:g,className:"border-blue-200 bg-blue-50 text-blue-700"}:"internal"===e.visibility?"PENDING"===e.registrationStatus?{label:"Chờ phê duyệt",icon:o,className:"border-yellow-200 bg-yellow-50 text-yellow-700"}:"REJECTED"===e.registrationStatus?{label:"Bị từ chối",icon:u,className:"border-red-200 bg-red-50 text-red-700"}:"APPROVED"===e.registrationStatus?{label:"Đã đăng ký",icon:i,className:"border-teal-200 bg-teal-50 text-teal-700"}:{label:"Chưa đăng ký",icon:d,className:"border-gray-200 bg-gray-50 text-gray-500"}:e.hasAttempt&&!a?{label:"Đã thi",icon:i,className:"border-emerald-200 bg-emerald-50 text-emerald-700"}:e.hasAttempt&&a?{label:"Có thể thi lại",icon:c,className:"border-sky-200 bg-sky-50 text-sky-700"}:{label:"Sẵn sàng",icon:c,className:"border-sky-200 bg-sky-50 text-sky-700"}}(a,r),l=s.icon;return t(N,{variant:"outline",className:`rounded-full border-2 px-3 py-1 text-xs font-extrabold uppercase tracking-wide ${s.className}`,children:[e(l,{className:"mr-1 h-3.5 w-3.5"}),s.label]})}export function StudentContestRoomsPageContainer({contestId:g,api:N,onNavigate:E,enterPath:z=e=>`/student/exams/${e}/enter`}){const[G,M]=l(null),[V,B]=l(),[H,J]=l(!0),[$,_]=l(""),[F,K]=l("all"),[Q,U]=l(null),{confirm:X,ConfirmDialog:q}=k(),W=e=>E?E(e):window.location.href=e,Y=async()=>{J(!0);try{const[e,t]=await Promise.all([N.getContestRooms(g),N.getContestDetail(g)]);M(I(e)),B(I(t))}finally{J(!1)}};r(()=>{Y()},[g]);const Z=s(()=>{if(!G||0===G.length)return[];let e=[...G];if($.trim()){const t=$.trim().toLowerCase();e=e.filter(e=>e.name.toLowerCase().includes(t))}return"registered"===F&&(e=e.filter(e=>"APPROVED"===e.registrationStatus||"PENDING"===e.registrationStatus||e.hasAttempt)),e.sort((e,t)=>R(e)-R(t))},[G,$,F]);return H?e("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3",children:[1,2,3,4,5,6].map(a=>t("div",{className:"overflow-hidden rounded-xl border bg-white shadow-sm",children:[e(v,{className:"h-2 w-full"}),t("div",{className:"space-y-3 p-4",children:[e(v,{className:"h-5 w-3/4"}),e(v,{className:"h-4 w-1/2"}),e(v,{className:"h-4 w-2/3"}),t("div",{className:"flex gap-2 pt-2",children:[e(v,{className:"h-8 w-20"}),e(v,{className:"h-8 w-20"})]})]})]},a))}):G&&0!==G.length?t(a,{children:[t("div",{className:"mb-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",children:[t("div",{className:"relative w-full sm:max-w-xs",children:[e(b,{className:"absolute left-3.5 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400"}),e(w,{type:"text",placeholder:"Tìm kiếm phòng thi...",value:$,onChange:e=>_(e.target.value),className:"h-11 rounded-2xl border-2 border-gray-200 pl-10 text-sm font-semibold focus-visible:border-[#07aff0]/40 focus-visible:ring-0"})]}),t("div",{className:"flex items-center gap-1.5 rounded-2xl border-2 border-gray-100 bg-gray-50 p-1.5",children:[e("button",{type:"button",onClick:()=>K("all"),className:"rounded-xl px-4 py-2 text-xs font-extrabold uppercase tracking-wide transition-all "+("all"===F?"border-2 border-b-4 border-[#07aff0]/30 bg-white text-[#07aff0]":"border-2 border-transparent text-gray-400 hover:text-[#07aff0]"),children:"Tất cả"}),e("button",{type:"button",onClick:()=>K("registered"),className:"rounded-xl px-4 py-2 text-xs font-extrabold uppercase tracking-wide transition-all "+("registered"===F?"border-2 border-b-4 border-[#07aff0]/30 bg-white text-[#07aff0]":"border-2 border-transparent text-gray-400 hover:text-[#07aff0]"),children:"Đã đăng ký"})]})]}),0===Z.length&&t("div",{className:"flex flex-col items-center justify-center rounded-2xl border-2 border-dashed border-gray-200 bg-gradient-to-br from-gray-50 to-white py-12",children:[e("div",{className:"flex h-16 w-16 items-center justify-center rounded-full bg-gray-100",children:e(b,{className:"h-8 w-8 text-gray-300"})}),e("p",{className:"mt-3 text-base font-medium text-gray-400",children:"Không tìm thấy phòng thi phù hợp"}),e("p",{className:"mt-1 text-sm text-gray-400",children:"Thử thay đổi từ khóa tìm kiếm hoặc bộ lọc"})]}),e("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3",children:Z.map(r=>{!function(e){if(e.isLocked)return{label:"Đã khóa",className:"border-red-200 bg-red-50 text-red-700",icon:x,canEnter:!1};switch(e.status){case"IN_PROGRESS":return{label:"Đang mở",className:"border-green-200 bg-green-50 text-green-700",icon:c,canEnter:!0};case"COMPLETED":return{label:"Đã kết thúc",className:"border-gray-200 bg-gray-50 text-gray-700",icon:o,canEnter:!1};default:;}}(r);const s=S(r,V),l=!(r.isLocked||"UPCOMING"!==r.status&&r.status),b=D(r,V),w=A(r),v=P(r),k=T(r),E=Q===r.id;return e("div",{className:"group relative flex flex-col overflow-hidden rounded-3xl border-2 border-b-[6px] bg-white shadow-sm transition-all duration-150 hover:-translate-y-0.5 "+(k?"border-[#07aff0]/30":"border-gray-200"),children:t("div",{className:"flex flex-1 flex-col p-5",children:[t("div",{className:"mb-3 flex items-start justify-between gap-3",children:[t("div",{className:"min-w-0 flex-1",children:[t("h3",{className:"flex items-center gap-2 truncate text-lg font-extrabold tracking-tight text-gray-800 group-hover:text-[#07aff0]",children:[(!r.visibility||"public"===r.visibility)&&e("span",{className:"flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-xl bg-emerald-100",children:e(m,{className:"h-4 w-4 text-emerald-500"})}),"internal"===r.visibility&&e("span",{className:"flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-xl bg-amber-100",children:e(n,{className:"h-4 w-4 text-amber-500"})}),"private"===r.visibility&&e("span",{className:"flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-xl bg-gray-100",children:e(x,{className:"h-4 w-4 text-gray-400"})}),e("span",{className:"truncate",children:r.name})]}),t("p",{className:"mt-1 text-xs font-medium text-gray-400",children:["Mã: ",e("span",{className:"font-mono font-bold text-gray-500",children:r.code})]})]}),t("div",{className:"flex flex-shrink-0 items-start gap-2",children:[null!=r.registrationCount&&t("div",{className:"flex items-center gap-1 rounded-full bg-gray-100 px-2.5 py-1 text-gray-500",children:[e(p,{className:"h-3.5 w-3.5"}),e("span",{className:"text-xs font-bold",children:r.registrationCount})]}),r.startDatetime&&e("div",{className:"flex flex-col items-center overflow-hidden rounded-2xl border-2 border-gray-200 bg-white",children:t("div",{className:"flex flex-col items-center px-3 py-1.5",children:[e("span",{className:"text-xl font-extrabold leading-tight text-gray-800",children:new Date(r.startDatetime).getDate()}),t("span",{className:"text-[10px] font-bold uppercase text-gray-400",children:["Th ",new Date(r.startDatetime).getMonth()+1]})]})})]})]}),t("div",{className:"mb-3 space-y-2",children:[t("div",{className:"flex items-center gap-2 text-xs font-semibold text-gray-500",children:[e(d,{className:"h-4 w-4 flex-shrink-0 text-gray-400"}),e("span",{className:"truncate",children:r.examName})]}),r.startDatetime&&t("div",{className:"flex items-center gap-2 text-xs font-semibold text-gray-500",children:[e(o,{className:"h-4 w-4 flex-shrink-0 text-gray-400"}),t("span",{children:[new Date(r.startDatetime).toLocaleTimeString("vi-VN",{hour:"2-digit",minute:"2-digit"}),r.endDatetime&&t(a,{children:[" - ",new Date(r.endDatetime).toLocaleTimeString("vi-VN",{hour:"2-digit",minute:"2-digit"})]})]})]})]}),e("div",{className:"mb-3 flex flex-wrap items-center gap-1.5",children:e(O,{room:r,contest:V})}),!b&&!w&&!v&&l&&r.startDatetime&&t("div",{className:"mb-3 flex items-center gap-2 rounded-2xl border-2 border-[#07aff0]/15 bg-[#07aff0]/5 px-3 py-2",children:[e(f,{className:"h-4 w-4 flex-shrink-0 text-[#07aff0]"}),e("span",{className:"text-xs font-bold text-[#07aff0]",children:"Mở sau"}),e("div",{className:"ml-auto",children:e(L,{targetDate:r.startDatetime})})]}),e("div",{className:"mt-auto pt-3"}),t("div",{className:"flex flex-col gap-2",children:[t("div",{className:"flex flex-wrap items-center gap-2",children:[r.isCompleted&&!s&&t(y,{size:"sm",className:"h-11 flex-1 cursor-default rounded-2xl border-2 border-emerald-200 bg-emerald-50 text-sm font-extrabold uppercase tracking-wide text-emerald-600 hover:bg-emerald-50",disabled:!0,children:[e(i,{className:"mr-2 h-4 w-4"}),"Đã hoàn thành"]}),j(r,V)&&t(y,{size:"sm",className:"h-11 flex-1 rounded-2xl border-b-4 border-[#003d87] bg-[#07aff0] text-sm font-extrabold uppercase tracking-wide text-white shadow-none transition-all hover:bg-[#0060d0] active:translate-y-0.5 active:border-b-2",onClick:()=>(async e=>{U(e);try{await N.registerRoom(g,e),W(z(e))}finally{U(null)}})(r.id),disabled:E,children:[E?e(h,{className:"mr-2 h-4 w-4 animate-spin"}):e(c,{className:"mr-2 h-4 w-4"}),r.hasAttempt?"Đăng kí và Thi lại":"Vào phòng thi"]}),b&&!j(r,V)&&t("div",{className:"flex-1 flex flex-col gap-1.5",children:[r.hasAttempt&&e("div",{className:"rounded-xl border-2 border-amber-200/60 bg-amber-50 px-2 py-1 text-center text-xs font-bold text-amber-600",children:"Bạn đã hoàn thành bài thi"}),t(y,{size:"sm",className:"h-11 w-full rounded-2xl border-0 border-b-4 border-[#05a0db] bg-[#07aff0] text-sm font-extrabold uppercase tracking-wide text-white shadow-none transition-all hover:bg-[#06a0e0] active:translate-y-0.5 active:border-b-2",onClick:()=>W(z(r.id)),children:[e(c,{className:"mr-2 h-4 w-4"}),r.hasAttempt?"Thi lại":"Vào phòng thi"]})]}),w&&t(y,{size:"sm",className:"h-11 flex-1 rounded-2xl border-2 border-b-4 border-[#07aff0]/30 bg-white text-sm font-extrabold uppercase tracking-wide text-[#07aff0] shadow-none transition-all hover:bg-[#07aff0]/5 active:translate-y-0.5 active:border-b-2",onClick:()=>(async e=>{U(e);try{await N.registerRoom(g,e),await Y()}finally{U(null)}})(r.id),disabled:E,children:[E?e(h,{className:"mr-2 h-4 w-4 animate-spin"}):e(d,{className:"mr-2 h-4 w-4"}),"Đăng ký"]}),v&&"PENDING"===r.registrationStatus&&t(y,{size:"sm",className:"h-11 flex-1 cursor-default rounded-2xl border-2 border-yellow-200 bg-yellow-50 text-sm font-extrabold uppercase tracking-wide text-yellow-600 hover:bg-yellow-50",disabled:!0,children:[e(o,{className:"mr-2 h-4 w-4"}),"Đã gửi đăng ký"]}),v&&"REJECTED"===r.registrationStatus&&t(y,{size:"sm",className:"h-11 flex-1 cursor-default rounded-2xl border-2 border-red-200 bg-red-50 text-sm font-extrabold uppercase tracking-wide text-red-600 hover:bg-red-50",disabled:!0,children:[e(u,{className:"mr-2 h-4 w-4"}),"Bị từ chối"]})]}),C(r)&&e("button",{type:"button",className:"self-center text-[11px] font-semibold text-gray-400 underline-offset-2 hover:text-red-500 hover:underline transition-colors disabled:opacity-50",onClick:()=>(async e=>{if(await X({title:"Xác nhận hủy đăng ký",description:"Bạn có chắc chắn muốn hủy đăng ký phòng thi này không? Hành động này không thể hoàn tác.",confirmText:"Hủy đăng ký",cancelText:"Quay lại",variant:"destructive"})&&N.cancelRoomRegistration){U(e);try{await N.cancelRoomRegistration(g,e),await Y()}finally{U(null)}}})(r.id),disabled:E,children:E?"Đang hủy...":"Hủy đăng ký"})]})]})},r.id)})}),e(q,{})]}):t("div",{className:"flex flex-col items-center justify-center rounded-2xl border-2 border-dashed border-gray-200 bg-gradient-to-br from-gray-50 to-white py-16",children:[e("div",{className:"flex h-20 w-20 items-center justify-center rounded-full bg-gray-100",children:e(c,{className:"h-10 w-10 text-gray-300"})}),e("p",{className:"mt-4 text-lg font-medium text-gray-400",children:"Chưa có phòng thi nào trong kỳ thi này"})]})}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ApiData } from '../../../api/exam-entry.types';
|
|
2
|
+
import type { ContestRoomListItem, ContestRoomsContestDetail } from '../../../api/contest-rooms.types';
|
|
3
|
+
export declare function unwrap<T>(value: ApiData<T> | T): T;
|
|
4
|
+
/** Whether a student can retake a room (room override, falling back to contest default). */
|
|
5
|
+
export declare function canRetakeRoom(room: ContestRoomListItem, contest?: ContestRoomsContestDetail): boolean;
|
|
6
|
+
/** Whether the student can enter the room right now (status + registration gating). */
|
|
7
|
+
export declare function canEnterRoom(room: ContestRoomListItem, contest?: ContestRoomsContestDetail): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Public/private rooms need no student-initiated registration — the student
|
|
10
|
+
* enters directly (the backend auto-approves participation on first attempt).
|
|
11
|
+
* Registration is an internal-room concept only, so this is always false and
|
|
12
|
+
* public/private rooms fall through to the plain "enter" button. Kept as a
|
|
13
|
+
* named helper so the container's button logic reads intently.
|
|
14
|
+
*/
|
|
15
|
+
export declare function needsRegisterAndEnter(_room: ContestRoomListItem, _contest?: ContestRoomsContestDetail): boolean;
|
|
16
|
+
/** Internal room the student hasn't requested registration for yet. */
|
|
17
|
+
export declare function needsRegistration(room: ContestRoomListItem): boolean;
|
|
18
|
+
/** Internal room registration is pending/rejected (i.e. not approved yet). */
|
|
19
|
+
export declare function hasRegistrationStatus(room: ContestRoomListItem): boolean;
|
|
20
|
+
/** Whether a "cancel registration" action should be offered. */
|
|
21
|
+
export declare function canCancelRegistration(room: ContestRoomListItem): boolean;
|
|
22
|
+
/** Whether the student has any meaningful engagement with this room. */
|
|
23
|
+
export declare function isUserEngaged(room: ContestRoomListItem): boolean;
|
|
24
|
+
/** Sort priority for a room; lower = shown first. */
|
|
25
|
+
export declare function getRoomSortPriority(room: ContestRoomListItem): number;
|
|
26
|
+
/** Human-friendly seconds-remaining breakdown for a room's start countdown. */
|
|
27
|
+
export declare function getCountdownParts(targetIso: string): {
|
|
28
|
+
days: number;
|
|
29
|
+
hours: number;
|
|
30
|
+
minutes: number;
|
|
31
|
+
seconds: number;
|
|
32
|
+
} | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function unwrap(t){return function(t){return"object"==typeof t&&null!==t&&"data"in t}(t)?t.data:t}export function canRetakeRoom(t,i){return!0===t.allowMultipleSubmissions||!1!==t.allowMultipleSubmissions&&!0===i?.allowMultipleSubmissions}export function canEnterRoom(t,i){const e=canRetakeRoom(t,i);return!(t.isCompleted&&!e)&&(!t.isLocked&&"IN_PROGRESS"===t.status&&("internal"!==t.visibility||"APPROVED"===t.registrationStatus))}export function needsRegisterAndEnter(t,i){return!1}export function needsRegistration(t){return"internal"===t.visibility&&!t.registrationStatus}export function hasRegistrationStatus(t){return"internal"===t.visibility&&!!t.registrationStatus&&"APPROVED"!==t.registrationStatus}export function canCancelRegistration(t){return!t.hasAttempt&&!t.isCompleted&&("PENDING"===t.registrationStatus||"APPROVED"===t.registrationStatus)}export function isUserEngaged(t){return!(!t.isCompleted&&!t.hasAttempt)||("APPROVED"===t.registrationStatus||"PENDING"===t.registrationStatus)}export function getRoomSortPriority(t){return t.hasAttempt&&"IN_PROGRESS"===t.attemptStatus?0:"IN_PROGRESS"!==t.status||t.isLocked||t.isCompleted||"internal"===t.visibility&&"APPROVED"!==t.registrationStatus?("internal"!==t.visibility||"APPROVED"!==t.registrationStatus||t.isCompleted)&&("internal"===t.visibility||t.hasAttempt||"UPCOMING"!==t.status)?"internal"===t.visibility&&"PENDING"===t.registrationStatus?3:t.isCompleted||t.hasAttempt?4:"internal"!==t.visibility||t.registrationStatus?"internal"===t.visibility&&"REJECTED"===t.registrationStatus?6:"COMPLETED"===t.status||t.isLocked?7:8:5:2:1}export function getCountdownParts(t){const i=new Date(t).getTime()-Date.now();return i<=0?null:{days:Math.floor(i/864e5),hours:Math.floor(i%864e5/36e5),minutes:Math.floor(i%36e5/6e4),seconds:Math.floor(i%6e4/1e3)}}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { StudentContestRoomsPageContainer } from './StudentContestRoomsPageContainer';
|
|
2
|
+
export type { StudentContestRoomsPageContainerProps } from './StudentContestRoomsPageContainer';
|
|
3
|
+
export { canCancelRegistration, canEnterRoom, canRetakeRoom, getCountdownParts, getRoomSortPriority, hasRegistrationStatus, isUserEngaged, needsRegisterAndEnter, needsRegistration, unwrap, } from './contest-rooms.utils';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{StudentContestRoomsPageContainer}from"./StudentContestRoomsPageContainer";export{canCancelRegistration,canEnterRoom,canRetakeRoom,getCountdownParts,getRoomSortPriority,hasRegistrationStatus,isUserEngaged,needsRegisterAndEnter,needsRegistration,unwrap}from"./contest-rooms.utils";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { ExamTakingSdkApi } from '../../../api/exam-taking';
|
|
3
|
+
export declare function ExamTakingApiProvider({ api, children }: {
|
|
4
|
+
api: ExamTakingSdkApi;
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
}): import("react").JSX.Element;
|
|
7
|
+
/** Returns the injected API, or `null` when rendered outside a provider. */
|
|
8
|
+
export declare function useExamTakingApiOptional(): ExamTakingSdkApi | null;
|
|
9
|
+
/** Returns the injected API; throws when rendered outside a provider. */
|
|
10
|
+
export declare function useExamTakingApi(): ExamTakingSdkApi;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as r}from"react/jsx-runtime";import{createContext as i,useContext as n}from"react";const e=i(null);export function ExamTakingApiProvider({api:i,children:n}){return r(e.Provider,{value:i,children:n})}export function useExamTakingApiOptional(){return n(e)}export function useExamTakingApi(){const r=n(e);if(!r)throw new Error("useExamTakingApi must be used within an <ExamTakingApiProvider>.");return r}
|
|
@@ -1,9 +1,33 @@
|
|
|
1
1
|
import type { ExamTakingSdkApi } from '../../../api/exam-taking';
|
|
2
2
|
export interface ExamTakingPageContainerProps {
|
|
3
|
-
|
|
3
|
+
/** Exam room id from the route (`/student/exams/:roomId/take`). */
|
|
4
|
+
roomId: string;
|
|
5
|
+
/** API adapter; create one via `createExamTakingApi`. */
|
|
4
6
|
api: ExamTakingSdkApi;
|
|
5
|
-
|
|
7
|
+
/** Navigation callback; falls back to `window.location.href` when omitted. */
|
|
6
8
|
onNavigate?: (href: string) => void;
|
|
7
|
-
|
|
9
|
+
/** Build the results page path from an attemptId. */
|
|
10
|
+
resultPath?: (attemptId: string) => string;
|
|
11
|
+
/** Path to navigate to when loading/close fails (e.g. discover page). */
|
|
12
|
+
fallbackPath?: string;
|
|
13
|
+
/** Enable periodic webcam proctoring snapshots (requires camera permission). */
|
|
14
|
+
proctoringEnabled?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Exam title that gates the AI-teacher intro video. The host app previously
|
|
17
|
+
* gated on `NEXT_PUBLIC_ACHIEVERS_EXAM_TITLE`; pass it here so the SDK does
|
|
18
|
+
* not read host env vars. The intro plays only when the loaded exam's title
|
|
19
|
+
* matches this value.
|
|
20
|
+
*/
|
|
21
|
+
achieversExamTitle?: string;
|
|
22
|
+
/** Called after a successful submit with the pending grading context. */
|
|
23
|
+
onSubmitted?: (result: {
|
|
24
|
+
attemptId: string;
|
|
25
|
+
pendingAnswerIds: string[];
|
|
26
|
+
}) => void;
|
|
8
27
|
}
|
|
9
|
-
|
|
28
|
+
/**
|
|
29
|
+
* SDK container for the student exam-taking screen. Wraps the orchestration in an
|
|
30
|
+
* {@link ExamTakingApiProvider} so descendants (e.g. the speaking recorder) can
|
|
31
|
+
* reach the injected API without prop-drilling.
|
|
32
|
+
*/
|
|
33
|
+
export declare function ExamTakingPageContainer(props: ExamTakingPageContainerProps): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useEffect as n,useMemo as i,useState as s}from"react";import{ArrowLeft as a,ArrowRight as r,Loader2 as o,Send as l}from"lucide-react";import{Button as u}from"../../../components/ui/button";import{CambridgeYleExamLayout as c,EnglishCertificationExamLayout as m,SummerSkyLayout as d}from"../../../components/themes";import{useToast as h}from"../../../shared/lib/hooks/useToast";import{GenericQuestionRenderer as p}from"./GenericQuestionRenderer";import{groupQuestions as x,unwrap as g,unwrapAttempt as f}from"./exam-taking.utils";export function ExamTakingPageContainer({examId:t,api:a,exitPath:r="/student/exams",onNavigate:o,onSubmitted:l}){const{error:u,success:p}=h(),[S,E]=s(null),[P,_]=s([]),[M,A]=s(null),[k,Q]=s(0),[T,G]=s({}),[L,j]=s(!0),[R,D]=s(!1);n(()=>{let e=!1;return j(!0),async function(e,t){const n=g(await e.getActiveAttempt(t));return n||f(g(await e.startAttempt(t)))}(a,t).then(async t=>{const n=g(await a.getQuestions(t.id));e||(E(t),A(n),_(x(n)))}).catch(e=>u({message:"Không tải được bài thi",description:e instanceof Error?e.message:void 0})).finally(()=>{e||j(!1)}),()=>{e=!0}},[a,t,u]);const F=P[k],U=i(()=>P.flatMap(e=>e.questions),[P]),K=i(()=>U.findIndex(e=>F?.questions[0]?.id===e.id),[F?.questions,U]),Y=i(()=>Object.values(T).filter(e=>""!==e&&null!=e).length,[T]),B=U.length,O=function(e){return"ENGLISH_CERTIFICATION"===e||"CAMBRIDGE_YLE"===e||"SUMMER_SKY"===e?e:"DEFAULT"}(M?.examTemplate?.theme),H=M?.examTemplate?.title??"Làm bài thi",$=function(e){if(!e)return 0;const t=new Date(e.startedAt).getTime()+6e4*e.durationMinutes;return Math.max(0,Math.floor((t-Date.now())/1e3))}(S),z=e=>{o?o(e):"undefined"!=typeof window&&(window.location.href=e)},J=async()=>{if(S){D(!0);try{await a.submitAttempt(S.id),p({message:"Đã nộp bài"}),l?.(S.id)}catch(e){u({message:"Không nộp được bài",description:e instanceof Error?e.message:void 0})}finally{D(!1)}}};if(L)return e(q,{});if(!S||!F)return e(I,{onExit:()=>z(r)});const V=e(b,{part:F,answers:T,onAnswerChange:async(e,t)=>{G(n=>({...n,[e]:t})),S&&a.saveAnswers&&await a.saveAnswers({attemptId:S.id,answers:[{questionId:e,answer:t}]})}}),W=()=>Q(e=>Math.max(0,e-1)),X=()=>Q(e=>Math.min(P.length-1,e+1)),Z=0===k,ee=k>=P.length-1;return"ENGLISH_CERTIFICATION"===O?e(m,{headerProps:{examName:H,remainingSeconds:$,totalQuestions:B,answeredCount:Y,isSubmitting:R,onSubmit:J,onClose:()=>z(r),lastSavedAt:null,isSaving:!1,partLabel:F.name,questionRange:N(F)},navigationProps:{parts:v(P),questions:(te=U,te.map(e=>({id:e.id,question_type:e.question_type,content:e.content??{},is_example:Boolean(e.is_example),total_points:String(e.total_points??0),part_id:e.part_id??"",part_no:e.part_no??0,question_number:e.question_number}))),answers:T,flaggedQuestions:new Set,currentIndex:Math.max(0,K),onQuestionClick:e=>Q(C(P,e)),onPartClick:Q},footerProps:{onPrevious:W,onNext:X,onClear:()=>{},onToggleMark:()=>{},isPreviousDisabled:Z,isNextDisabled:ee,isMarked:!1},children:V}):"CAMBRIDGE_YLE"===O?e(c,{onPrevious:W,onNext:X,onClose:()=>z(r),isFirstQuestion:Z,isLastQuestion:ee,headerProps:{examName:H,examType:"Exam",totalQuestions:B,answeredCount:Y,remainingSeconds:$,isSubmitting:R,onSubmit:J},sidebarProps:y(P,T,Math.max(0,K),Q),children:V}):"SUMMER_SKY"===O?e(d,{onExit:()=>z(r),partName:F.name,instruction:F.instructions??"",onPrev:W,onNext:X,canGoPrev:!Z,canGoNext:!ee,audioUrl:F.audioUrl??"",questionNumber:k+1,recorder:null,children:V}):e(w,{title:H,answeredCount:Y,totalQuestions:B,onExit:()=>z(r),onPrev:W,onNext:X,isFirst:Z,isLast:ee,currentPart:F,onSubmit:J,isSubmitting:R,children:V});var te}function b({part:t,answers:n,onAnswerChange:i}){return e("div",{className:"space-y-4",children:t.questions.map(t=>e(p,{question:t,value:n[t.id],onChange:i},t.id))})}function w({title:n,answeredCount:i,totalQuestions:s,onExit:c,onPrev:m,onNext:d,isFirst:h,isLast:p,currentPart:x,onSubmit:g,isSubmitting:f,children:b}){return t("div",{className:"min-h-screen bg-slate-50",children:[e("header",{className:"sticky top-0 z-10 border-b bg-white px-4 py-3 shadow-sm",children:t("div",{className:"mx-auto flex max-w-5xl items-center justify-between gap-4",children:[t("div",{children:[e("h1",{className:"font-semibold text-gray-900",children:n}),t("p",{className:"text-sm text-gray-500",children:["Đã trả lời ",i,"/",s]})]}),e(u,{variant:"outline",onClick:c,children:"Thoát"})]})}),t("main",{className:"mx-auto max-w-5xl space-y-4 p-4",children:[t("div",{className:"flex items-center justify-between rounded-lg bg-white p-4 shadow-sm",children:[t(u,{variant:"outline",disabled:h,onClick:m,children:[e(a,{className:"mr-2 h-4 w-4"}),"Phần trước"]}),e("div",{className:"text-center",children:e("h2",{className:"font-medium",children:x.name})}),t(u,{variant:"outline",disabled:p,onClick:d,children:["Phần sau",e(r,{className:"ml-2 h-4 w-4"})]})]}),b,e("div",{className:"flex justify-end",children:t(u,{onClick:g,disabled:f,className:"bg-blue-600 hover:bg-blue-700",children:[f?e(o,{className:"mr-2 h-4 w-4 animate-spin"}):e(l,{className:"mr-2 h-4 w-4"}),"Nộp bài"]})})]})]})}function N(e){const t=e.questions.map(e=>e.question_number).filter(e=>Number.isFinite(e));return 0===t.length?"":`${Math.min(...t)}–${Math.max(...t)}`}function v(e){let t=0;return e.map(e=>{const n=t;return t+=e.questions.length,{id:e.id,name:e.name,category:e.template?.category,startIndex:n,endIndex:t-1,questionCount:e.questions.length,audioUrl:e.audioUrl,isGroup:e.isGroup}})}function C(e,t){let n=0;for(let i=0;i<e.length;i+=1)if(n+=e[i].questions.length,t<n)return i;return 0}function y(e,t,n,i){const s=e.flatMap((n,i)=>n.questions.map((n,s)=>({globalIndex:e.slice(0,i).reduce((e,t)=>e+t.questions.length,0)+s,partIndex:i,questionNumber:n.question_number,isAnswered:void 0!==t[n.id]&&""!==t[n.id]})));return{parts:e.map((e,n)=>({partIndex:n,partNo:e.partNo??n+1,name:e.name,category:e.template?.category,totalQuestions:e.questions.length,answeredCount:e.questions.filter(e=>void 0!==t[e.id]&&""!==t[e.id]).length})),questions:s,currentQuestionGlobalIndex:n,onPartClick:i,onQuestionClick:t=>i(C(e,t))}}function q(){return e("div",{className:"flex h-screen items-center justify-center",children:e(o,{className:"h-8 w-8 animate-spin text-blue-600"})})}function I({onExit:n}){return t("div",{className:"flex h-screen flex-col items-center justify-center gap-4",children:[e("p",{children:"Không có câu hỏi."}),e(u,{onClick:n,children:"Quay lại"})]})}
|
|
1
|
+
"use client";import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import{useEffect as i,useRef as s,useState as r,useMemo as a,useCallback as o}from"react";import d from"next/image";import l from"../../../components/themes/summer-sky/assets/images/clock.png";import m from"../../../components/themes/summer-sky/assets/images/submit.png";import c from"../../../components/themes/summer-sky/assets/images/has_answered.png";import{toast as p}from"sonner";import{Loader2 as u}from"lucide-react";import{t as g}from"../../../shared/lib/i18n";import{transformAnswersForSubmission as h}from"./utils/answer-transformers";import{getThemeForLevel as x,normalizeExamTheme as b}from"../../../shared/lib/themes";import{useExamTakingStore as I}from"../../../shared/lib/stores/examTakingStore";import{useGradingTransientStore as f}from"../../../shared/lib/stores/gradingTransientStore";import{AlertDialog as w,AlertDialogAction as E,AlertDialogCancel as S,AlertDialogContent as y,AlertDialogDescription as _,AlertDialogFooter as v,AlertDialogHeader as N,AlertDialogTitle as A}from"../../../components/ui/alert-dialog";import{useExamTimer as T}from"./hooks/useExamTimer";import{useAutoSave as C}from"./hooks/useAutoSave";import{useProctoringCamera as k}from"./hooks/useProctoringCamera";import{getStandardExamTheme as P}from"../../../components/themes";import{QuestionRenderer as q}from"./components/QuestionRenderer";import{FullscreenLoading as R}from"../entry/fullscreen-loading";import{SummerSkySubmitModal as M}from"../../../components/themes/summer-sky/SummerSkySubmitModal";import{EnglishCertificationExamLayout as D,EnglishCertificationQuestionRenderer as L,englishCertQuestionDomId as G}from"../../../components/themes/english-certification";import{groupQuestionsByPart as Q}from"./utils/question-transformers";import{unwrap as B,unwrapAttempt as O}from"./exam-taking.utils";import{ExamTakingApiProvider as Y}from"./ExamTakingApiContext";function F({roomId:Y,api:F,onNavigate:K,resultPath:U=e=>`/student/results/${e}`,fallbackPath:V="/student/contests/discover",proctoringEnabled:$=!1,achieversExamTitle:H,onSubmitted:j}){const z=I(),W=s(!1),J=o(e=>{K?K(e):"undefined"!=typeof window&&(window.location.href=e)},[K]),{isCameraActive:X}=k({api:F,attemptId:z.attemptId,intervalMs:1e4,enabled:$}),[Z,ee]=r(!0),te=z.currentPartIndex,ne=z.currentQuestionGlobalIndex,ie=o(e=>{const t=I.getState().currentPartIndex,n="function"==typeof e?e(t):e;I.getState().setCurrentPartIndex(n)},[]),se=o(e=>{const t=I.getState().currentQuestionGlobalIndex,n="function"==typeof e?e(t):e;I.getState().setCurrentQuestionGlobalIndex(n)},[]),[re,ae]=r([]),[oe,de]=r("SUMMER_SKY"),[le,me]=r(""),[ce,pe]=r(!1),[ue,ge]=r(null),[he,xe]=r(""),be=o(e=>{I.getState().markIntroPlayed(e)},[]),Ie="TOEIC"===z.examType||"ENGLISH_CERTIFICATION"===le,fe=a(()=>{if(!Ie||0===z.parts.length)return te;const e=z.currentIndex;for(let t=0;t<z.parts.length;t++){const n=z.parts[t],i=n.startIndex??0,s=n.endIndex??i;if(e>=i&&e<=s)return t}return 0},[Ie,z.currentIndex,z.parts,te]);i(()=>{(async()=>{try{ee(!0);let e=B(await F.getActiveAttempt(Y));e||(e=O(B(await F.startAttempt(Y))));let t=null;try{t=F.getRoom?B(await F.getRoom(Y)):null,t&&ge(t)}catch{}const{examTemplate:n,questions:i}=B(await F.getQuestions(e.id));n?.title&&xe(n.title);const s=n?.parts??e.exam?.template?.parts,r=Q(i,s),a=n?.subTitle??null,o=(r.every(e=>e.questions.every(e=>"SPEAKING"===e.question_skill_type)),r.some(e=>"SPEAKING"===e.category||e.questions.every(e=>"SPEAKING"===e.question_skill_type)));ae(r);const d=n?.theme||e?.exam?.template?.theme||e?.exam?.theme||t?.exam?.template?.theme||t?.exam?.theme||"",l=b(d);if(o){const e=["SPACESHIP","SUMMER_SKY"].includes(d);de(e?d:"SUMMER_SKY")}const m=new Date(e.startedAt),c=60*e.durationMinutes*1e3,u=m.getTime()+c,h=Date.now();if(0===Math.max(0,u-h)){p.info(g("student.exam.take.timeExpired"));try{await F.submitAttempt(e.id)}catch{}return I.persist.clearStorage(),void J(U(e.id))}z.hydrateFromServer({attemptId:e.id,examRoomId:Y,questions:i.map(e=>({id:e.id,question_type:e.question_type,content:e.content,is_example:e.is_example,total_points:e.total_points,part_id:e.part_id,part_no:e.part_no,question_number:e.question_number})),durationMinutes:e.durationMinutes,startedAt:e.startedAt,examType:a??void 0,examTitle:n?.title??void 0,parts:s}),a&&z.setExamType(a),me(l),s&&z.setParts(s),ee(!1)}catch(e){console.error("Failed to load exam data:",e),p.error(g("student.exam.take.loadError")),J(V)}})()},[Y]);const we=a(()=>re.length>0&&re.every(e=>e.questions.every(e=>"SPEAKING"===e.question_skill_type)),[re]),Ee=a(()=>{const e=re[te];return!!e&&(("SPEAKING_DESCRIBE_IMAGE"!==e.questionType&&"SPONTANEOUS_QA"!==e.questionType&&"SPEAKING_CUE_CARD"!==e.questionType&&"READ_DISPLAYED_CONTENT"!==e.questionType||"CAMBRIDGE_YLE"!==le)&&("SPEAKING"===e.category||e.questions.every(e=>"SPEAKING"===e.question_skill_type)))},[re,te,le]),{remainingSeconds:Se,warningLevel:ye}=T({onTimeExpired:async()=>{p.info(g("student.exam.take.autoSubmit")),await Ae()},onWarningThreshold:we||Ie?void 0:()=>{p.warning(g("student.exam.take.timeWarning"))},warningThresholdSeconds:we||Ie?void 0:300,warningThresholds:Ie?[{seconds:900,level:"warning",callback:()=>p.warning("Còn 15 phút!",{duration:3e3})},{seconds:300,level:"critical",callback:()=>p.warning("Còn 5 phút! Hãy nộp bài ngay!",{duration:5e3})}]:we?[{seconds:300,level:"warning",callback:()=>p.warning("Còn 5 phút! Hãy hoàn thành bài thi.",{duration:5e3})},{seconds:120,level:"critical",callback:()=>p.warning("Còn 2 phút! Bài thi sẽ được tự động nộp.",{duration:5e3})}]:void 0}),_e=C({api:F,attemptId:z.attemptId||"",parts:re,intervalMs:Ie?15e3:3e4,onSaveError:e=>{console.error("Save error:",e)}}),ve=s(_e.saveNow),Ne=s(re);i(()=>{ve.current=_e.saveNow,Ne.current=re}),i(()=>{const e=()=>{const e=I.getState();if(!e.attemptId||!e.isDirty||e.isSubmitting)return;const t=h(e.answers,Ne.current);if(0!==t.length)try{F.saveAnswers?.({attemptId:e.attemptId,answers:t,keepalive:!0})}catch{}},t=()=>{"hidden"===document.visibilityState&&e()},n=()=>{const e=I.getState();e.isDirty&&!e.isSubmitting&&ve.current()};return document.addEventListener("visibilitychange",t),window.addEventListener("pagehide",e),window.addEventListener("online",n),()=>{document.removeEventListener("visibilitychange",t),window.removeEventListener("pagehide",e),window.removeEventListener("online",n)}},[]),i(()=>{we||ve.current()},[z.currentIndex,te,ne,we]);const Ae=async()=>{if(!W.current){W.current=!0,z.setIsSubmitting(!0),pe(!1);try{z.isDirty&&await _e.saveNow();const e=B(await F.submitAttempt(z.attemptId)),t=e?.pendingAnswerIds??[];z.attemptId&&(f.getState().setPending(z.attemptId,t),j?.({attemptId:z.attemptId,pendingAnswerIds:t})),0===t.length?p.success(g("student.exam.take.submitSuccess")):p.success(g("student.exam.take.submittedAIGradingInProgress")),I.persist.clearStorage(),J(U(z.attemptId))}catch(e){console.error("Failed to submit exam:",e);const t=e?.response?.data?.errorCode;if("ATTEMPT_ALREADY_SUBMITTED"===t)return I.persist.clearStorage(),void J(U(z.attemptId));p.warning(g("student.exam.take.submitError")),W.current=!1,z.setIsSubmitting(!1)}}},Te=o(()=>{pe(!0)},[]),Ce=s(new Map),ke=s([]),Pe=o((e,t)=>{z.setAnswer(e,t);const n=Ce.current.get(e)||e,i=ke.current.findIndex(e=>e.questionId===n);-1!==i&&se(e=>e!==i?i:e)},[]),qe=s("forward"),Re=e=>{if("CAMBRIDGE_YLE"!==le)return!1;const t=re[e];return"SPEAKING_DESCRIBE_IMAGE"===t?.questionType||"SPONTANEOUS_QA"===t?.questionType||"SPEAKING_CUE_CARD"===t?.questionType||"READ_DISPLAYED_CONTENT"===t?.questionType},Me=()=>{const e=()=>{window.scrollTo({top:0,behavior:"smooth"});const e=document.getElementById("exam-main-scroll-area");if(e){e.scrollTo({top:0,behavior:"smooth"});e.querySelectorAll(".overflow-y-auto").forEach(e=>{e.scrollTo({top:0,behavior:"smooth"})})}};requestAnimationFrame(e),setTimeout(e,100),setTimeout(e,250)},De=()=>{if("ENGLISH_CERTIFICATION"===le){const e=z.parts[fe+1];e&&z.goToQuestion(e.startIndex??0)}else if(Ie)z.goToQuestion(Math.min(z.currentIndex+1,z.questions.length-1));else if("CAMBRIDGE_YLE"===le&&Re(te)){const e=ne+1,t=Ve[e];t&&(t.partIndex!==te&&(qe.current="forward",ie(t.partIndex)),se(e))}else qe.current="forward",ie(e=>{const t=Math.min(e+1,re.length-1);if("CAMBRIDGE_YLE"===le){const e=Ve.find(e=>e.partIndex===t);e&&se(e.globalIndex)}return t});Me()},Le=()=>{if("ENGLISH_CERTIFICATION"===le){const e=z.parts[fe-1];e&&z.goToQuestion(e.startIndex??0)}else if(Ie)z.goToQuestion(Math.max(z.currentIndex-1,0));else if("CAMBRIDGE_YLE"===le&&Re(te)){const e=ne-1,t=Ve[e];t&&(t.partIndex!==te&&(qe.current="backward",ie(t.partIndex)),se(e))}else qe.current="backward",ie(e=>{const t=Math.max(e-1,0);if("CAMBRIDGE_YLE"===le){const e=Ve.find(e=>e.partIndex===t);e&&se(e.globalIndex)}return t});Me()},Ge=()=>{J(V)},Qe=a(()=>re.reduce((e,t)=>e+("CAMBRIDGE_YLE"===le?t.questions.length:t.questions.filter(e=>!e.is_example).length),0),[re,le]),Be=a(()=>{const e=new Map;return re.forEach(t=>{t.questions.forEach(n=>{if(n.is_example)return;const i=n.content;if("FILL_MISSING_WORDS_IN_GRID"===t.questionType&&i?.grid&&i.grid.forEach((t,i)=>{t.forEach((t,s)=>{e.set(`${i}-${s}`,n.id)})}),"LABEL_THE_PICTURE"===t.questionType&&i?.labels&&i.labels.forEach(t=>{t.id&&e.set(t.id,n.id)}),"READ_AND_COLOR_OBJECTS"===t.questionType){const t=i?.regions||i?.regionNodes;t?.forEach(t=>{t.id&&e.set(t.id,n.id)})}if("IMAGE_OBJECT_MATCHING"===t.questionType){const t=i?.regions||i?.regionNodes;t?.forEach(t=>{t.id&&e.set(t.id,n.id)})}if("LOOK_PICTURE_FILL_WORD_HINT"===t.questionType){const t=i?.word;if(t&&"string"==typeof t){const i=/\{(\d+)\}/g;let s;for(;null!==(s=i.exec(t));){const t=s[1];e.set(`${n.id}-blank-${t}`,n.id)}}}})}),e},[re]);i(()=>{Ce.current=Be},[Be]);const Oe=a(()=>{if(!z.answers)return new Set;const e=new Set(re.flatMap(e=>e.questions.filter(e=>!e.is_example).map(e=>e.id))),t=new Set;return Object.keys(z.answers).forEach(n=>{const i=z.answers[n];if(void 0===i||""===i)return;if(e.has(n))return void t.add(n);const s=Be.get(n);s&&e.has(s)&&t.add(s)}),t},[z.answers,re,Be]),Ye=Oe.size+("CAMBRIDGE_YLE"===le?re.reduce((e,t)=>e+t.questions.filter(e=>e.is_example).length,0):0),Fe=a(()=>ue?.exam?.name||ue?.name||(Ie?"TOEIC Listening and Reading Test":"Bài thi"),[ue,Ie]),Ke=a(()=>x(ue?.exam?.level).displayName,[ue?.exam?.level]),{sidebarParts:Ue,sidebarQuestions:Ve}=a(()=>{const e=[],t=[];let n=0;return re.forEach((i,s)=>{const r="CAMBRIDGE_YLE"===le?i.questions:i.questions.filter(e=>!e.is_example);let a=0;r.forEach(e=>{const r=!("CAMBRIDGE_YLE"!==le||!e.is_example)||Oe.has(e.id);r&&a++;const o=i.questions.findIndex(t=>t.id===e.id);t.push({globalIndex:n,partIndex:s,indexInPart:o,questionNumber:e.question_number,isAnswered:r,questionId:e.id,isExample:e.is_example}),n++}),e.push({partIndex:s,partNo:i.partNo,name:i.name,category:i.category,totalQuestions:"CAMBRIDGE_YLE"===le?i.questions.length:i.questions.filter(e=>!e.is_example).length,answeredCount:a})}),{sidebarParts:e,sidebarQuestions:t}},[re,Oe,le]);if(i(()=>{ke.current=Ve},[Ve]),Z)return e(R,{});const $e=te,He=re[$e];if(!He)return e("div",{className:"flex min-h-screen items-center justify-center",children:t("div",{className:"text-center",children:[e("p",{className:"text-lg font-semibold text-red-500",children:"Không tìm thấy câu hỏi"}),e("button",{type:"button",onClick:()=>J(V),className:"mt-4 rounded-lg bg-blue-500 px-4 py-2 text-white hover:bg-blue-600",children:"Quay lại"})]})});if(Ee)return t(n,{children:[e(q,{part:He,answers:z.answers||{},onAnswerChange:Pe,isReviewMode:!1,onExit:Ge,onPartComplete:$e<re.length-1?De:Te,onPartBack:$e>0?Le:void 0,speakingTheme:oe,initialQuestionIndex:"backward"===qe.current?He.questions.length-1:0,skipTeacherVideo:z.playedIntroParts.has($e)||he!==H,onTeacherIntroPlayed:()=>be($e)},`${He.partId}-${$e}`),"SUMMER_SKY"===oe?ce&&e(M,{onClose:()=>pe(!1),onSubmit:Ae,isSubmitting:z.isSubmitting}):e(w,{open:ce,onOpenChange:pe,children:t(y,{children:[t(N,{children:[e(A,{children:"Nộp bài thi"}),e(_,{children:"Bạn có chắc chắn muốn nộp bài không? Sau khi nộp, bạn sẽ không thể thay đổi câu trả lời."})]}),t(v,{children:[e(S,{disabled:z.isSubmitting,children:"Quay lại"}),e(E,{onClick:Ae,disabled:z.isSubmitting,children:z.isSubmitting?t(n,{children:[e(u,{className:"mr-2 h-4 w-4 animate-spin"}),"Đang nộp..."]}):"Nộp bài"})]})]})}),t("div",{className:"fixed top-8 right-6 z-[100] flex flex-col items-end gap-4 sm:gap-6 lg:top-10 lg:right-16",children:[t("div",{className:"flex items-center gap-4 sm:gap-6",children:[Se>0&&t("div",{className:"flex items-center w-[130px] sm:w-[170px] h-[40px] sm:h-[50px] rounded-[33.5px] backdrop-blur-[8px] transition-all duration-300 ease-in-out border-none shadow-[0_4px_20px_rgba(0,0,0,0.25)] "+("critical"===ye?"bg-[rgba(220,38,38,0.85)] shadow-[0_0_24px_rgba(220,38,38,0.5)] animate-pulse":"warning"===ye?"bg-[rgba(180,120,0,0.85)]":"bg-[#001590]"),children:[e(d,{src:l,alt:"clock",width:75,height:75,className:"w-[50px] h-[50px] sm:w-[75px] sm:h-[75px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none z-10"}),t("span",{className:"flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]",style:{fontFamily:"'SVN-Volte Rounded', 'Quicksand', sans-serif",textShadow:"0 2px 4px rgba(0, 0, 0, 0.2)"},children:[Math.floor(Se/60).toString().padStart(2,"0"),":",(Se%60).toString().padStart(2,"0")]})]}),t("div",{className:"flex items-center w-[130px] sm:w-[170px] h-[40px] sm:h-[50px] rounded-[33.5px] bg-[#FF9900] shadow-[0_4px_20px_rgba(0,0,0,0.25)] border-none shrink-0",title:"Số câu hỏi đã hoàn thành",children:[e(d,{src:c,alt:"Progress",width:75,height:75,className:"w-[50px] h-[50px] sm:w-[75px] sm:h-[75px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none z-10"}),t("span",{className:"flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]",style:{fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif',textShadow:"0 2px 4px rgba(0,0,0,0.2)"},children:[Ye,"/",Qe]})]})]}),t("button",{onClick:Te,disabled:z.isSubmitting,className:"group cursor-pointer flex items-center h-[40px] sm:h-[50px] w-[130px] sm:w-[170px] rounded-[33.5px] shadow-[0_4px_20px_rgba(0,0,0,0.25)] transition-all duration-300 hover:scale-105 active:scale-95 disabled:pointer-events-none disabled:opacity-60 border-none "+(z.isSubmitting?"bg-slate-400":"bg-[#16CA3B] hover:bg-[#15b736]"),children:[e(d,{src:m,alt:"Submit",width:75,height:75,className:"w-[50px] h-[50px] sm:w-[75px] sm:h-[75px] -ml-[5px] sm:-ml-[10px] -mt-[10px] sm:-mt-[15px] shrink-0 drop-shadow-[0_2px_6px_rgba(0,0,0,0.2)] pointer-events-none transition-transform duration-300 group-hover:scale-110 z-10"}),z.isSubmitting?e("div",{className:"flex-1 flex justify-center pr-[10px] sm:pr-[16px]",children:e(u,{className:"h-6 w-6 animate-spin text-white"})}):e("span",{className:"flex-1 text-center font-bold text-[18px] sm:text-[25px] leading-none tracking-[-0.03em] uppercase text-white pr-[10px] sm:pr-[16px]",style:{fontFamily:'"SVN-Volte Rounded", "Quicksand", sans-serif',textShadow:"0 2px 4px rgba(0,0,0,0.2)"},children:"Nộp bài"})]})]}),z.isSubmitting&&e("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm",children:t("div",{className:"rounded-xl bg-white p-8 text-center shadow-2xl",children:[e(u,{className:"mx-auto h-12 w-12 animate-spin text-green-500"}),e("p",{className:"mt-4 text-lg font-semibold text-gray-700",children:"Đang nộp bài..."}),e("p",{className:"mt-2 text-sm text-gray-500",children:"Vui lòng đợi trong giây lát"})]})})]});if(Ie){const i=re[fe],s=z.parts[fe],r=s?Math.max(0,z.currentIndex-(s.startIndex??0)):0,a=(s?.startIndex??0)+1,o=(s?.endIndex??a-1)+1,d={examName:Fe,remainingSeconds:z.remainingSeconds,totalQuestions:Qe,answeredCount:Ye,isSubmitting:z.isSubmitting,onSubmit:Ae,onClose:Ge,lastSavedAt:z.lastSavedAt,isSaving:_e.isSaving,partLabel:(s?.name||i?.name||"").toUpperCase()||void 0,partSubLabel:s?.category||void 0,questionRange:`${a}–${o}`},l=i?.questions?.[r],m="ENGLISH_CERTIFICATION"===le,c={onPrevious:Le,onClear:m?void 0:()=>{l&&Pe(l.id,{optionId:null})},onToggleMark:m?void 0:()=>{l&&z.toggleFlag(l.id)},onNext:De,isMarked:!!l&&z.flaggedQuestions.has(l.id),showSecondaryActions:!m,isPreviousDisabled:m?fe<=0:z.currentIndex<=0,isNextDisabled:m?fe>=z.parts.length-1:z.currentIndex>=z.questions.length-1},p={parts:z.parts,questions:z.questions,answers:z.answers,flaggedQuestions:z.flaggedQuestions,currentIndex:z.currentIndex,onQuestionClick:e=>{z.goToQuestion(e);const t=z.questions[e];t&&setTimeout(()=>{document.getElementById(G(t.id))?.scrollIntoView({behavior:"smooth",block:"start"})},80)},onPartClick:e=>{const t=z.parts[e];t&&(z.goToQuestion(t.startIndex??0),z.setCurrentPartIndex(e))}};if(i&&s)return t(n,{children:[e(D,{headerProps:d,navigationProps:p,footerProps:c,children:e(L,{part:i,partConfig:s,currentQuestionIndex:r,answers:z.answers,flaggedQuestions:z.flaggedQuestions,onAnswerChange:Pe,onToggleFlag:e=>z.toggleFlag(e),isReviewMode:!1,isAudioPlayed:z.playedListeningAudioParts.has(i.partId),onAudioFirstPlay:()=>z.markListeningAudioPlayed(i.partId)})}),z.isSubmitting&&e("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50",children:t("div",{className:"rounded-xl bg-white p-8 text-center shadow-2xl",children:[e(u,{className:"mx-auto h-12 w-12 animate-spin text-green-500"}),e("p",{className:"mt-4 text-lg font-semibold text-gray-700",children:"Đang nộp bài..."}),e("p",{className:"mt-2 text-sm text-gray-500",children:"Vui lòng đợi trong giây lát"})]})})]})}return t(n,{children:[(()=>{const{Layout:n,QuestionCard:i}=P(le),s={headerProps:{examName:Fe,examType:"EXAM",levelLabel:Ke,totalQuestions:Qe,answeredCount:Ye,remainingSeconds:z.remainingSeconds,isSubmitting:z.isSubmitting,isCameraActive:X,onSubmit:Te},onPrevious:Le,onNext:De,onClose:Ge,isNavDisabled:z.isNavDisabled,partName:He?.name||(He?.partNo?`PART ${He.partNo}`:void 0)};if("CAMBRIDGE_YLE"===le){const e=Re($e);s.isFirstQuestion=e?0===ne:0===$e,s.isLastQuestion=e?ne===Ve.length-1:$e===re.length-1,s.sidebarProps={parts:Ue,questions:Ve,currentQuestionGlobalIndex:ne,isNavDisabled:z.isNavDisabled,onPartClick:e=>{if(z.isNavDisabled)return;qe.current=e>$e?"forward":"backward",ie(e);const t=Ve.find(t=>t.partIndex===e);t&&se(t.globalIndex),Me()},onQuestionClick:e=>{if(z.isNavDisabled)return;const t=Ve[e];t&&t.partIndex!==$e&&(qe.current=t.partIndex>$e?"forward":"backward",ie(t.partIndex)),se(e),t&&setTimeout(()=>{const e=document.getElementById(`question-${t.questionId}`);e&&e.scrollIntoView({behavior:"smooth",block:"center"})},100)}}}else s.isFirstQuestion=0===$e,s.isLastQuestion=$e===re.length-1;const r="CAMBRIDGE_YLE"===le&&("SPEAKING_DESCRIBE_IMAGE"===He?.questionType||"SPONTANEOUS_QA"===He?.questionType||"SPEAKING_CUE_CARD"===He?.questionType||"READ_DISPLAYED_CONTENT"===He?.questionType),a=Ve[ne],o=r&&a?.partIndex===$e?a.indexInPart:void 0;return t(n,{...s,children:[e(i,{partName:He?.name||(He?.partNo?`PART ${He.partNo}`:void 0),children:e(q,{part:He,answers:z.answers||{},onAnswerChange:Pe,isReviewMode:!1,currentQuestionIndex:o,onExit:Ge,onPartComplete:$e<re.length-1?De:Te,onPartBack:$e>0?Le:void 0,speakingTheme:"CAMBRIDGE_YLE"===le?"CAMBRIDGE_YLE":oe,initialQuestionIndex:"backward"===qe.current?He?.questions.length-1:0,skipTeacherVideo:z.playedIntroParts.has($e)||he!==H,onTeacherIntroPlayed:()=>be($e)})}),z.isSubmitting&&e("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50",children:t("div",{className:"rounded-xl bg-white p-8 text-center shadow-2xl",children:[e(u,{className:"mx-auto h-12 w-12 animate-spin text-green-500"}),e("p",{className:"mt-4 text-lg font-semibold text-gray-700",children:"Đang nộp bài..."}),e("p",{className:"mt-2 text-sm text-gray-500",children:"Vui lòng đợi trong giây lát"})]})})]})})(),"CAMBRIDGE_YLE"===le?ce&&e(M,{onClose:()=>pe(!1),onSubmit:Ae,isSubmitting:z.isSubmitting}):e(w,{open:ce,onOpenChange:pe,children:t(y,{children:[t(N,{children:[e(A,{children:"Nộp bài thi"}),e(_,{children:"Bạn có chắc chắn muốn nộp bài không? Sau khi nộp, bạn sẽ không thể thay đổi câu trả lời."})]}),t(v,{children:[e(S,{disabled:z.isSubmitting,children:"Quay lại"}),e(E,{onClick:Ae,disabled:z.isSubmitting,children:z.isSubmitting?t(n,{children:[e(u,{className:"mr-2 h-4 w-4 animate-spin"}),"Đang nộp..."]}):"Nộp bài"})]})]})})]})}export function ExamTakingPageContainer(t){return e(Y,{api:t.api,children:e(F,{...t})})}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type QuestionPart } from '../utils/question-transformers';
|
|
2
|
+
interface QuestionRendererProps {
|
|
3
|
+
part: QuestionPart;
|
|
4
|
+
answers: Record<string, any>;
|
|
5
|
+
onAnswerChange: (questionId: string, value: any) => void;
|
|
6
|
+
isReviewMode?: boolean;
|
|
7
|
+
/** Override the exit/close action for speaking renderers. Defaults to router.back(). */
|
|
8
|
+
onExit?: () => void;
|
|
9
|
+
/** Called when the last question of this part is navigated past (speaking exams only). */
|
|
10
|
+
onPartComplete?: () => void;
|
|
11
|
+
/** Called when the first question of this part is navigated back from (speaking exams only). */
|
|
12
|
+
onPartBack?: () => void;
|
|
13
|
+
/** Speaking theme string. */
|
|
14
|
+
speakingTheme?: string;
|
|
15
|
+
/** Initial question index within the part (useful when navigating backward). */
|
|
16
|
+
initialQuestionIndex?: number;
|
|
17
|
+
/** Skip teacher intro video (already played for this part). */
|
|
18
|
+
skipTeacherVideo?: boolean;
|
|
19
|
+
/** Callback when teacher intro video finishes playing. */
|
|
20
|
+
onTeacherIntroPlayed?: () => void;
|
|
21
|
+
/** Index of the question to render within the part (for Cambridge YLE 1-by-1 navigation) */
|
|
22
|
+
currentQuestionIndex?: number;
|
|
23
|
+
}
|
|
24
|
+
export declare function QuestionRenderer({ part, answers, onAnswerChange, isReviewMode, onExit, onPartComplete, onPartBack, speakingTheme, initialQuestionIndex, skipTeacherVideo, onTeacherIntroPlayed, currentQuestionIndex, }: QuestionRendererProps): import("react").JSX.Element;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as n}from"react/jsx-runtime";import{MoversListenAndWriteRenderer as t,MoversChooseBestAnswerRenderer as s,MoversChooseAdjectiveRenderer as i,MoversWritingRenderer as r,MoversColoringRenderer as o,MoversPictureChooseRenderer as a,MoversPictureFillBlankChooseRenderer as u,MoversReadingPassageRenderer as c,MoversLabelThePictureRenderer as m,MoversFillWordHintRenderer as l,MoversGridFillRenderer as g,MoversTrueFalseRenderer as p,MoversAnswerTheQuestionRenderer as _,MoversWriteSentencesRenderer as N,MoversWordOrderingRenderer as E,MoversWordFillParagraphRenderer as d,MoversMatchByWritingAnswerRenderer as C,MoversWordFillStructuredFormRenderer as A}from"./question-renderers";import{SpeakingQuestionRenderer as I}from"./speaking/renderers";import{transformFillInBlank as w,transformWriteCorrectVerbForm as R,transformChooseCorrectAnswer as T,transformChooseCorrectAdjective as h,transformWriteShortLetter as S,transformColorObjects as O,transformPictureChoose as U,transformPictureFillBlankChoose as q,transformReadingPassage as M,transformLabelPicture as b,transformFillWordHint as L,transformGridFill as x,transformAnswerTheQuestion as v,transformTrueFalse as D,transformWordOrdering as f,transformWordFillParagraph as P,transformMatchByWritingAnswer as W,transformWriteSentences as G,transformWordFillStructuredForm as H}from"../utils/question-transformers";import{normalizeColoringAssignments as B}from"../utils/coloring-assignments";export function QuestionRenderer({part:K,answers:Q,onAnswerChange:F,isReviewMode:k=!1,onExit:j,onPartComplete:y,onPartBack:V,speakingTheme:J,initialQuestionIndex:Y,skipTeacherVideo:X,onTeacherIntroPlayed:z,currentQuestionIndex:Z}){const{partNo:$,questionType:ee,questions:ne}=K,te=ne.filter(e=>!e.is_example).length,se=e=>{if(void 0!==Z&&Z>=0){if(e.length>0&&"isExample"in e[0]){const n=e.filter(e=>e.isExample),t=e.filter(e=>!e.isExample);if(Z<t.length)return 0===Z&&n.length>0?[...n,t[Z]]:[t[Z]]}else if(Z<e.length)return[e[Z]]}return e};switch(ee){case"FILL_IN_BLANK":{const n=w(ne);return e(t,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,title:n.title,imageUrl:n.groupImageUrl||n.imageUrl,audioUrl:n.audioUrl||K.audioUrl,exampleText:n.exampleText,exampleHighlight:n.exampleHighlight,questions:se(n.questions),answers:Q,onAnswerChange:F,isReviewMode:k,showHints:n.showHints,groupContent:n.groupContent,groupTitle:n.groupTitle})}case"WRITE_CORRECT_VERB_FORM":{const n=R(ne);return e(t,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,title:n.title,questions:se(n.questions),answers:Q,onAnswerChange:F,isReviewMode:k})}case"CHOOSE_THE_CORRECT_ANSWER":{const n=T(ne);return e(s,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,imageUrl:n.groupImageUrl,groupTitle:n.groupTitle,groupContent:n.groupContent,articles:n.articles,audioUrl:n.audioUrl||K.audioUrl,example:n.example,questions:se(n.questions),answers:Q,onAnswerChange:F,isReviewMode:k})}case"CHOOSE_CORRECT_ADJECTIVE":{const n=h(ne);return e(i,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,questions:se(n.questions),answers:Q,onAnswerChange:F,isReviewMode:k})}case"WRITE_A_SHORT_LETTER":{const n=ne[0],t=S(n),s=Q[n.id]||"";return e(r,{partNumber:$,partName:K.name,instruction:K.instructions,prompt:t.prompt,requirements:t.requirements,minWords:t.minWords,maxWords:t.maxWords,answer:s,onAnswerChange:e=>F(n.id,e),isReviewMode:k,guideImages:t.guideImages})}case"READ_AND_COLOR_OBJECTS":{const n=O(ne),t=new Set(n.regions.map(e=>e.id)),s=Object.fromEntries(Object.entries(Q).filter(([e])=>t.has(e))),i=B(s,n.hintItems);return e(o,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,instructions:n.instructions,imageUrl:n.imageUrl,audioUrl:n.audioUrl||K.audioUrl,hintItems:n.hintItems,regions:n.regions,assignments:i,onAssignmentChange:(e,t)=>{if(t){const s=n.hintItems.find(e=>e.id===t);if(s&&s.color)return void F(e,s.color)}F(e,t)},isReviewMode:k})}case"LOOK_PICTURE_CHOOSE_CORRECT_ANSWER":{const n=U(ne);return e(a,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,subQuestions:n.subQuestions,answers:Q,onAnswerChange:F,isReviewMode:k})}case"LOOK_PICTURE_FILL_BLANK_CHOOSE_ANSWER":{const n=q(ne);return e(u,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,subQuestions:n.subQuestions,answers:Q,onAnswerChange:F,isReviewMode:k})}case"READ_PASSAGE_AND_ANSWER_QUESTIONS":{const n=M(ne);return e(c,{partNumber:$,partName:K.name,questionCount:n.questions.length,instruction:K.instructions||n.instruction,passageTitle:n.passageTitle,passage:n.passage,passageImageUrl:n.passageImageUrl,questions:se(n.questions),answers:Q,onAnswerChange:F,isReviewMode:k})}case"LABEL_THE_PICTURE":{const n=b(ne);return e(m,{partNumber:$,partName:K.name,questionCount:n.labels.length,instruction:K.instructions||n.instruction,imageUrl:n.imageUrl,wordBank:n.wordBank,labels:n.labels,answers:Q,onAnswerChange:F,isReviewMode:k})}case"LOOK_PICTURE_FILL_WORD_HINT":{const n=L(ne);return e(l,{partNumber:$,partName:K.name,questionCount:n.subQuestions.length,instruction:K.instructions||n.instruction,hintLetters:n.hintLetters,subQuestions:n.subQuestions,answers:Q,onAnswerChange:F,isReviewMode:k})}case"FILL_MISSING_WORDS_IN_GRID":{const n=x(ne);return e(g,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,grid:n.grid,rows:n.rows,columns:n.columns,cellAnswers:{},answers:Q,onAnswerChange:F,isReviewMode:k,disabledCells:n.disabledCells})}case"IMAGE_OBJECT_MATCHING":{const n=O(ne),t=new Set(n.regions.map(e=>e.id)),s=Object.fromEntries(Object.entries(Q).filter(([e])=>t.has(e))),i=B(s,n.hintItems);return e(o,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,instructions:n.instructions,imageUrl:n.imageUrl,audioUrl:n.audioUrl||K.audioUrl,hintItems:n.hintItems,regions:n.regions,assignments:i,onAssignmentChange:(e,t)=>{if(t){const s=n.hintItems.find(e=>e.id===t);if(s&&s.color)return void F(e,s.color)}F(e,t)},isReviewMode:k})}case"ANSWER_THE_QUESTION":{const n=v(ne);return e(_,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,imageUrl:n.imageUrl,audioUrl:K.audioUrl,title:n.title,groupContent:n.groupContent,questions:se(n.questions),answers:Q,onAnswerChange:F,isReviewMode:k})}case"TRUE_FALSE":{const n=D(ne);return e(p,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,imageUrl:n.imageUrl,groupContent:n.groupContent,questions:se(n.questions),answers:Q,onAnswerChange:F,isReviewMode:k})}case"WORD_ORDERING":{const n=f(ne);return e(E,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,questions:se(n.questions),answers:Q,onAnswerChange:F,isReviewMode:k})}case"WORD_FILL_PARAGRAPH":{const n=P(ne),t=n.wordBank.filter(e=>e.isExample).length,s=n.paragraph.match(/\{\d+\}/g),i=s?s.length:0,r=Math.max(1,i-t);let o=K.instructions||n.instruction;return o=o.replace(/\{FROM\}/gi,"1").replace(/\{TO\}/gi,String(r)),e(d,{partNumber:$,partName:K.name,questionCount:te,instruction:o,questionId:n.questionId,paragraph:n.paragraph,title:n.title,imageUrl:n.imageUrl,wordBank:n.wordBank,viewMode:n.viewMode,answers:Q,onAnswerChange:F,exampleAnswer:n.exampleAnswer,isReviewMode:k,emailFrom:n.emailFrom,emailTo:n.emailTo})}case"MATCH_BY_WRITING_ANSWER":{const n=W(ne);return e(C,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,audioUrl:K.audioUrl,options:n.options,questions:se(n.questions),answers:Q,onAnswerChange:F,isReviewMode:k,viewMode:n.viewMode,groupImageUrl:n.groupImageUrl})}case"WORD_FILL_STRUCTURED_FORM":{const n=H(ne);return e(A,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,audioUrl:n.audioUrl||K.audioUrl,groupTitle:n.groupTitle,groupContent:n.groupContent,groupImageUrl:n.groupImageUrl,questions:se(n.questions),answers:Q,onAnswerChange:F,isReviewMode:k})}case"WRITE_SENTENCES":{const n=G(ne);return e(N,{partNumber:$,partName:K.name,questionCount:te,instruction:K.instructions||n.instruction,imageUrl:n.imageUrl,title:n.title,groupContent:n.groupContent,questions:se(n.questions),answers:Q,onAnswerChange:F,isReviewMode:k})}case"LISTEN_AND_CHOOSE_OBJECTS_IN_SCENE":case"LISTEN_AND_CHOOSE_FROM_ANSWER_GROUP":case"LISTEN_AND_DRAG_OBJECTS_INTO_SCENE":case"LISTEN_AND_SPEAK_ANSWER":case"LISTEN_AND_SPEAK_COMPARE_IMAGES":case"LISTEN_AND_SPEAK_WITH_STORY_IMAGES":case"LISTEN_AND_SPEAK_IMAGE_GROUP":case"LISTEN_AND_SPEAK_ODD_ONE_OUT":case"LISTEN_AND_SPEAK_QUESTION_LIST":case"LISTEN_AND_SPEAK_INFO_EXCHANGE":case"SPEAKING_DESCRIBE_IMAGE":case"READ_DISPLAYED_CONTENT":case"SPONTANEOUS_QA":case"SPEAKING_CONVERSATION":case"GN_SPEAKING_INTERVIEW":case"SPEAKING_CUE_CARD":return e(I,{part:K,answers:Q,onAnswerChange:F,isReviewMode:k,onExit:j,onPartComplete:y,onPartBack:V,speakingTheme:J,initialQuestionIndex:Y,skipTeacherVideo:X,onTeacherIntroPlayed:z,currentQuestionIndex:Z});default:return e("div",{className:"flex h-full items-center justify-center",children:n("div",{className:"text-center",children:[e("p",{className:"text-lg font-semibold text-red-500",children:"Unsupported question type"}),e("p",{className:"mt-2 text-gray-500",children:ee})]})})}}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { CambridgeYleExamLayout as MoversExamLayout } from '../../../../components/themes/cambridge-yle/CambridgeYleExamLayout';
|
|
2
|
+
export { CambridgeYleHeader as MoversHeader } from '../../../../components/themes/cambridge-yle/CambridgeYleHeader';
|
|
3
|
+
export { CambridgeYleNavButton as MoversNavButton } from '../../../../components/themes/cambridge-yle/CambridgeYleNavButton';
|
|
4
|
+
export { CambridgeYleProgressBar as MoversProgressBar } from '../../../../components/themes/cambridge-yle/CambridgeYleProgressBar';
|
|
5
|
+
export { CambridgeYleTimer as MoversTimer } from '../../../../components/themes/cambridge-yle/CambridgeYleTimer';
|
|
6
|
+
export { default as MoversQuestionCard } from '../../../../components/themes/cambridge-yle/CambridgeYleQuestionCard';
|
|
7
|
+
export { default as MoversPartBanner } from '../../../../components/themes/cambridge-yle/CambridgeYlePartBanner';
|
|
8
|
+
export { default as MoversInstructionBanner } from '../../../../components/themes/cambridge-yle/CambridgeYleInstructionBanner';
|
|
9
|
+
export { default as MoversAudioPlayer } from '../../../../components/themes/cambridge-yle/CambridgeYleAudioPlayer';
|
|
10
|
+
export { default as MoversExampleText } from '../../../../components/themes/cambridge-yle/CambridgeYleExampleText';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{CambridgeYleExamLayout as MoversExamLayout}from"../../../../components/themes/cambridge-yle/CambridgeYleExamLayout";export{CambridgeYleHeader as MoversHeader}from"../../../../components/themes/cambridge-yle/CambridgeYleHeader";export{CambridgeYleNavButton as MoversNavButton}from"../../../../components/themes/cambridge-yle/CambridgeYleNavButton";export{CambridgeYleProgressBar as MoversProgressBar}from"../../../../components/themes/cambridge-yle/CambridgeYleProgressBar";export{CambridgeYleTimer as MoversTimer}from"../../../../components/themes/cambridge-yle/CambridgeYleTimer";export{default as MoversQuestionCard}from"../../../../components/themes/cambridge-yle/CambridgeYleQuestionCard";export{default as MoversPartBanner}from"../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";export{default as MoversInstructionBanner}from"../../../../components/themes/cambridge-yle/CambridgeYleInstructionBanner";export{default as MoversAudioPlayer}from"../../../../components/themes/cambridge-yle/CambridgeYleAudioPlayer";export{default as MoversExampleText}from"../../../../components/themes/cambridge-yle/CambridgeYleExampleText";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as l}from"react/jsx-runtime";import{ResolvedImage as r}from"../../../../../components/common/ResolvedImage";export function ArticlesViewer({articles:t,title:a}){return t&&0!==t.length?l("div",{className:"flex flex-col gap-3",children:[a&&e("h3",{className:"text-center text-lg font-bold text-gray-800",children:a}),e("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3",children:t.map((t,a)=>l("div",{className:"rounded-lg border border-gray-200 bg-white p-3 shadow-sm",children:[t.imageUrl&&e("div",{className:"mb-2 flex justify-center",children:e(r,{src:t.imageUrl,alt:t.name,className:"h-24 w-24 rounded-full object-cover"})}),e("h4",{className:"mb-1 text-center text-base font-bold text-gray-900",children:t.name}),e("p",{className:"text-sm leading-relaxed text-gray-700",children:t.content})]},a))})]}):null}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ANSWER_THE_QUESTION Renderer - Text input per question with optional prefix/suffix
|
|
3
|
+
* Used in Starters P2/P6/P9, Movers P2/P11
|
|
4
|
+
*/
|
|
5
|
+
import type { AnswerTheQuestionQuestion } from '../../utils/question-transformers';
|
|
6
|
+
interface MoversAnswerTheQuestionRendererProps {
|
|
7
|
+
partNumber: number;
|
|
8
|
+
partName?: string;
|
|
9
|
+
questionCount: number;
|
|
10
|
+
instruction: string;
|
|
11
|
+
imageUrl?: string;
|
|
12
|
+
audioUrl?: string;
|
|
13
|
+
title?: string;
|
|
14
|
+
groupContent?: string;
|
|
15
|
+
questions: AnswerTheQuestionQuestion[];
|
|
16
|
+
answers: Record<string, string>;
|
|
17
|
+
onAnswerChange: (questionId: string, value: string) => void;
|
|
18
|
+
isReviewMode?: boolean;
|
|
19
|
+
correctAnswerTextMap?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
export declare function MoversAnswerTheQuestionRenderer({ partNumber, partName, questionCount, instruction, imageUrl, audioUrl, groupContent, questions, answers, onAnswerChange, isReviewMode, correctAnswerTextMap, }: MoversAnswerTheQuestionRendererProps): import("react").JSX.Element;
|
|
22
|
+
export {};
|
package/dist/components/exams/take/components/question-renderers/MoversAnswerTheQuestionRenderer.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as e,jsxs as r}from"react/jsx-runtime";import{ResolvedImage as s}from"../../../../../components/common/ResolvedImage";import a from"../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";import t from"../../../../../components/themes/cambridge-yle/CambridgeYleInstructionBanner";import n from"../../../../../components/themes/cambridge-yle/CambridgeYleAudioPlayer";function i({question:a,answer:t,onAnswerChange:n,isReviewMode:i,correctAnswerTextMap:o,id:l}){const d=a.isExample,m=i||d,c=o[a.id],g=t||"",p=d&&a.exampleAnswer?a.exampleAnswer:g,x=i&&void 0!==c,u=x&&g.trim().toLowerCase()===c.trim().toLowerCase(),b=x&&!!g&&!u;return r("div",{id:l,className:"flex items-start gap-3 rounded-lg p-3 "+(d?"border-2 border-orange-200 bg-orange-50":""),children:[e("span",{className:"flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full text-sm font-bold text-white "+(d?"bg-orange-400":u?"bg-green-500":b?"bg-red-500":"bg-blue-500"),children:a.questionNumber}),r("div",{className:"flex flex-1 flex-col gap-2",children:[a.imageUrl&&e(s,{src:a.imageUrl,alt:`Q${a.questionNumber}`,className:"max-h-[120px] rounded-lg object-contain"}),r("div",{className:"flex flex-wrap items-baseline gap-2",children:[e("span",{className:"font-medium text-gray-800",children:a.question}),a.prefixText&&e("span",{className:"text-gray-600",children:a.prefixText}),e("input",{type:"text",value:p,onChange:e=>n(a.id,e.target.value),disabled:m,placeholder:d?"":"Type your answer...",className:"min-w-[140px] flex-1 border-b-2 bg-transparent px-1 py-1 text-center outline-none focus:border-blue-500 disabled:cursor-default "+(d?"border-orange-400 font-semibold text-orange-700 disabled:opacity-100":u?"border-green-500 text-green-700":b?"border-red-500 text-red-700":"border-gray-400 disabled:opacity-60")}),a.suffixText&&e("span",{className:"text-gray-600",children:a.suffixText}),d&&e("span",{className:"rounded bg-orange-100 px-2 py-0.5 text-xs font-semibold text-orange-600",children:"Example"})]}),!d&&b&&x&&r("p",{className:"text-sm text-green-600",children:["Đáp án đúng: ",c]}),!d&&x&&!g&&r("p",{className:"text-sm text-green-600",children:["Đáp án đúng: ",c]}),a.suggestedAnswers&&a.suggestedAnswers.length>0&&!m&&e("div",{className:"flex flex-wrap gap-2",children:a.suggestedAnswers.map((r,s)=>e("button",{type:"button",onClick:()=>n(a.id,r),className:"rounded-full border border-blue-300 bg-blue-50 px-3 py-1 text-sm text-blue-700 transition-colors hover:bg-blue-100",children:r},s))})]})]})}export function MoversAnswerTheQuestionRenderer({partNumber:o,partName:l,questionCount:d,instruction:m,imageUrl:c,audioUrl:g,groupContent:p,questions:x,answers:u,onAnswerChange:b,isReviewMode:h=!1,correctAnswerTextMap:f={}}){const w=x.filter(e=>e.isExample),N=x.filter(e=>!e.isExample);return r("div",{className:"flex flex-col h-full gap-4 sm:gap-6 overflow-y-auto custom-scrollbar",children:[r("div",{className:"flex flex-col gap-4 p-3 sm:px-6 sm:pt-2",children:[e(a,{partNumber:o,questionCount:d,partName:l,isReviewMode:h}),e(t,{instruction:m,isReviewMode:h}),g&&e("div",{className:"relative z-10",children:e(n,{audioSrc:g,compact:!0})}),c&&e("div",{className:"relative z-0 flex items-center justify-center",children:e(s,{src:c,alt:"Shared illustration",className:"max-h-[450px] rounded-lg object-contain shadow-md"})}),p&&e("div",{className:"rounded-lg bg-amber-50 p-4 text-base leading-relaxed text-gray-800",dangerouslySetInnerHTML:{__html:p}}),w.length>0&&e("div",{className:"flex flex-col gap-4 mt-2",children:w.map(r=>e(i,{id:`question-${r.id}`,question:r,answer:u[r.id],onAnswerChange:b,isReviewMode:h,correctAnswerTextMap:f},r.id))})]}),w.length>0&&N.length>0&&e("div",{className:"px-3 sm:px-6",children:e("hr",{className:"border-t border-slate-200/60 my-1"})}),e("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-4 sm:gap-5 p-3 sm:px-6 sm:pb-6",children:N.map(r=>e("div",{id:`question-${r.id}`,className:"w-full rounded-xl border border-gray-200 bg-white shadow-sm transition-all hover:border-indigo-200 hover:shadow-md",children:e(i,{question:r,answer:u[r.id],onAnswerChange:b,isReviewMode:h,correctAnswerTextMap:f})},r.id))})]})}
|
package/dist/components/exams/take/components/question-renderers/MoversChooseAdjectiveRenderer.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ChooseAdjectiveQuestion } from '../../utils/question-transformers';
|
|
2
|
+
interface MoversChooseAdjectiveRendererProps {
|
|
3
|
+
partNumber: number;
|
|
4
|
+
partName?: string;
|
|
5
|
+
questionCount: number;
|
|
6
|
+
instruction: string;
|
|
7
|
+
questions: ChooseAdjectiveQuestion[];
|
|
8
|
+
answers: Record<string, string>;
|
|
9
|
+
onAnswerChange: (questionId: string, optionId: string) => void;
|
|
10
|
+
isReviewMode?: boolean;
|
|
11
|
+
correctAnswers?: Record<string, number>;
|
|
12
|
+
}
|
|
13
|
+
export declare function MoversChooseAdjectiveRenderer({ partNumber, partName, questionCount, instruction, questions, answers, onAnswerChange, isReviewMode, correctAnswers, }: MoversChooseAdjectiveRendererProps): import("react").JSX.Element;
|
|
14
|
+
export {};
|
package/dist/components/exams/take/components/question-renderers/MoversChooseAdjectiveRenderer.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import t from"../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";import n from"../../../../../components/themes/cambridge-yle/CambridgeYleInstructionBanner";function i({question:t,selectedOptionId:n,onSelect:i,isReviewMode:o,correctOptionIndex:s,id:d}){const l=function(e,r){if(!r)return null;const t=e.options.find(e=>e.id===r);return t?.text||null}(t,n),a=void 0!==s?`${t.id}-opt-${s}`:void 0,c=e=>{const r=n===e.id,t=e.id===a;return o?t?"border-green-500 bg-green-50 text-green-700":r&&!t?"border-red-500 bg-red-50 text-red-700":"border-gray-300 bg-white text-gray-500":r?"border-blue-500 bg-blue-50 text-blue-700":"border-gray-300 bg-white hover:border-blue-300 text-gray-700"};return r("div",{id:d,className:"mb-6",children:[r("div",{className:"mb-3 flex items-baseline gap-2",children:[e("span",{className:"flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full bg-blue-500 text-sm font-bold text-white",children:t.questionNumber}),r("div",{className:"flex-1 text-base leading-relaxed text-gray-800",children:[e("span",{children:t.sentenceBefore}),e("span",{className:`mx-1 inline-block min-w-[100px] border-b-2 px-2 text-center font-semibold ${(()=>{if(!o)return l?"text-blue-600":"text-gray-400";if(!n)return"text-gray-400";return n===a?"text-green-600":"text-red-600"})()} ${(()=>{if(!o)return l?"border-blue-500":"border-gray-300";if(!n)return"border-gray-300";return n===a?"border-green-500":"border-red-500"})()}`,children:l||"_______"}),e("span",{children:t.sentenceAfter}),r("span",{className:"ml-2 text-sm italic text-gray-500",children:["(",t.options.map(e=>e.text).join(" / "),")"]})]})]}),e("div",{className:"flex flex-wrap gap-2 pl-9",children:t.options.map(e=>r("button",{type:"button",onClick:()=>!o&&i(e.id),disabled:o,className:`rounded-lg border-2 px-4 py-2 text-sm font-medium transition-colors ${c(e)} ${o?"cursor-default":"cursor-pointer"}`,children:[e.label,". ",e.text]},e.id))}),o&&n&&n!==a&&void 0!==s&&r("div",{className:"mt-2 pl-9 text-sm text-green-600",children:[e("span",{className:"font-semibold",children:"Đáp án đúng: "}),t.options[s]?.text]})]})}export function MoversChooseAdjectiveRenderer({partNumber:o,partName:s,questionCount:d,instruction:l,questions:a,answers:c,onAnswerChange:m,isReviewMode:u=!1,correctAnswers:p={}}){return r("div",{className:"grid h-full grid-cols-1 gap-4 sm:gap-6 "+(u?"":"lg:grid-cols-2"),children:[r("div",{className:"flex flex-col gap-4 overflow-y-auto p-3 sm:pb-6 sm:pr-6 sm:pt-6",children:[e(t,{partNumber:o,questionCount:d,partName:s,isReviewMode:u}),e(n,{instruction:l,isReviewMode:u})]}),e("div",{className:"flex flex-col gap-4 overflow-y-auto p-3 sm:pb-6 sm:pl-2 sm:pt-6",children:a.map(r=>e(i,{id:`question-${r.id}`,question:r,selectedOptionId:c[r.id],onSelect:e=>m(r.id,e),isReviewMode:u,correctOptionIndex:p[r.id]},r.id))})]})}
|
package/dist/components/exams/take/components/question-renderers/MoversChooseBestAnswerRenderer.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { MoversChooseBestAnswerRendererProps } from '../../types';
|
|
2
|
+
export declare function MoversChooseBestAnswerRenderer({ partNumber, partName, questionCount, instruction, imageUrl, groupTitle, groupContent, articles, audioUrl, example, questions, answers, onAnswerChange, isReviewMode, }: MoversChooseBestAnswerRendererProps): import("react").JSX.Element;
|
package/dist/components/exams/take/components/question-renderers/MoversChooseBestAnswerRenderer.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as t,Fragment as r}from"react/jsx-runtime";import{ZoomIn as n}from"lucide-react";import{useState as l}from"react";import{cn as o}from"../../../../../shared/lib/utils";import{ResolvedImage as i}from"../../../../../components/common/ResolvedImage";import s from"../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";import a from"../../../../../components/themes/cambridge-yle/CambridgeYleInstructionBanner";import d from"../../../../../components/themes/cambridge-yle/CambridgeYleAudioPlayer";function c(e){if("string"==typeof e)return e;if("number"==typeof e||"boolean"==typeof e)return String(e);if(Array.isArray(e))return e.map(e=>c(e)).filter(Boolean).join(" ");if(e&&"object"==typeof e){const t=e;if("string"==typeof t.content)return t.content;if("string"==typeof t.question)return t.question;if("string"==typeof t.text)return t.text;const r=Object.entries(t).filter(([e,t])=>/^\d+$/.test(e)&&"string"==typeof t).sort(([e],[t])=>Number(e)-Number(t)).map(([,e])=>e);if(r.length>0)return r.join("")}return""}function m({imageUrl:o}){const[s,a]=l(!1);return t(r,{children:[t("div",{className:"relative flex items-center justify-center",children:[e(i,{src:o,alt:"Question illustration",className:"max-h-[250px] cursor-pointer rounded-lg object-contain shadow-md",onClick:()=>a(!0)}),e("button",{type:"button",onClick:()=>a(!0),className:"absolute right-2 top-2 rounded-full bg-white/80 p-1.5 shadow-md hover:bg-white","aria-label":"Zoom image",children:e(n,{className:"h-4 w-4 text-gray-600"})})]}),s&&e("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/70",onClick:()=>a(!1),children:e(i,{src:o,alt:"Question illustration (zoomed)",className:"max-h-[90vh] max-w-[90vw] rounded-lg object-contain",showLoadingState:!1})})]})}function u({example:r}){return t("div",{className:"rounded-lg border-2 border-orange-300 bg-white p-4",children:[e("p",{className:"mb-3 text-sm font-semibold text-gray-700",children:"Example:"}),t("p",{className:"mb-3 text-[19px] font-bold text-[#001590]",children:[r.questionNumber,". ",c(r.questionText)]}),r.imageUrl&&e("div",{className:"mb-3",children:e(m,{imageUrl:r.imageUrl})}),"image"===r.optionType?e("div",{className:"grid gap-3 px-2",style:{gridTemplateColumns:`repeat(${r.options.length}, minmax(0, 1fr))`},children:r.options.map(n=>{const l=n.id===r.correctOptionId;return t("div",{className:"relative flex flex-col items-center gap-1 rounded-[16px] border-[3px] p-4 pt-6 mt-3 transition-colors "+(l?"border-green-500 bg-green-50":"border-blue-200 bg-white"),children:[e("div",{className:"absolute -top-[14px] left-1/2 -translate-x-1/2 bg-blue-600 text-white w-[28px] h-[28px] rounded-full flex items-center justify-center font-bold text-[15px] shadow-sm",children:n.label}),e(i,{src:n.text,alt:`Option ${n.label}`,className:"w-40 rounded object-contain mb-2"}),e("div",{className:o("w-7 h-7 rounded-full flex items-center justify-center border-[3px] transition-all mt-auto",l?"bg-green-500 border-green-500 text-white":"border-gray-300 bg-white text-transparent"),children:e("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"3.5",strokeLinecap:"round",strokeLinejoin:"round",children:e("polyline",{points:"20 6 9 17 4 12"})})})]},n.id)})}):e("div",{className:"flex flex-col gap-2 pl-2",children:r.options.map(n=>{const l=n.id===r.correctOptionId;return t("div",{className:"flex items-center gap-3 rounded-lg border-2 px-3 py-2 text-left transition-colors "+(l?"border-green-500 bg-green-50":"border-blue-200 bg-white"),children:[t("span",{className:"text-sm font-medium text-gray-600",children:[n.label,"."]}),e("span",{className:"flex-1 text-sm text-gray-700",children:c(n.text)}),e("div",{className:"flex h-5 w-5 items-center justify-center border-2 rounded-full "+(l?"border-green-500 bg-green-500":"border-gray-300 bg-white"),children:l&&e("div",{className:"h-2 w-2 rounded-full bg-white"})})]},n.id)})})]})}function p({question:r,selectedOptionIds:n,onSelect:l,isReviewMode:s,id:a}){const d=Boolean(r.multipleAnswers||r.correctOptionIds?.length),u=r.correctOptionIds?.length?r.correctOptionIds:r.correctOptionId?[r.correctOptionId]:[],p=e=>{const t=n.includes(e),r=u.includes(e);return s?r?"border-green-500 bg-green-50":t&&!r?"border-red-500 bg-red-50":"border-blue-200 bg-white":t?"border-blue-500 bg-[#f4f9ff]":"border-blue-200 bg-white hover:border-blue-300 hover:bg-blue-50/30"},b=e=>{const t=n.includes(e),r=u.includes(e);return s?r?"border-green-500 bg-green-500":t&&!r?"border-red-500 bg-red-500":"border-gray-300 bg-white":t?"border-blue-500 bg-blue-500":"border-gray-300 bg-white"},g=e=>s?n.includes(e)||u.includes(e):n.includes(e);return t("div",{id:a,className:"mb-6",children:[t("p",{className:"mb-3 text-[19px] font-bold text-[#001590]",children:[r.questionNumber,". ",c(r.questionText)]}),d&&e("p",{className:"mb-3 pl-2 text-sm font-medium text-blue-600",children:"Chọn nhiều đáp án"}),r.imageUrl&&e("div",{className:"mb-3",children:e(m,{imageUrl:r.imageUrl})}),"image"===r.optionType?e("div",{className:"grid gap-3 px-2",style:{gridTemplateColumns:`repeat(${r.options.length}, minmax(0, 1fr))`},children:r.options.map(r=>t("button",{type:"button",onClick:()=>!s&&l(r.id),disabled:s,className:`relative flex flex-col items-center gap-1 rounded-[16px] border-[3px] p-4 pt-6 mt-3 transition-colors ${p(r.id)} ${s?"cursor-default":"cursor-pointer"}`,children:[e("div",{className:"absolute -top-[14px] left-1/2 -translate-x-1/2 bg-blue-600 text-white w-[28px] h-[28px] rounded-full flex items-center justify-center font-bold text-[15px] shadow-sm",children:r.label}),e(i,{src:r.text,alt:`Option ${r.label}`,className:"w-35 rounded object-contain mb-2"}),e("div",{className:o("w-7 h-7 rounded-full flex items-center justify-center border-[3px] transition-all mt-auto",g(r.id)?"bg-blue-600 border-blue-600 text-white":"border-gray-300 bg-white text-transparent"),children:e("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"3.5",strokeLinecap:"round",strokeLinejoin:"round",children:e("polyline",{points:"20 6 9 17 4 12"})})})]},r.id))}):e("div",{className:"flex flex-col gap-2 pl-2",children:r.options.map(r=>t("button",{type:"button",onClick:()=>!s&&l(r.id),disabled:s,className:`flex items-center gap-3 rounded-lg border-2 px-3 py-2 text-left transition-colors ${p(r.id)} ${s?"cursor-default":"cursor-pointer"}`,children:[t("span",{className:"text-sm font-medium text-gray-600",children:[r.label,"."]}),e("span",{className:"flex-1 text-sm text-gray-700",children:c(r.text)}),e("div",{className:`flex h-5 w-5 items-center justify-center border-2 ${d?"rounded-md":"rounded-full"} ${b(r.id)}`,children:g(r.id)&&e("div",{className:(d?"h-2.5 w-2.5 rounded-sm":"h-2 w-2 rounded-full")+" bg-white"})})]},r.id))})]})}function b({article:r,label:n}){return t("div",{className:"rounded-lg border border-gray-200 bg-white p-4 shadow-sm",children:[t("div",{className:"mb-2 flex items-center gap-2",children:[e("span",{className:"flex h-7 w-7 items-center justify-center rounded-full bg-teal-500 text-xs font-bold text-white",children:n}),e("h3",{className:"text-sm font-bold text-gray-900",children:r.name})]}),r.imageUrl&&e("div",{className:"mb-2",children:e(i,{src:r.imageUrl,alt:r.name,className:"max-h-48 w-full rounded-md object-contain"})}),e("div",{className:"article-content text-sm leading-relaxed text-gray-700",dangerouslySetInnerHTML:{__html:r.content}})]})}export function MoversChooseBestAnswerRenderer({partNumber:r,partName:n,questionCount:l,instruction:o,imageUrl:c,groupTitle:m,groupContent:g,articles:x,audioUrl:h,example:f,questions:w,answers:y,onAnswerChange:N,isReviewMode:v=!1}){const j=!!(h||c||x&&x.length>0||g||f);return t("div",{className:"flex flex-col h-full gap-4 sm:gap-6 overflow-y-auto custom-scrollbar relative",children:[t("div",{className:"flex flex-col gap-2 sm:gap-3 p-3 sm:px-6 sm:pt-2",children:[e(s,{partNumber:r,questionCount:l,partName:n,isReviewMode:v}),e(a,{instruction:o,isReviewMode:v}),m&&!(x&&x.length>0)&&e("h2",{className:"text-center text-xl font-bold uppercase text-coral-500",children:m})]}),j&&t("div",{className:"flex flex-col gap-2 sm:gap-3 p-3 sm:px-6 sm:pt-0 sticky top-0 z-20 bg-white/95 backdrop-blur pb-2 shadow-sm border-b border-gray-100",children:[h&&e(d,{audioSrc:h,compact:!0}),c&&e("div",{className:"flex items-center justify-center",children:e(i,{src:c,alt:"Shared illustration",className:"max-h-[250px] rounded-lg object-contain shadow-md"})}),x&&x.length>0?e("div",{className:"flex flex-col gap-3 max-h-[35vh] overflow-y-auto custom-scrollbar pr-2",children:x.map((t,r)=>e(b,{article:t,label:String.fromCharCode(65+r)},r))}):g?e("div",{className:"article-content rounded-lg bg-amber-50 p-3 sm:p-4 text-sm leading-relaxed text-gray-700 max-h-[35vh] overflow-y-auto pr-2 custom-scrollbar shadow-inner",dangerouslySetInnerHTML:{__html:g}}):null,f&&e(u,{example:f})]}),e("div",{className:"p-3 sm:pb-6 sm:px-6 "+(v?"grid grid-cols-1 md:grid-cols-2 gap-6":"flex flex-col gap-4"),children:w.map(t=>{const r=y[t.id],n=Array.isArray(r)?r:"string"==typeof r&&r?[r]:[];return e(p,{id:`question-${t.id}`,question:t,selectedOptionIds:n,onSelect:e=>{const r=t.multipleAnswers?n.includes(e)?n.filter(t=>t!==e):[...n,e]:e;N(t.id,r)},isReviewMode:v},t.id)})})]})}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import{useState as i,useRef as n,useEffect as r,useCallback as o,useMemo as d}from"react";import{ReactFlow as l,useNodesState as s,useEdgesState as a,ReactFlowProvider as c,useReactFlow as h}from"@xyflow/react";import"@xyflow/react/dist/style.css";import{usePresignedFileUrl as u}from"../../../../../shared/lib/hooks/usePresignedFileUrl";import g from"../../../../../components/themes/cambridge-yle/CambridgeYleInstructionBanner";import f from"../../../../../components/themes/cambridge-yle/CambridgeYleAudioPlayer";import m from"../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";const p={coloringHintNode:function({data:t}){const{hintItem:i,isAssigned:n,highlightStyle:r,isHighlighted:o}=t,d=!!i.color,l=n?"flex h-full w-full items-center justify-center overflow-hidden rounded-xl transition-all duration-200":"flex h-full w-full items-center justify-center overflow-hidden rounded-full border-2 transition-all duration-200 cursor-move hover:shadow-lg",s=o?"transparent":d?"rgba(0,0,0,0.2)":"#9ca3af",a=!!i.label?i.label:"";return e("div",{className:l,style:{...r,backgroundColor:d?i.color:"#ffffff",borderColor:n?"transparent":s,padding:n?0:void 0},children:a&&e("span",{className:"px-2 py-5 text-[10px] font-bold uppercase tracking-wide pointer-events-none drop-shadow-md font-[family-name:var(--font-nunito)] md:text-xs",style:{color:(e=>{if(!e)return"#333";if(!e.startsWith("#"))return"#fff";const t=e.replace("#","");return(.299*parseInt(t.substr(0,2),16)+.587*parseInt(t.substr(2,2),16)+.114*parseInt(t.substr(4,2),16))/255>.5?"#000":"#fff"})(i.color),textShadow:d?"0 1px 2px rgba(0,0,0,0.3)":"none"},children:a})})},coloringRegionNode:function({data:t}){const{assignedHint:i,isHighlighted:n,isCorrect:r,isReviewMode:o}=t;return e("div",{className:"flex h-full w-full items-center justify-center rounded-xl transition-all "+(o?i?r?"border-2 border-solid border-green-500":"border-2 border-solid border-red-500":"border-2 border-solid border-blue-500":n?"border-2 border-solid border-blue-500":i?"":"border-2 border-dashed border-red-400"),style:{backgroundColor:i?.color||(n?"rgba(59,130,246,0.1)":"rgba(0,0,0,0.1)"),minWidth:"60px",minHeight:"40px"},children:i?.label&&e("span",{className:"px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wide pointer-events-none drop-shadow-md font-[family-name:var(--font-nunito)] md:text-xs",style:{color:(e=>{if(!e)return"#333";const t=e.replace("#","");return(.299*parseInt(t.substr(0,2),16)+.587*parseInt(t.substr(2,2),16)+.114*parseInt(t.substr(4,2),16))/255>.5?"#000":"#fff"})(i.color)},children:i.label})})}};function x({partNumber:c,partName:x,questionCount:b,instruction:w,instructions:y,hasExample:v=!1,imageUrl:N,audioUrl:I,hintItems:M,regions:C,assignments:H,onAssignmentChange:j,isReviewMode:O=!1}){const{previewUrl:$}=u(N),[z,R]=i(!1),[k,S]=i({width:0,height:0}),[E,D]=i({width:0,height:0}),A=n(null),P=n(null),[U,W,L]=s([]),[,,Y]=a([]),[q,B]=i(null),V=n(!1),F=n(null),{getIntersectingNodes:K}=h(),Q=E.width>0&&E.width<640,T=Q?60:100,G=Q?32:40,J=Q?10:16,X=Math.max(E.width-32,T),Z=Math.max(1,Math.floor((X+J)/(T+J))),_=M.filter(e=>!Object.values(H).includes(e.id)).length,ee=20+Math.max(1,Math.ceil(_/Z))*(G+8)+(Q?20:10),te=ee+20;r(()=>{const e=()=>{P.current&&D({width:P.current.clientWidth,height:P.current.clientHeight})};return e(),window.addEventListener("resize",e),()=>window.removeEventListener("resize",e)},[]);const ie=o(()=>{if(A.current&&E.width>0){const e=E.width-20,t=E.height-te-10,i=A.current.naturalWidth||800,n=A.current.naturalHeight||600,r=e/i,o=t/n,d=Math.min(r,o,2);S({width:i*d,height:n*d}),R(!0)}},[E,te]);r(()=>{E.width>0&&A.current?.complete&&ie()},[E,ie]);const ne=d(()=>!z||k.width<=0||E.width<=0?10:Math.max(10,(E.width-k.width)/2),[z,k.width,E.width]),re=o((e,t)=>{if("coloringHintNode"!==t.type)return;V.current=!0;const i=t.data,n=i.hintItem?.id;if(!n)return;const r=i.regionId||Object.keys(H).find(e=>H[e]===n);F.current=r||null,r&&j(r,null)},[H,j]),oe=o((e,t)=>{if("coloringHintNode"!==t.type)return;const i=K(t,!0).filter(e=>"coloringRegionNode"===e.type),n=t.position.y,r=n>=0&&n<=ee;i.length>0?B(i[0].id):B(r?"hint-area":null)},[K,ee]),de=o((e,t)=>{if("coloringHintNode"!==t.type)return;const i=t.data,n=i.hintItem?.id;if(!n)return B(null),void(V.current=!1);const r=K(t,!0).filter(e=>"coloringRegionNode"===e.type);if(B(null),r.length>0){const e=r[0],t=F.current,i=H[e.id];i&&i!==n?(j(e.id,n),t&&j(t,i)):j(e.id,n)}else{if(M.find(e=>e.id===n)){const e=F.current?Object.fromEntries(Object.entries(H).filter(([e])=>e!==F.current)):H,i=M.filter(t=>!Object.values(e).includes(t.id)||t.id===n).findIndex(e=>e.id===n),r=i%Z,o=Math.floor(i/Z),d={x:16+r*(T+J),y:20+o*(G+8)};W(e=>e.map(e=>e.id===t.id?{...e,position:d}:e))}}F.current=null,V.current=!1},[K,H,j,M,W,Z,T,J,G]),le=d(()=>M.filter(e=>!Object.values(H).includes(e.id)).map((e,t)=>{const i=t%Z,n=Math.floor(t/Z);return{id:`hint-${e.id}`,type:"coloringHintNode",position:{x:16+i*(T+J),y:20+n*(G+8)},data:{hintItem:e,isAssigned:!1},draggable:!O,style:{width:`${T}px`,height:`${G}px`}}}),[M,H,O,Z,16,T,J,20,G,8]),se=d(()=>!z||k.width<=0?[]:C.filter(e=>H[e.id]).map(e=>{const t=H[e.id],i=M.find(e=>e.id===t);if(!i)return null;const n=ne+e.x/100*k.width,r=te+e.y/100*k.height,o=Math.max(e.width/100*k.width,60),d=Math.max(e.height/100*k.height,40);return{id:`hint-in-region-${e.id}`,type:"coloringHintNode",position:{x:n,y:r},data:{hintItem:i,isAssigned:!0,regionId:e.id},draggable:!O,style:{width:`${o}px`,height:`${d}px`}}}).filter(e=>null!==e),[z,k,ne,C,H,M,O,te]),ae=d(()=>!z||k.width<=0?[]:C.map(e=>{const t=H[e.id],i=t?M.find(e=>e.id===t):void 0,n=O&&t===e.correctHintId;return{id:e.id,type:"coloringRegionNode",position:{x:ne+e.x/100*k.width,y:te+e.y/100*k.height},data:{region:e,assignedHint:i,isHighlighted:q===e.id,isCorrect:n,isReviewMode:O},draggable:!1,style:{width:`${Math.max(e.width/100*k.width,60)}px`,height:`${Math.max(e.height/100*k.height,40)}px`,pointerEvents:i?"none":"auto"},zIndex:0}}),[z,k,ne,C,H,M,q,O,te]);return r(()=>{if(V.current)return;const e=[...ae,...le,...se];W(e)},[ae,le,se,W]),t("div",{className:"flex h-full w-full flex-col gap-3",children:[e(m,{partNumber:c,questionCount:b,partName:x,isReviewMode:O}),e("div",{className:"shrink-0",children:e(g,{instruction:w,instructions:y,hasExample:v,isReviewMode:O,children:I&&e("div",{className:"shrink-0",children:e(f,{audioSrc:I,compact:!0})})})}),t("div",{ref:P,className:"relative flex-1 overflow-x-auto overflow-y-hidden rounded-xl bg-gray-100",style:{minHeight:"1000px"},children:[e("div",{className:"pointer-events-none absolute left-0 right-0 z-20 flex items-center justify-center sm:justify-end sm:pr-4",style:{top:Q?ee-40+"px":"20px",height:"40px"},children:e("span",{className:"rounded-full bg-white/80 px-3 py-1 text-xs font-medium text-gray-500 shadow-sm",children:"Kéo màu vào vị trí tương ứng"})}),e("div",{className:"pointer-events-none absolute",style:{left:`${ne}px`,top:`${te}px`,width:k.width?`${k.width}px`:"auto",height:k.height?`${k.height}px`:"auto",zIndex:0},children:e("img",{ref:A,src:$||N,alt:"Question illustration",className:"h-full w-full rounded-lg object-contain shadow-md",onLoad:ie,onError:()=>R(!1)})}),e("div",{className:"absolute inset-0 z-10",children:e(l,{nodes:U,edges:[],onNodesChange:L,onNodeDragStart:re,onNodeDrag:oe,onNodeDragStop:de,onEdgesChange:Y,nodeTypes:p,defaultViewport:{x:0,y:0,zoom:1},fitView:!1,nodesDraggable:!O,nodesConnectable:!1,elementsSelectable:!1,panOnDrag:!1,panOnScroll:!1,zoomOnScroll:!1,zoomOnDoubleClick:!1,zoomOnPinch:!1,preventScrolling:!0,autoPanOnNodeDrag:!1,autoPanOnConnect:!1,proOptions:{hideAttribution:!0}})})]})]})}export function MoversColoringRenderer(t){return e(c,{children:e(x,{...t})})}
|
package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { MoversFillWordHintRendererProps } from '../../types';
|
|
2
|
+
export declare function MoversFillWordHintRenderer({ partNumber, partName, questionCount, instruction, hintLetters, subQuestions, answers, onAnswerChange, isReviewMode, }: MoversFillWordHintRendererProps): import("react").JSX.Element;
|
package/dist/components/exams/take/components/question-renderers/MoversFillWordHintRenderer.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as r,Fragment as t}from"react/jsx-runtime";import{useState as s}from"react";import{ZoomIn as o,Check as n}from"lucide-react";import{ResolvedImage as a}from"../../../../../components/common/ResolvedImage";import i from"../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";import l from"../../../../../components/themes/cambridge-yle/CambridgeYleInstructionBanner";function c({imageUrl:n,alt:i}){const[l,c]=s(!1);return n?r(t,{children:[r("div",{className:"relative flex items-center justify-center",children:[e(a,{src:n,alt:i,className:"h-24 w-24 cursor-pointer rounded-lg object-cover shadow-md",onClick:()=>c(!0)}),e("button",{type:"button",onClick:()=>c(!0),className:"absolute -right-1 -top-1 rounded-full bg-white/80 p-1 shadow-md hover:bg-white","aria-label":"Zoom image",children:e(o,{className:"h-3 w-3 text-gray-600"})})]}),l&&e("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/70",onClick:()=>c(!1),children:e(a,{src:n,alt:`${i} (zoomed)`,className:"max-h-[90vh] max-w-[90vw] rounded-lg object-contain",showLoadingState:!1})})]}):null}function d({letters:t}){return r("div",{className:"rounded-lg border-2 border-amber-200 bg-amber-50 p-4",children:[e("p",{className:"mb-3 text-sm font-semibold text-amber-800",children:"Available Letters:"}),e("div",{className:"flex flex-wrap gap-2",children:t.map((r,t)=>e("span",{className:"flex h-10 w-10 items-center justify-center rounded-lg bg-white text-lg font-bold text-amber-700 shadow-sm",children:r},t))})]})}function m({word:t,answer:s,isReviewMode:o,correctAnswer:n}){const a=t.indexOf("_"),i=t.slice(0,a),l=t.slice(a+1),c=o&&s.toLowerCase()===n?.toLowerCase(),d=o&&s&&s.toLowerCase()!==n?.toLowerCase(),m=o&&!s,u=m?n:s||"_";return r("div",{className:"flex items-center justify-center text-2xl font-bold tracking-wider text-gray-700",children:[e("span",{children:i}),e("span",{className:"mx-0.5 inline-flex h-8 w-8 items-center justify-center rounded border-2 "+(o?c?"border-green-500 bg-green-100 text-green-600":d?"border-red-500 bg-red-100 text-red-600":m?"border-blue-500 bg-blue-50 text-blue-600":"border-gray-300 bg-gray-50 text-gray-400":"border-blue-400 bg-blue-50 text-blue-600"),children:u}),e("span",{children:l})]})}function u({subQuestion:t,answer:s,onChange:o,isReviewMode:a,hintLetters:i,id:l}){const d=a&&s.toLowerCase()===t.correctAnswer?.toLowerCase(),u=a&&s&&s.toLowerCase()!==t.correctAnswer?.toLowerCase(),b=a&&!s;return r("div",{id:l,className:"rounded-lg border border-gray-200 bg-white p-4 shadow-sm",children:[r("div",{className:"mb-3 flex items-start gap-3",children:[e("span",{className:"flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full bg-blue-500 text-sm font-bold text-white",children:t.questionNumber}),e(c,{imageUrl:t.imageUrl,alt:`Question ${t.questionNumber}`})]}),e("div",{className:"mb-3",children:e(m,{word:t.word,answer:s,isReviewMode:a,correctAnswer:t.correctAnswer})}),e("div",{className:"flex flex-wrap justify-center gap-2",children:i.map((r,n)=>{const i=s.toLowerCase()===r.toLowerCase(),l=t.correctAnswer?.toLowerCase()===r.toLowerCase(),c=!s,d=s&&s.toLowerCase()!==t.correctAnswer?.toLowerCase();let m="border-gray-300 bg-white hover:border-blue-300",u="text-gray-700";return a?l?(m=c||d?"border-blue-500 bg-blue-50":"border-green-500 bg-green-100",u="text-gray-800 font-bold"):i&&!l?(m="border-red-500 bg-red-100",u="text-gray-800 font-bold"):u="text-gray-600":i&&(m="border-blue-500 bg-blue-100"),e("button",{type:"button",onClick:()=>!a&&o(r),disabled:a,className:`flex h-10 w-10 items-center justify-center rounded-lg border-2 text-lg transition-colors ${m} ${u} ${a?"cursor-default":"cursor-pointer"}`,children:r},n)})}),a&&r("div",{className:"mt-2 flex items-center justify-center gap-2",children:[d&&r("span",{className:"flex items-center gap-1 text-sm font-medium text-green-600",children:[e(n,{className:"h-4 w-4"})," Correct"]}),u&&r("span",{className:"text-sm font-medium text-blue-600",children:["Correct answer: ",t.correctAnswer]}),b&&r("span",{className:"flex items-center gap-1 text-sm font-medium text-blue-600",children:["Correct answer: ",t.correctAnswer]})]})]})}function b({subQuestion:t,answer:s,onChange:o,isReviewMode:a,hintLetters:i,id:l}){const c=a&&s.toLowerCase()===t.correctAnswer?.toLowerCase(),d=a&&s&&s.toLowerCase()!==t.correctAnswer?.toLowerCase(),u=a&&!s;return r("div",{id:l,className:"flex flex-col items-center gap-2 rounded-lg border border-gray-200 bg-white p-4",children:[e(m,{word:t.word,answer:s,isReviewMode:a,correctAnswer:t.correctAnswer}),e("div",{className:"flex flex-wrap justify-center gap-1",children:i.map((r,n)=>{const i=s.toLowerCase()===r.toLowerCase(),l=t.correctAnswer?.toLowerCase()===r.toLowerCase(),c=!s,d=s&&s.toLowerCase()!==t.correctAnswer?.toLowerCase();let m="border-gray-300 bg-white hover:border-blue-300",u="text-gray-700";return a?l?(m=c||d?"border-blue-500 bg-blue-50":"border-green-500 bg-green-100",u="text-gray-800 font-bold"):i&&!l?(m="border-red-500 bg-red-100",u="text-gray-800 font-bold"):u="text-gray-600":i&&(m="border-blue-500 bg-blue-100"),e("button",{type:"button",onClick:()=>!a&&o(r),disabled:a,className:`flex h-8 w-8 items-center justify-center rounded-lg border-2 text-base transition-colors ${m} ${u} ${a?"cursor-default":"cursor-pointer"}`,children:r},n)})}),a&&r("div",{className:"flex items-center justify-center gap-2",children:[c&&r("span",{className:"flex items-center gap-1 text-xs font-medium text-green-600",children:[e(n,{className:"h-3 w-3"})," Correct"]}),(d||u)&&r("span",{className:"text-xs font-medium text-blue-600",children:["Correct answer: ",t.correctAnswer]})]})]})}export function MoversFillWordHintRenderer({partNumber:t,partName:s,questionCount:o,instruction:n,hintLetters:a,subQuestions:m,answers:g,onAnswerChange:w,isReviewMode:f=!1}){const h=m.length>0&&void 0!==m[0].blankIndex&&m.every(e=>e.imageUrl===m[0].imageUrl);return r("div",h?{className:"flex h-full flex-col gap-4 overflow-y-auto p-6",children:[r("div",{className:"flex flex-col gap-4",children:[e(i,{partNumber:t,questionCount:o,partName:s,isReviewMode:f}),e(l,{instruction:n,isReviewMode:f}),e(d,{letters:a})]}),r("div",{className:"rounded-lg border border-gray-200 bg-white p-6 shadow-sm",children:[e("div",{className:"mb-6 flex justify-center",children:e(c,{imageUrl:m[0].imageUrl,alt:"Question image"})}),e("div",{className:"flex flex-wrap justify-center gap-4",children:m.map(r=>e(b,{id:`question-${r.id}`,subQuestion:r,answer:g[r.id]||"",onChange:e=>w(r.id,e),isReviewMode:f,hintLetters:a},r.id))})]})]}:{className:"flex h-full flex-col gap-4 overflow-y-auto p-6",children:[r("div",{className:"flex flex-col gap-4",children:[e(i,{partNumber:t,questionCount:o,partName:s,isReviewMode:f}),e(l,{instruction:n,isReviewMode:f}),e(d,{letters:a})]}),e("div",{className:"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",children:m.map(r=>e(u,{id:`question-${r.id}`,subQuestion:r,answer:g[r.id]||"",onChange:e=>w(r.id,e),isReviewMode:f,hintLetters:a},r.id))})]})}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { MoversGridFillRendererProps } from '../../types';
|
|
2
|
+
export declare function MoversGridFillRenderer({ partNumber, partName, questionCount, instruction, grid, rows, columns, cellAnswers, answers, onAnswerChange, isReviewMode, caseSensitive, disabledCells, }: MoversGridFillRendererProps): import("react").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as r,Fragment as s}from"react/jsx-runtime";import{Check as n,X as a}from"lucide-react";import t from"../../../../../components/themes/cambridge-yle/CambridgeYlePartBanner";import l from"../../../../../components/themes/cambridge-yle/CambridgeYleInstructionBanner";function d({value:s,isEditable:t,cellKey:l,userAnswer:d,correctAnswer:i,onChange:o,isReviewMode:c,caseSensitive:m=!1}){const g="h-10 w-10 text-lg sm:h-12 sm:w-12 sm:text-xl md:h-14 md:w-14 md:text-2xl lg:h-16 lg:w-16";if(!t)return e("div",{className:`flex items-center justify-center rounded-lg border-2 border-gray-300 bg-gray-100 font-bold text-gray-700 ${g}`,children:s});const h=d||"",u=c&&(m?h===i:h.toLowerCase()===i?.toLowerCase()),b=c&&h&&(m?h!==i:h.toLowerCase()!==i?.toLowerCase());return r("div",{className:"relative",children:[e("input",{type:"text",value:h,onChange:e=>!c&&o(e.target.value.slice(0,2)),disabled:c,maxLength:2,className:`flex items-center justify-center rounded-lg border-2 text-center font-bold outline-none transition-colors ${g} ${c?u?"border-green-500 bg-green-100":b?"border-red-500 bg-red-100":"border-dashed border-gray-400 bg-yellow-50":h?"border-blue-500 bg-blue-50":"border-dashed border-gray-400 bg-white"} ${c?u?"text-green-600":b?"text-red-600":"text-gray-800":"text-gray-800"} ${c?"cursor-default":"cursor-text"}`,placeholder:"?"}),c&&u&&e("span",{className:"absolute -right-1 -top-1 rounded-full bg-green-500 p-0.5",children:e(n,{className:"h-3 w-3 text-white"})}),c&&b&&e("span",{className:"absolute -right-1 -top-1 rounded-full bg-red-500 p-0.5",children:e(a,{className:"h-3 w-3 text-white"})})]})}function i({grid:r,rows:s,columns:n,cellAnswers:a,answers:t,onAnswerChange:l,isReviewMode:i,caseSensitive:o=!1,disabledCells:c=[]}){return e("div",{className:"inline-grid gap-1 sm:gap-1.5 md:gap-2",style:{gridTemplateColumns:`repeat(${n}, minmax(0, 1fr))`},children:r.map((r,s)=>r.map((r,n)=>{const m=`${s+1}-${n+1}`,g=null===r,h=a[m];return c?.includes(m)?e("div",{className:"h-10 w-10 sm:h-12 sm:w-12 md:h-14 md:w-14 lg:h-16 lg:w-16"},m):e(d,{value:r,isEditable:g,cellKey:m,userAnswer:t[m],correctAnswer:h?.correctAnswer,onChange:e=>l(m,e),isReviewMode:i,caseSensitive:o},m)}))})}function o({isReviewMode:n}){return r("div",{className:"flex flex-wrap gap-4 text-sm text-gray-600",children:[r("div",{className:"flex items-center gap-2",children:[e("div",{className:"h-6 w-6 rounded border-2 border-gray-300 bg-gray-100"}),e("span",{children:"Pre-filled"})]}),r("div",{className:"flex items-center gap-2",children:[e("div",{className:"h-6 w-6 rounded border-2 border-dashed border-gray-400 bg-white"}),e("span",{children:"Fill in"})]}),n&&r(s,{children:[r("div",{className:"flex items-center gap-2",children:[e("div",{className:"h-6 w-6 rounded border-2 border-green-500 bg-green-100"}),e("span",{children:"Correct"})]}),r("div",{className:"flex items-center gap-2",children:[e("div",{className:"h-6 w-6 rounded border-2 border-red-500 bg-red-100"}),e("span",{children:"Incorrect"})]})]})]})}function c({cellAnswers:n,answers:a,caseSensitive:t=!1}){const l=Object.entries(n);return r("div",{className:"rounded-lg border border-gray-200 bg-white p-4 shadow-sm",children:[e("p",{className:"mb-3 text-sm font-semibold text-gray-700",children:"Answer Summary:"}),e("div",{className:"grid grid-cols-2 gap-2",children:l.map(([n,{correctAnswer:l}])=>{const d=a[n]||"",i=t?d===l:d.toLowerCase()===l.toLowerCase();return r("div",{className:"flex items-center justify-between rounded px-3 py-1.5 "+(i?"bg-green-50":"bg-red-50"),children:[r("span",{className:"text-sm font-medium text-gray-600",children:["Cell ",n,":"]}),e("div",{className:"flex items-center gap-2",children:i?e("span",{className:"text-sm font-semibold text-green-600",children:d}):r(s,{children:[e("span",{className:"text-sm font-semibold text-red-600 line-through",children:d||"—"}),r("span",{className:"text-sm text-blue-600",children:["→ ",l]})]})})]},n)})})]})}export function MoversGridFillRenderer({partNumber:s,partName:n,questionCount:a,instruction:d,grid:m,rows:g,columns:h,cellAnswers:u,answers:b,onAnswerChange:w,isReviewMode:p=!1,caseSensitive:x=!1,disabledCells:v=[]}){return r("div",{className:"flex h-full flex-col gap-4 overflow-y-auto p-3 sm:gap-5 sm:p-4 md:gap-6 md:p-6",children:[r("div",{className:"flex flex-col gap-4",children:[e(t,{partNumber:s,questionCount:a,partName:n,isReviewMode:p}),e(l,{instruction:d,isReviewMode:p})]}),r("div",{className:"flex flex-col items-center gap-6",children:[e(o,{isReviewMode:p}),e("div",{className:"rounded-xl border-2 border-gray-200 bg-gray-50 p-3 shadow-sm sm:p-4 md:p-6",children:e(i,{grid:m,rows:g,columns:h,cellAnswers:u,answers:b,onAnswerChange:w,isReviewMode:p,caseSensitive:x,disabledCells:v})}),p&&e(c,{cellAnswers:u,answers:b,caseSensitive:x})]})]})}
|
package/dist/components/exams/take/components/question-renderers/MoversLabelThePictureRenderer.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { MoversLabelThePictureRendererProps } from '../../types';
|
|
2
|
+
export declare function MoversLabelThePictureRenderer({ partNumber, partName, questionCount, instruction, imageUrl, wordBank, labels, answers, onAnswerChange, isReviewMode, }: MoversLabelThePictureRendererProps): import("react").JSX.Element;
|