/* eslint-disable @next/next/no-img-element */ import Head from "next/head"; import {withIronSessionSsr} from "iron-session/next"; import {sessionOptions} from "@/lib/session"; import {Stat, User} from "@/interfaces/user"; import {useEffect, useState} from "react"; import useStats from "@/hooks/useStats"; import {convertToUserSolutions, groupByDate} from "@/utils/stats"; import moment from "moment"; import useUsers from "@/hooks/useUsers"; import useExamStore from "@/stores/examStore"; import {Module} from "@/interfaces"; import {ToastContainer} from "react-toastify"; import {useRouter} from "next/router"; import {uniqBy} from "lodash"; import {getExamById} from "@/utils/exams"; import {sortByModule} from "@/utils/moduleUtils"; import Layout from "@/components/High/Layout"; import clsx from "clsx"; import {calculateBandScore} from "@/utils/score"; import {BsBook, BsHeadphones, BsMegaphone, BsPen} from "react-icons/bs"; 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 History({user}: {user: User}) { const [selectedUser, setSelectedUser] = useState(user); const [groupedStats, setGroupedStats] = useState<{[key: string]: Stat[]}>(); const [filter, setFilter] = useState<"months" | "weeks" | "days">(); const {users, isLoading: isUsersLoading} = useUsers(); const {stats, isLoading: isStatsLoading} = useStats(selectedUser?.id); const setExams = useExamStore((state) => state.setExams); const setShowSolutions = useExamStore((state) => state.setShowSolutions); const setUserSolutions = useExamStore((state) => state.setUserSolutions); const setSelectedModules = useExamStore((state) => state.setSelectedModules); const router = useRouter(); useEffect(() => { if (stats && !isStatsLoading) { setGroupedStats(groupByDate(stats)); } }, [stats, isStatsLoading]); const toggleFilter = (value: "months" | "weeks" | "days") => { setFilter((prev) => (prev === value ? undefined : value)); }; const filterStatsByDate = (stats: {[key: string]: Stat[]}) => { if (filter) { const filterDate = moment() .subtract({[filter as string]: 1}) .format("x"); const filteredStats: {[key: string]: Stat[]} = {}; Object.keys(stats).forEach((timestamp) => { if (timestamp >= filterDate) filteredStats[timestamp] = stats[timestamp]; }); return filteredStats; } return stats; }; const formatTimestamp = (timestamp: string) => { const date = moment(parseInt(timestamp)); const formatter = "YYYY/MM/DD - HH:mm"; return date.format(formatter); }; const aggregateScoresByModule = (stats: Stat[]): {module: Module; total: number; missing: number; correct: number}[] => { const scores: {[key in Module]: {total: number; missing: number; correct: number}} = { reading: { total: 0, correct: 0, missing: 0, }, listening: { total: 0, correct: 0, missing: 0, }, writing: { total: 0, correct: 0, missing: 0, }, speaking: { total: 0, correct: 0, missing: 0, }, }; stats.forEach((x) => { scores[x.module!] = { total: scores[x.module!].total + x.score.total, correct: scores[x.module!].correct + x.score.correct, missing: scores[x.module!].missing + x.score.missing, }; }); return Object.keys(scores) .filter((x) => scores[x as Module].total > 0) .map((x) => ({module: x as Module, ...scores[x as Module]})); }; const customContent = (timestamp: string) => { if (!groupedStats) return <>; const dateStats = groupedStats[timestamp]; const correct = dateStats.reduce((accumulator, current) => accumulator + current.score.correct, 0); const total = dateStats.reduce((accumulator, current) => accumulator + current.score.total, 0); const aggregatedScores = aggregateScoresByModule(dateStats).filter((x) => x.total > 0); const aggregatedLevels = aggregatedScores.map((x) => ({ module: x.module, level: calculateBandScore(x.correct, x.total, x.module, user.focus), })); const selectExam = () => { const examPromises = uniqBy(dateStats, "exam").map((stat) => getExamById(stat.module, stat.exam)); Promise.all(examPromises).then((exams) => { if (exams.every((x) => !!x)) { setUserSolutions(convertToUserSolutions(dateStats)); setShowSolutions(true); setExams(exams.map((x) => x!).sort(sortByModule)); setSelectedModules( exams .map((x) => x!) .sort(sortByModule) .map((x) => x!.module), ); router.push("/exercises"); } }); }; return (
= 0.7 && "hover:border-mti-purple", correct / total >= 0.3 && correct / total < 0.7 && "hover:border-mti-red", correct / total < 0.3 && "hover:border-mti-orange", )} onClick={selectExam} role="button">
{formatTimestamp(timestamp)} = 0.7 && "text-mti-purple", correct / total >= 0.3 && correct / total < 0.7 && "text-mti-red", correct / total < 0.3 && "text-mti-orange", )}> Level{" "} {(aggregatedLevels.reduce((accumulator, current) => accumulator + current.level, 0) / aggregatedLevels.length).toFixed(1)}
{aggregatedLevels.map(({module, level}) => (
{module === "reading" && } {module === "listening" && } {module === "writing" && } {module === "speaking" && } {level.toFixed(1)}
))}
); }; return ( <> IELTS GPT | Muscat Training Institute {user && (
{!isUsersLoading && user.type !== "student" && ( <> )}
{groupedStats && Object.keys(groupedStats).length > 0 && !isStatsLoading && (
{Object.keys(filterStatsByDate(groupedStats)) .sort((a, b) => parseInt(b) - parseInt(a)) .map(customContent)}
)} {groupedStats && Object.keys(groupedStats).length === 0 && !isStatsLoading && ( No record to display... )}
)} ); }