/* eslint-disable @next/next/no-img-element */ import Head from "next/head"; import { BsArrowClockwise, BsChevronLeft, BsChevronRight, BsFileEarmarkText, BsPencil, BsStar, } from "react-icons/bs"; import { LinearScale, Chart as ChartJS, CategoryScale, PointElement, LineElement, Legend, Tooltip, LineController, } from "chart.js"; import { withIronSessionSsr } from "iron-session/next"; import { sessionOptions } from "@/lib/session"; import { useEffect, useMemo, useState } from "react"; import useStats from "@/hooks/useStats"; import { groupBySession, groupByModule, timestampToMoment, } from "@/utils/stats"; import { ToastContainer } from "react-toastify"; import { capitalize } from "lodash"; import { Module } from "@/interfaces"; import ProgressBar from "@/components/Low/ProgressBar"; import { calculateBandScore } from "@/utils/score"; import { MODULE_ARRAY, sortByModule, } from "@/utils/moduleUtils"; import { Chart } from "react-chartjs-2"; import DatePicker from "react-datepicker"; import { shouldRedirectHome } from "@/utils/navigation.disabled"; import ProfileSummary from "@/components/ProfileSummary"; import moment from "moment"; import { Stat, User } from "@/interfaces/user"; import { Divider } from "primereact/divider"; import Badge from "@/components/Low/Badge"; import { mapBy, redirect, serialize } from "@/utils"; import { getEntities } from "@/utils/entities.be"; import { checkAccess } from "@/utils/permissions"; import { EntityWithRoles } from "@/interfaces/entity"; import Select from "@/components/Low/Select"; import { requestUser } from "@/utils/api"; import useUserData from "../hooks/useUserData"; import useUsersSelect from "../hooks/useUsersSelect"; import AsyncSelect from "../components/Low/AsyncSelect"; ChartJS.register( LinearScale, CategoryScale, PointElement, LineElement, LineController, Legend, Tooltip ); const COLORS = ["#1EB3FF", "#FF790A", "#3D9F11", "#EF5DA8", "#414288"]; export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => { const user = await requestUser(req, res); if (!user) return redirect("/login"); if (shouldRedirectHome(user)) return redirect("/"); const entityIDs = mapBy(user.entities, "id"); const isAdmin = checkAccess(user, ["admin", "developer"]); const entities = await getEntities(isAdmin ? undefined : entityIDs, { id: 1, label: 1, }); return { props: serialize({ user, entities, isAdmin }), }; }, sessionOptions); interface Props { user: User; entities: EntityWithRoles[]; isAdmin: boolean; } export default function Stats({ user, entities, isAdmin }: Props) { const [statsUserId, setStatsUserId] = useState(user.id); const { userData } = useUserData({ userId: statsUserId }); const [startDate, setStartDate] = useState( moment(new Date()).subtract(1, "weeks").toDate() ); const [endDate, setEndDate] = useState(new Date()); const [selectedEntity, setSelectedEntity] = useState(); const entitiesToSearch = useMemo(() => { if (selectedEntity) return [selectedEntity]; if (isAdmin) return undefined; return mapBy(entities, "id"); }, [entities, isAdmin, selectedEntity]); const { users: students, isLoading, onScrollLoadMoreOptions, loadOptions, } = useUsersSelect({ type: "student", size: 50, orderBy: "name", direction: "asc", entities: entitiesToSearch, }); const [monthlyOverallScoreDate, setMonthlyOverallScoreDate] = useState(new Date()); const [monthlyModuleScoreDate, setMonthlyModuleScoreDate] = useState(new Date()); const [dailyScoreDate, setDailyScoreDate] = useState(new Date()); const [intervalDates, setIntervalDates] = useState([]); const { data: { allStats: stats = [], fullExams: exams = 0, uniqueModules: modules = 0, averageScore = 0, }, } = useStats<{ allStats: Stat[]; fullExams: number; uniqueModules: number; averageScore: number; }>(statsUserId, !statsUserId, "stats"); const initialStatDate = useMemo( () => (stats[0] ? timestampToMoment(stats[0]).toDate() : null), [stats] ); const calculateModuleScore = (stats: Stat[]) => { const moduleStats = groupByModule(stats); return Object.keys(moduleStats).map((y) => { const correct = moduleStats[y].reduce( (accumulator, current) => accumulator + current.score.correct, 0 ); const total = moduleStats[y].reduce( (accumulator, current) => accumulator + current.score.total, 0 ); return { module: y as Module, score: calculateBandScore( correct, total, y as Module, user?.focus || "academic" ), }; }); }; const calculateModularScorePerSession = (stats: Stat[], module: Module) => { const groupedBySession = groupBySession(stats); const sessionAverage = Object.keys(groupedBySession).map((x: string) => { const session = groupedBySession[x]; const moduleStats = groupByModule(session); if (!Object.keys(moduleStats).includes(module)) return null; const correct = moduleStats[module].reduce( (acc, curr) => acc + curr.score.correct, 0 ); const total = moduleStats[module].reduce( (acc, curr) => acc + curr.score.total, 0 ); return calculateBandScore( correct, total, module, user?.focus || "academic" ); }); return sessionAverage; }; const getListOfDateInInterval = (start: Date, end: Date) => { let currentDate = moment(start); const dates = [currentDate.toDate()]; while (moment(end).diff(currentDate, "days") > 0) { currentDate = currentDate.add(1, "days"); dates.push(currentDate.toDate()); } return dates; }; useEffect(() => { if (startDate && endDate) { setIntervalDates(getListOfDateInInterval(startDate, endDate)); } }, [startDate, endDate]); const calculateTotalScore = (stats: Stat[], divisionFactor: number) => { const moduleScores = calculateModuleScore(stats); return ( moduleScores.reduce((acc, curr) => acc + curr.score, 0) / divisionFactor ); }; const calculateScorePerModule = (stats: Stat[], module: Module) => { const moduleScores = calculateModuleScore(stats); return moduleScores.find((x) => x.module === module)?.score || -1; }; return ( <> Stats | EnCoach {user && ( <> ), value: exams, label: "Exams", tooltip: "Number of all conducted completed exams", }, { icon: ( ), value: modules, label: "Modules", tooltip: "Number of all exam modules performed including Level Test", }, { icon: ( ), value: `${averageScore.toFixed(2) || 0}%`, label: "Average Score", tooltip: "Average success rate for questions responded", }, ]} />
{[ "corporate", "teacher", "mastercorporate", "developer", "admin", ].includes(user.type) && ( <>