/* eslint-disable @next/next/no-img-element */ import Head from "next/head"; import Navbar from "@/components/Navbar"; import {useEffect, useState} from "react"; import {Module} from "@/interfaces"; import Selection from "@/exams/Selection"; import Reading from "@/exams/Reading"; import {Exam, ListeningExam, ReadingExam, SpeakingExam, UserSolution, WritingExam} from "@/interfaces/exam"; import Listening from "@/exams/Listening"; import Writing from "@/exams/Writing"; import {ToastContainer, toast} from "react-toastify"; import Finish from "@/exams/Finish"; import axios from "axios"; import {withIronSessionSsr} from "iron-session/next"; import {sessionOptions} from "@/lib/session"; import {Stat, User} from "@/interfaces/user"; import Speaking from "@/exams/Speaking"; import {v4 as uuidv4} from "uuid"; import useUser from "@/hooks/useUser"; import useExamStore, {ExamState} from "@/stores/examStore"; export const getServerSideProps = withIronSessionSsr(({req, res}) => { const user = req.session.user; if (!user) { res.setHeader("location", "/login"); res.statusCode = 302; res.end(); return { props: { user: null, }, }; } return { props: {user: req.session.user}, }; }, sessionOptions); export default function Page() { const [hasBeenUploaded, setHasBeenUploaded] = useState(false); const [moduleIndex, setModuleIndex] = useState(0); const [sessionId, setSessionId] = useState(""); const [exam, setExam] = useState(); const [timer, setTimer] = useState(-1); const [exams, setExams] = useExamStore((state) => [state.exams, state.setExams]); 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 {user} = useUser({redirectTo: "/login"}); useEffect(() => setSessionId(uuidv4()), []); useEffect(() => { (async () => { if (selectedModules.length > 0 && exams.length > 0 && moduleIndex < selectedModules.length) { const nextExam = exams[moduleIndex]; setExam(nextExam ? updateExamWithUserSolutions(nextExam) : undefined); } })(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedModules, moduleIndex, exams]); useEffect(() => { (async () => { if (selectedModules.length > 0) { const examPromises = selectedModules.map(getExam); Promise.all(examPromises).then((values) => { if (values.every((x) => !!x)) { setExams(values.map((x) => x!)); } }); } })(); }, [selectedModules, setExams]); useEffect(() => { (async () => { if (selectedModules.length > 0 && moduleIndex >= selectedModules.length && !hasBeenUploaded) { const newStats: Stat[] = userSolutions.map((solution) => ({ ...solution, session: sessionId, exam: solution.exam!, module: solution.module!, user: user?.id || "", date: new Date().getTime(), })); axios .post<{ok: boolean}>("/api/stats", newStats) .then((response) => setHasBeenUploaded(response.data.ok)) .catch(() => setHasBeenUploaded(false)); } })(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedModules, moduleIndex, hasBeenUploaded]); useEffect(() => { if (exam) { setTimer(exam.minTimer * 60); const timerInterval = setInterval(() => setTimer((prev) => (prev && prev > 0 ? prev - 1 : 0)), 1000); return () => { clearInterval(timerInterval); }; } }, [exam]); const getExam = async (module: Module): Promise => { const examRequest = await axios(`/api/exam/${module}`); if (examRequest.status !== 200) { toast.error("Something went wrong!"); return undefined; } const newExam = examRequest.data; switch (module) { case "reading": return newExam.shift() as ReadingExam; case "listening": return newExam.shift() as ListeningExam; case "writing": return newExam.shift() as WritingExam; case "speaking": return newExam.shift() as SpeakingExam; } }; const updateExamWithUserSolutions = (exam: Exam): Exam => { const exercises = exam.exercises.map((x) => Object.assign(x, !x.userSolutions ? {userSolutions: userSolutions.find((y) => x.id === y.exercise)?.solutions} : x.userSolutions), ); return Object.assign(exam, exercises); }; const onFinish = (solutions: UserSolution[]) => { const solutionIds = solutions.map((x) => x.exercise); setUserSolutions([...userSolutions.filter((x) => !solutionIds.includes(x.exercise)), ...solutions]); setModuleIndex((prev) => prev + 1); }; const renderScreen = () => { if (selectedModules.length === 0) { return ; } if (moduleIndex >= selectedModules.length) { return ( { setShowSolutions(true); setModuleIndex(0); setExam(exams[0]); }} scores={userSolutions.map((x) => ({...x.score, module: x.module}))} /> ); } if (exam && exam.module === "reading") { return ; } if (exam && exam.module === "listening") { return ; } if (exam && exam.module === "writing" && showSolutions) { setModuleIndex((prev) => prev + 1); return <>; } if (exam && exam.module === "writing") { return ; } if (exam && exam.module === "speaking" && showSolutions) { setModuleIndex((prev) => prev + 1); return <>; } if (exam && exam.module === "speaking") { return ; } return <>Loading...; }; return ( <> Exam | IELTS GPT {user && (
{renderScreen()}
)} ); }