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 !== "");
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {Module} from "@/interfaces";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
import {moduleLabels} from "@/utils/moduleUtils";
|
||||
import {ReactNode, useEffect, useState} from "react";
|
||||
import {BsBook, BsHeadphones, BsMegaphone, BsPen, BsStopwatch} from "react-icons/bs";
|
||||
@@ -15,6 +16,7 @@ interface Props {
|
||||
|
||||
export default function ModuleTitle({minTimer, module, label, exerciseIndex, totalExercises, disableTimer = false}: Props) {
|
||||
const [timer, setTimer] = useState(minTimer * 60);
|
||||
const setHasExamEnded = useExamStore((state) => state.setHasExamEnded);
|
||||
|
||||
useEffect(() => {
|
||||
if (!disableTimer) {
|
||||
@@ -26,6 +28,10 @@ export default function ModuleTitle({minTimer, module, label, exerciseIndex, tot
|
||||
}
|
||||
}, [disableTimer, minTimer]);
|
||||
|
||||
useEffect(() => {
|
||||
if (timer <= 0) setHasExamEnded(true);
|
||||
}, [setHasExamEnded, timer]);
|
||||
|
||||
const moduleIcon: {[key in Module]: ReactNode} = {
|
||||
reading: <BsBook className="text-ielts-reading w-6 h-6" />,
|
||||
listening: <BsHeadphones className="text-ielts-listening w-6 h-6" />,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {ListeningExam, UserSolution} from "@/interfaces/exam";
|
||||
import {useState} from "react";
|
||||
import {useEffect, useState} from "react";
|
||||
import Icon from "@mdi/react";
|
||||
import {mdiArrowRight} from "@mdi/js";
|
||||
import clsx from "clsx";
|
||||
@@ -10,6 +10,8 @@ import ModuleTitle from "@/components/Medium/ModuleTitle";
|
||||
import AudioPlayer from "@/components/Low/AudioPlayer";
|
||||
import Button from "@/components/Low/Button";
|
||||
import BlankQuestionsModal from "@/components/BlankQuestionsModal";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
import {defaultUserSolutions} from "@/utils/exams";
|
||||
|
||||
interface Props {
|
||||
exam: ListeningExam;
|
||||
@@ -20,9 +22,11 @@ interface Props {
|
||||
export default function Listening({exam, showSolutions = false, onFinish}: Props) {
|
||||
const [exerciseIndex, setExerciseIndex] = useState(-1);
|
||||
const [timesListened, setTimesListened] = useState(0);
|
||||
const [userSolutions, setUserSolutions] = useState<UserSolution[]>([]);
|
||||
const [userSolutions, setUserSolutions] = useState<UserSolution[]>(exam.exercises.map((x) => defaultUserSolutions(x, exam)));
|
||||
const [showBlankModal, setShowBlankModal] = useState(false);
|
||||
|
||||
const hasExamEnded = useExamStore((state) => state.hasExamEnded);
|
||||
|
||||
const confirmFinishModule = (keepGoing?: boolean) => {
|
||||
if (!keepGoing) {
|
||||
setShowBlankModal(false);
|
||||
@@ -37,12 +41,12 @@ export default function Listening({exam, showSolutions = false, onFinish}: Props
|
||||
setUserSolutions((prev) => [...prev.filter((x) => x.exercise !== solution.exercise), solution]);
|
||||
}
|
||||
|
||||
if (exerciseIndex + 1 < exam.exercises.length) {
|
||||
if (exerciseIndex + 1 < exam.exercises.length && !hasExamEnded) {
|
||||
setExerciseIndex((prev) => prev + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!userSolutions.map((x) => x.score.missing).every((x) => x === 0)) {
|
||||
if (!userSolutions.map((x) => x.score.missing).every((x) => x === 0) && !hasExamEnded) {
|
||||
setShowBlankModal(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ import ModuleTitle from "@/components/Medium/ModuleTitle";
|
||||
import {Divider} from "primereact/divider";
|
||||
import Button from "@/components/Low/Button";
|
||||
import BlankQuestionsModal from "@/components/BlankQuestionsModal";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
import {defaultUserSolutions} from "@/utils/exams";
|
||||
|
||||
interface Props {
|
||||
exam: ReadingExam;
|
||||
@@ -80,9 +82,11 @@ function TextModal({isOpen, title, content, onClose}: {isOpen: boolean; title: s
|
||||
export default function Reading({exam, showSolutions = false, onFinish}: Props) {
|
||||
const [exerciseIndex, setExerciseIndex] = useState(-1);
|
||||
const [showTextModal, setShowTextModal] = useState(false);
|
||||
const [userSolutions, setUserSolutions] = useState<UserSolution[]>([]);
|
||||
const [userSolutions, setUserSolutions] = useState<UserSolution[]>(exam.exercises.map((x) => defaultUserSolutions(x, exam)));
|
||||
const [showBlankModal, setShowBlankModal] = useState(false);
|
||||
|
||||
const [hasExamEnded, setHasExamEnded] = useExamStore((state) => [state.hasExamEnded, state.setHasExamEnded]);
|
||||
|
||||
const confirmFinishModule = (keepGoing?: boolean) => {
|
||||
if (!keepGoing) {
|
||||
setShowBlankModal(false);
|
||||
@@ -97,16 +101,18 @@ export default function Reading({exam, showSolutions = false, onFinish}: Props)
|
||||
setUserSolutions((prev) => [...prev.filter((x) => x.exercise !== solution.exercise), solution]);
|
||||
}
|
||||
|
||||
if (exerciseIndex + 1 < exam.exercises.length) {
|
||||
if (exerciseIndex + 1 < exam.exercises.length && !hasExamEnded) {
|
||||
setExerciseIndex((prev) => prev + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!userSolutions.map((x) => x.score.missing).every((x) => x === 0)) {
|
||||
if (!userSolutions.map((x) => x.score.missing).every((x) => x === 0) && !hasExamEnded) {
|
||||
setShowBlankModal(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setHasExamEnded(false);
|
||||
|
||||
if (solution) {
|
||||
onFinish(
|
||||
[...userSolutions.filter((x) => x.exercise !== solution.exercise), solution].map((x) => ({...x, module: "reading", exam: exam.id})),
|
||||
|
||||
@@ -3,6 +3,8 @@ import ModuleTitle from "@/components/Medium/ModuleTitle";
|
||||
import {renderSolution} from "@/components/Solutions";
|
||||
import {infoButtonStyle} from "@/constants/buttonStyles";
|
||||
import {UserSolution, SpeakingExam} from "@/interfaces/exam";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
import {defaultUserSolutions} from "@/utils/exams";
|
||||
import {mdiArrowRight} from "@mdi/js";
|
||||
import Icon from "@mdi/react";
|
||||
import clsx from "clsx";
|
||||
@@ -17,7 +19,7 @@ interface Props {
|
||||
|
||||
export default function Speaking({exam, showSolutions = false, onFinish}: Props) {
|
||||
const [exerciseIndex, setExerciseIndex] = useState(0);
|
||||
const [userSolutions, setUserSolutions] = useState<UserSolution[]>([]);
|
||||
const [userSolutions, setUserSolutions] = useState<UserSolution[]>(exam.exercises.map((x) => defaultUserSolutions(x, exam)));
|
||||
|
||||
const nextExercise = (solution?: UserSolution) => {
|
||||
if (solution) {
|
||||
@@ -29,6 +31,8 @@ export default function Speaking({exam, showSolutions = false, onFinish}: Props)
|
||||
return;
|
||||
}
|
||||
|
||||
if (exerciseIndex >= exam.exercises.length) return;
|
||||
|
||||
if (solution) {
|
||||
onFinish(
|
||||
[...userSolutions.filter((x) => x.exercise !== solution.exercise), solution].map((x) => ({...x, module: "speaking", exam: exam.id})),
|
||||
|
||||
@@ -3,6 +3,8 @@ import ModuleTitle from "@/components/Medium/ModuleTitle";
|
||||
import {renderSolution} from "@/components/Solutions";
|
||||
import {infoButtonStyle} from "@/constants/buttonStyles";
|
||||
import {UserSolution, WritingExam} from "@/interfaces/exam";
|
||||
import useExamStore from "@/stores/examStore";
|
||||
import {defaultUserSolutions} from "@/utils/exams";
|
||||
import {mdiArrowRight} from "@mdi/js";
|
||||
import Icon from "@mdi/react";
|
||||
import clsx from "clsx";
|
||||
@@ -17,7 +19,7 @@ interface Props {
|
||||
|
||||
export default function Writing({exam, showSolutions = false, onFinish}: Props) {
|
||||
const [exerciseIndex, setExerciseIndex] = useState(0);
|
||||
const [userSolutions, setUserSolutions] = useState<UserSolution[]>([]);
|
||||
const [userSolutions, setUserSolutions] = useState<UserSolution[]>(exam.exercises.map((x) => defaultUserSolutions(x, exam)));
|
||||
|
||||
const nextExercise = (solution?: UserSolution) => {
|
||||
if (solution) {
|
||||
@@ -29,6 +31,8 @@ export default function Writing({exam, showSolutions = false, onFinish}: Props)
|
||||
return;
|
||||
}
|
||||
|
||||
if (exerciseIndex >= exam.exercises.length) return;
|
||||
|
||||
if (solution) {
|
||||
onFinish(
|
||||
[...userSolutions.filter((x) => x.exercise !== solution.exercise), solution].map((x) => ({...x, module: "writing", exam: exam.id})),
|
||||
|
||||
@@ -32,7 +32,15 @@ async function login(req: NextApiRequest, res: NextApiResponse) {
|
||||
const userId = userCredentials.user.uid;
|
||||
delete req.body.password;
|
||||
|
||||
const user = {...req.body, desiredLevels: DEFAULT_DESIRED_LEVELS, levels: DEFAULT_LEVELS, bio: "", isFirstLogin: true};
|
||||
const user = {
|
||||
...req.body,
|
||||
desiredLevels: DEFAULT_DESIRED_LEVELS,
|
||||
levels: DEFAULT_LEVELS,
|
||||
bio: "",
|
||||
isFirstLogin: true,
|
||||
focus: "academic",
|
||||
type: "student",
|
||||
};
|
||||
|
||||
await setDoc(doc(db, "users", userId), user);
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ export default function Page() {
|
||||
const [userSolutions, setUserSolutions] = useExamStore((state) => [state.userSolutions, state.setUserSolutions]);
|
||||
const [showSolutions, setShowSolutions] = useExamStore((state) => [state.showSolutions, state.setShowSolutions]);
|
||||
const [selectedModules, setSelectedModules] = useExamStore((state) => [state.selectedModules, state.setSelectedModules]);
|
||||
const setHasExamEnded = useExamStore((state) => state.setHasExamEnded);
|
||||
|
||||
const {user} = useUser({redirectTo: "/login"});
|
||||
|
||||
|
||||
@@ -201,6 +201,11 @@ export default function Page() {
|
||||
|
||||
const onFinish = (solutions: UserSolution[]) => {
|
||||
const solutionIds = solutions.map((x) => x.exercise);
|
||||
const solutionExams = solutions.map((x) => x.exam);
|
||||
|
||||
console.log(solutionExams, exam?.id, moduleIndex, selectedModules);
|
||||
|
||||
if (exam && !solutionExams.includes(exam.id)) return;
|
||||
|
||||
if (exam && (exam.module === "writing" || exam.module === "speaking") && solutions.length > 0 && !showSolutions) {
|
||||
setHasBeenUploaded(true);
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import {Module} from "@/interfaces";
|
||||
import {Exam, UserSolution} from "@/interfaces/exam";
|
||||
import {Stat} from "@/interfaces/user";
|
||||
import {create} from "zustand";
|
||||
|
||||
export interface ExamState {
|
||||
exams: Exam[];
|
||||
userSolutions: UserSolution[];
|
||||
showSolutions: boolean;
|
||||
hasExamEnded: boolean;
|
||||
selectedModules: Module[];
|
||||
setHasExamEnded: (hasExamEnded: boolean) => void;
|
||||
setUserSolutions: (userSolutions: UserSolution[]) => void;
|
||||
setExams: (exams: Exam[]) => void;
|
||||
setShowSolutions: (showSolutions: boolean) => void;
|
||||
@@ -20,6 +21,7 @@ export const initialState = {
|
||||
userSolutions: [],
|
||||
showSolutions: false,
|
||||
selectedModules: [],
|
||||
hasExamEnded: false,
|
||||
};
|
||||
|
||||
const useExamStore = create<ExamState>((set) => ({
|
||||
@@ -28,6 +30,7 @@ const useExamStore = create<ExamState>((set) => ({
|
||||
setExams: (exams: Exam[]) => set(() => ({exams})),
|
||||
setShowSolutions: (showSolutions: boolean) => set(() => ({showSolutions})),
|
||||
setSelectedModules: (modules: Module[]) => set(() => ({selectedModules: modules})),
|
||||
setHasExamEnded: (hasExamEnded: boolean) => set(() => ({hasExamEnded})),
|
||||
reset: () => set(() => initialState),
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import {Module} from "@/interfaces";
|
||||
import {Exam, ReadingExam, ListeningExam, WritingExam, SpeakingExam} from "@/interfaces/exam";
|
||||
import {
|
||||
Exam,
|
||||
ReadingExam,
|
||||
ListeningExam,
|
||||
WritingExam,
|
||||
SpeakingExam,
|
||||
Exercise,
|
||||
UserSolution,
|
||||
FillBlanksExercise,
|
||||
MatchSentencesExercise,
|
||||
} from "@/interfaces/exam";
|
||||
import axios from "axios";
|
||||
|
||||
export const getExamById = async (module: Module, id: string): Promise<Exam | undefined> => {
|
||||
@@ -21,3 +31,37 @@ export const getExamById = async (module: Module, id: string): Promise<Exam | un
|
||||
return newExam as SpeakingExam;
|
||||
}
|
||||
};
|
||||
|
||||
export const defaultUserSolutions = (exercise: Exercise, exam: Exam): UserSolution => {
|
||||
const defaultSettings = {
|
||||
exam: exam.id,
|
||||
exercise: exercise.id,
|
||||
solutions: [],
|
||||
module: exam.module,
|
||||
type: exercise.type,
|
||||
};
|
||||
|
||||
let total = 0;
|
||||
switch (exercise.type) {
|
||||
case "fillBlanks":
|
||||
total = exercise.text.match(/({{\d+}})/g)?.length || 0;
|
||||
return {...defaultSettings, score: {correct: 0, total, missing: total}};
|
||||
case "matchSentences":
|
||||
total = exercise.sentences.length;
|
||||
return {...defaultSettings, score: {correct: 0, total, missing: total}};
|
||||
case "multipleChoice":
|
||||
total = exercise.questions.length;
|
||||
return {...defaultSettings, score: {correct: 0, total, missing: total}};
|
||||
case "writeBlanks":
|
||||
total = exercise.text.match(/({{\d+}})/g)?.length || 0;
|
||||
return {...defaultSettings, score: {correct: 0, total, missing: total}};
|
||||
case "writing":
|
||||
total = 1;
|
||||
return {...defaultSettings, score: {correct: 0, total, missing: total}};
|
||||
case "speaking":
|
||||
total = 1;
|
||||
return {...defaultSettings, score: {correct: 0, total, missing: total}};
|
||||
default:
|
||||
return {...defaultSettings, score: {correct: 0, total: 0, missing: 0}};
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user