/* 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, useMemo, useState } from "react"; import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser"; import { groupByDate } from "@/utils/stats"; import moment from "moment"; import { ToastContainer } from "react-toastify"; import clsx from "clsx"; import { shouldRedirectHome } from "@/utils/navigation.disabled"; import { uuidv4 } from "@firebase/util"; import { usePDFDownload } from "@/hooks/usePDFDownload"; import useRecordStore from "@/stores/recordStore"; import StatsGridItem from "@/components/Medium/StatGridItem"; import RecordFilter from "@/components/Medium/RecordFilter"; import { useRouter } from "next/router"; import useTrainingContentStore from "@/stores/trainingContentStore"; import { Assignment } from "@/interfaces/results"; import { getEntitiesUsers, getUsers } from "@/utils/users.be"; import { getAssignments, getEntitiesAssignments } from "@/utils/assignments.be"; import { findBy, mapBy, redirect, serialize } from "@/utils"; import { getEntitiesWithRoles } from "@/utils/entities.be"; import { checkAccess } from "@/utils/permissions"; import { getGradingSystemByEntities, } from "@/utils/grading.be"; import { Grading } from "@/interfaces"; import { EntityWithRoles } from "@/interfaces/entity"; import CardList from "@/components/High/CardList"; import { requestUser } from "@/utils/api"; import { useAllowedEntities } from "@/hooks/useEntityPermissions"; import getPendingEvals from "@/utils/disabled.be"; import useEvaluationPolling from "@/hooks/useEvaluationPolling"; 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 getEntitiesWithRoles(isAdmin ? undefined : entityIDs); const entitiesIds = mapBy(entities, "id"); const [users, assignments, gradingSystems, pendingSessionIds] = await Promise.all([ isAdmin ? getUsers() : getEntitiesUsers(entitiesIds), isAdmin ? getAssignments() : getEntitiesAssignments(entitiesIds), getGradingSystemByEntities(entitiesIds), getPendingEvals(user.id), ]); return { props: serialize({ user, users, assignments, entities, gradingSystems, isAdmin, pendingSessionIds, }), }; }, sessionOptions); type Filter = "months" | "weeks" | "days" | "assignments" | undefined; interface Props { user: User; users: User[]; assignments: Assignment[]; entities: EntityWithRoles[]; gradingSystems: Grading[]; pendingSessionIds: string[]; isAdmin: boolean; } const MAX_TRAINING_EXAMS = 10; export default function History({ user, users, assignments, entities, gradingSystems, isAdmin, pendingSessionIds, }: Props) { const router = useRouter(); const [statsUserId, setStatsUserId, training, setTraining] = useRecordStore( (state) => [ state.selectedUser, state.setSelectedUser, state.training, state.setTraining, ] ); const [filter, setFilter] = useState(); const { data: stats, isLoading: isStatsLoading } = useFilterRecordsByUser< Stat[] >(statsUserId || user?.id); const allowedDownloadEntities = useAllowedEntities( user, entities, "download_student_record" ); const renderPdfIcon = usePDFDownload("stats"); const [selectedTrainingExams, setSelectedTrainingExams] = useState( [] ); const setTrainingStats = useTrainingContentStore((state) => state.setStats); const groupedStats = useMemo( () => groupByDate( stats.filter((x) => { if ( (x.module === "writing" || x.module === "speaking") && !x.isDisabled && Array.isArray(x.solutions) && !x.solutions.every((y) => Object.keys(y).includes("evaluation")) ) return false; return true; }) ), [stats] ); useEffect(() => setStatsUserId(user.id), [setStatsUserId, user]); useEffect(() => { const handleRouteChange = (url: string) => { setTraining(false); }; router.events.on("routeChangeStart", handleRouteChange); return () => { router.events.off("routeChangeStart", handleRouteChange); }; }, [router.events, setTraining]); const filterStatsByDate = (stats: { [key: string]: Stat[] }) => { if (filter && filter !== "assignments") { 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; } if (filter && filter === "assignments") { const filteredStats: { [key: string]: Stat[] } = {}; Object.keys(stats).forEach((timestamp) => { if ( stats[timestamp] .map((s) => s.assignment === undefined) .includes(false) ) filteredStats[timestamp] = [ ...stats[timestamp].filter((s) => !!s.assignment), ]; }); return filteredStats; } return stats; }; const handleTrainingContentSubmission = () => { if (groupedStats) { const groupedStatsByDate = filterStatsByDate(groupedStats); const allStats = Object.keys(groupedStatsByDate); const selectedStats = selectedTrainingExams.reduce< Record >((accumulator, moduleAndTimestamp) => { const timestamp = moduleAndTimestamp.split("-")[1]; if ( allStats.includes(timestamp) && !accumulator.hasOwnProperty(timestamp) ) { accumulator[timestamp] = groupedStatsByDate[timestamp]; } return accumulator; }, {}); setTrainingStats(Object.values(selectedStats).flat()); router.push("/training"); } }; const filteredStats = useMemo( () => Object.keys(filterStatsByDate(groupedStats)).sort( (a, b) => parseInt(b) - parseInt(a) ), // eslint-disable-next-line react-hooks/exhaustive-deps [groupedStats, filter] ); const customContent = (timestamp: string) => { const dateStats = groupedStats[timestamp]; const statUser = findBy(users, "id", dateStats[0]?.user); const canDownload = mapBy(statUser?.entities, "id").some((e) => mapBy(allowedDownloadEntities, "id").includes(e) ); return ( ); }; useEvaluationPolling( pendingSessionIds ? pendingSessionIds : [], "records", user.id ); return ( <> Record | EnCoach {user && ( <> {training && (
Select up to 10 exercises {`(${selectedTrainingExams.length}/${MAX_TRAINING_EXAMS})`}
)}
{filteredStats.length > 0 && !isStatsLoading && ( )} {filteredStats.length === 0 && !isStatsLoading && ( No record to display... )} {isStatsLoading && (
)} )} ); }