Made it so when the timer ends, the module ends
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import {FillBlanksExercise} from "@/interfaces/exam";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
import clsx from "clsx";
|
||||
import {Fragment, useEffect, useState} from "react";
|
||||
import reactStringReplace from "react-string-replace";
|
||||
@@ -79,10 +80,17 @@ export default function FillBlanks({
|
||||
const [currentBlankId, setCurrentBlankId] = useState<string>();
|
||||
const [isDrawerShowing, setIsDrawerShowing] = useState(false);
|
||||
|
||||
const hasExamEnded = useExamStore((state) => state.hasExamEnded);
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => setIsDrawerShowing(!!currentBlankId), 100);
|
||||
}, [currentBlankId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasExamEnded) onNext({exercise: id, solutions: answers, score: calculateScore(), type});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hasExamEnded]);
|
||||
|
||||
const calculateScore = () => {
|
||||
const total = text.match(/({{\d+}})/g)?.length || 0;
|
||||
const correct = answers.filter((x) => solutions.find((y) => x.id === y.id)?.solution === x.solution.toLowerCase() || false).length;
|
||||
|
||||
@@ -3,16 +3,19 @@ import {MatchSentencesExercise} from "@/interfaces/exam";
|
||||
import {mdiArrowLeft, mdiArrowRight} from "@mdi/js";
|
||||
import Icon from "@mdi/react";
|
||||
import clsx from "clsx";
|
||||
import {Fragment, useState} from "react";
|
||||
import {Fragment, useEffect, useState} from "react";
|
||||
import LineTo from "react-lineto";
|
||||
import {CommonProps} from ".";
|
||||
import Button from "../Low/Button";
|
||||
import Xarrow from "react-xarrows";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
|
||||
export default function MatchSentences({id, options, type, prompt, sentences, userSolutions, onNext, onBack}: MatchSentencesExercise & CommonProps) {
|
||||
const [selectedQuestion, setSelectedQuestion] = useState<string>();
|
||||
const [answers, setAnswers] = useState<{question: string; option: string}[]>(userSolutions);
|
||||
|
||||
const hasExamEnded = useExamStore((state) => state.hasExamEnded);
|
||||
|
||||
const calculateScore = () => {
|
||||
const total = sentences.length;
|
||||
const correct = answers.filter((x) => sentences.find((y) => y.id === x.question)?.solution === x.option || false).length;
|
||||
@@ -27,9 +30,11 @@ export default function MatchSentences({id, options, type, prompt, sentences, us
|
||||
setSelectedQuestion(undefined);
|
||||
};
|
||||
|
||||
const getSentenceColor = (id: string) => {
|
||||
return sentences.find((x) => x.id === id)?.color || "";
|
||||
};
|
||||
useEffect(() => {
|
||||
console.log({hasExamEnded});
|
||||
if (hasExamEnded) onNext({exercise: id, solutions: answers, score: calculateScore(), type});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hasExamEnded]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -44,7 +49,7 @@ export default function MatchSentences({id, options, type, prompt, sentences, us
|
||||
</span>
|
||||
<div className="flex gap-8 w-full items-center justify-between bg-mti-gray-smoke rounded-xl px-24 py-6">
|
||||
<div className="flex flex-col gap-4">
|
||||
{sentences.map(({sentence, id, color}) => (
|
||||
{sentences.map(({sentence, id}) => (
|
||||
<div key={`question_${id}`} className="flex items-center justify-end gap-2 cursor-pointer">
|
||||
<span>{sentence} </span>
|
||||
<button
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import {MultipleChoiceExercise, MultipleChoiceQuestion} from "@/interfaces/exam";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
import clsx from "clsx";
|
||||
import {useState} from "react";
|
||||
import {useEffect, useState} from "react";
|
||||
import {CommonProps} from ".";
|
||||
import Button from "../Low/Button";
|
||||
|
||||
@@ -51,6 +52,13 @@ export default function MultipleChoice({id, prompt, type, questions, userSolutio
|
||||
const [answers, setAnswers] = useState<{question: string; option: string}[]>(userSolutions);
|
||||
const [questionIndex, setQuestionIndex] = useState(0);
|
||||
|
||||
const hasExamEnded = useExamStore((state) => state.hasExamEnded);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasExamEnded) onNext({exercise: id, solutions: answers, score: calculateScore(), type});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hasExamEnded]);
|
||||
|
||||
const onSelectOption = (option: string) => {
|
||||
const question = questions[questionIndex];
|
||||
setAnswers((prev) => [...prev.filter((x) => x.question !== question.id), {option, question: question.id}]);
|
||||
|
||||
@@ -4,6 +4,7 @@ import {Fragment, useEffect, useState} from "react";
|
||||
import {BsCheckCircleFill, BsMicFill, BsPauseCircle, BsPlayCircle, BsTrashFill} from "react-icons/bs";
|
||||
import dynamic from "next/dynamic";
|
||||
import Button from "../Low/Button";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
|
||||
const Waveform = dynamic(() => import("../Waveform"), {ssr: false});
|
||||
const ReactMediaRecorder = dynamic(() => import("react-media-recorder").then((mod) => mod.ReactMediaRecorder), {
|
||||
@@ -15,6 +16,20 @@ export default function Speaking({id, title, text, type, prompts, onNext, onBack
|
||||
const [isRecording, setIsRecording] = useState(false);
|
||||
const [mediaBlob, setMediaBlob] = useState<string>();
|
||||
|
||||
const hasExamEnded = useExamStore((state) => state.hasExamEnded);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasExamEnded) {
|
||||
onNext({
|
||||
exercise: id,
|
||||
solutions: mediaBlob ? [{id, solution: mediaBlob}] : [],
|
||||
score: {correct: 1, total: 1, missing: 0},
|
||||
type,
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hasExamEnded]);
|
||||
|
||||
useEffect(() => {
|
||||
let recordingInterval: NodeJS.Timer | undefined = undefined;
|
||||
if (isRecording) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import reactStringReplace from "react-string-replace";
|
||||
import {CommonProps} from ".";
|
||||
import {toast} from "react-toastify";
|
||||
import Button from "../Low/Button";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
|
||||
function Blank({
|
||||
id,
|
||||
@@ -48,6 +49,13 @@ function Blank({
|
||||
export default function WriteBlanks({id, prompt, type, maxWords, solutions, userSolutions, text, onNext, onBack}: WriteBlanksExercise & CommonProps) {
|
||||
const [answers, setAnswers] = useState<{id: string; solution: string}[]>(userSolutions);
|
||||
|
||||
const hasExamEnded = useExamStore((state) => state.hasExamEnded);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasExamEnded) onNext({exercise: id, solutions: answers, score: calculateScore(), type});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hasExamEnded]);
|
||||
|
||||
const calculateScore = () => {
|
||||
const total = text.match(/({{\d+}})/g)?.length || 0;
|
||||
const correct = answers.filter(
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import {errorButtonStyle, infoButtonStyle} from "@/constants/buttonStyles";
|
||||
import {WritingExercise} from "@/interfaces/exam";
|
||||
import {mdiArrowLeft, mdiArrowRight} from "@mdi/js";
|
||||
import Icon from "@mdi/react";
|
||||
import clsx from "clsx";
|
||||
import {CommonProps} from ".";
|
||||
import {Fragment, useEffect, useState} from "react";
|
||||
import {toast} from "react-toastify";
|
||||
import Button from "../Low/Button";
|
||||
import {Dialog, Transition} from "@headlessui/react";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
|
||||
export default function Writing({id, prompt, info, type, wordCounter, attachment, userSolutions, onNext, onBack}: WritingExercise & CommonProps) {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [inputText, setInputText] = useState(userSolutions.length === 1 ? userSolutions[0].solution : "");
|
||||
const [isSubmitEnabled, setIsSubmitEnabled] = useState(false);
|
||||
|
||||
const hasExamEnded = useExamStore((state) => state.hasExamEnded);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasExamEnded) onNext({exercise: id, solutions: [{id, solution: inputText}], score: {correct: 1, total: 1, missing: 0}, type});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hasExamEnded]);
|
||||
|
||||
useEffect(() => {
|
||||
const words = inputText.split(" ").filter((x) => x !== "");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user