diff --git a/src/interfaces/entity.ts b/src/interfaces/entity.ts index 3cb45e74..da1e8e5e 100644 --- a/src/interfaces/entity.ts +++ b/src/interfaces/entity.ts @@ -3,7 +3,7 @@ import { RolePermission } from "@/resources/entityPermissions"; export interface Entity { id: string; label: string; - licenses: number + licenses: number; } export interface Role { diff --git a/src/pages/stats.tsx b/src/pages/stats.tsx index 36e5a944..6c402baa 100644 --- a/src/pages/stats.tsx +++ b/src/pages/stats.tsx @@ -1,31 +1,31 @@ /* 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, useState} from "react"; +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 useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser"; -import {averageScore, totalExamsByModule, groupBySession, groupByModule, timestampToMoment, groupByDate} from "@/utils/stats"; +import { averageScore, totalExamsByModule, groupBySession, groupByModule, timestampToMoment, groupByDate } from "@/utils/stats"; import useUser from "@/hooks/useUser"; -import {ToastContainer} from "react-toastify"; -import {capitalize, Dictionary} from "lodash"; -import {Module} from "@/interfaces"; +import { ToastContainer } from "react-toastify"; +import { capitalize, Dictionary } from "lodash"; +import { Module } from "@/interfaces"; import ProgressBar from "@/components/Low/ProgressBar"; import Layout from "@/components/High/Layout"; -import {calculateAverageLevel, calculateBandScore} from "@/utils/score"; -import {countExamModules, countFullExams, MODULE_ARRAY, sortByModule} from "@/utils/moduleUtils"; -import {Chart} from "react-chartjs-2"; +import { calculateAverageLevel, calculateBandScore } from "@/utils/score"; +import { countExamModules, countFullExams, MODULE_ARRAY, sortByModule } from "@/utils/moduleUtils"; +import { Chart } from "react-chartjs-2"; import useUsers from "@/hooks/useUsers"; import useGroups from "@/hooks/useGroups"; import DatePicker from "react-datepicker"; -import {shouldRedirectHome} from "@/utils/navigation.disabled"; +import { shouldRedirectHome } from "@/utils/navigation.disabled"; import ProfileSummary from "@/components/ProfileSummary"; import moment from "moment"; -import {Group, Stat, User} from "@/interfaces/user"; -import {Divider} from "primereact/divider"; +import { Group, Stat, User } from "@/interfaces/user"; +import { Divider } from "primereact/divider"; import Badge from "@/components/Low/Badge"; -import { mapBy, redirect, serialize } from "@/utils"; +import { filterBy, mapBy, redirect, serialize } from "@/utils"; import { getEntitiesWithRoles } from "@/utils/entities.be"; import { checkAccess } from "@/utils/permissions"; import { getEntitiesUsers, getUsers } from "@/utils/users.be"; @@ -38,7 +38,7 @@ ChartJS.register(LinearScale, CategoryScale, PointElement, LineElement, LineCont const COLORS = ["#1EB3FF", "#FF790A", "#3D9F11", "#EF5DA8", "#414288"]; -export const getServerSideProps = withIronSessionSsr(async ({req, res}) => { +export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => { const user = await requestUser(req, res) if (!user) return redirect("/login") @@ -50,7 +50,7 @@ export const getServerSideProps = withIronSessionSsr(async ({req, res}) => { const groups = await (checkAccess(user, ["admin", "developer"]) ? getGroups() : getGroupsByEntities(mapBy(entities, 'id'))) return { - props: serialize({user, entities, users, groups}), + props: serialize({ user, entities, users, groups }), }; }, sessionOptions); @@ -66,6 +66,7 @@ export default function Stats({ user, entities, users, groups }: Props) { const [startDate, setStartDate] = useState(moment(new Date()).subtract(1, "weeks").toDate()); const [endDate, setEndDate] = useState(new Date()); const [initialStatDate, setInitialStatDate] = useState(); + const [selectedEntity, setSelectedEntity] = useState() const [monthlyOverallScoreDate, setMonthlyOverallScoreDate] = useState(new Date()); const [monthlyModuleScoreDate, setMonthlyModuleScoreDate] = useState(new Date()); @@ -73,7 +74,12 @@ export default function Stats({ user, entities, users, groups }: Props) { const [dailyScoreDate, setDailyScoreDate] = useState(new Date()); const [intervalDates, setIntervalDates] = useState([]); - const {data: stats} = useFilterRecordsByUser(statsUserId, !statsUserId); + const { data: stats } = useFilterRecordsByUser(statsUserId, !statsUserId); + + const students = useMemo(() => + filterBy(users, 'type', 'student').filter(x => !selectedEntity ? true : mapBy(x.entities, 'id').includes((selectedEntity))), + [users, selectedEntity] + ) useEffect(() => { setInitialStatDate( @@ -181,26 +187,24 @@ export default function Stats({ user, entities, users, groups }: Props) {
- <> - {(user.type === "developer" || user.type === "admin") && ( + {["corporate", "teacher", "mastercorporate", "developer", "admin"].includes(user.type) && ( + <> groups.flatMap((y) => y.participants).includes(x.id)) - .map((x) => ({value: x.id, label: `${x.name} - ${x.email}`}))} - defaultValue={{value: user.id, label: `${user.name} - ${user.email}`}} + options={students + .map((x) => ({ value: x.id, label: `${x.name} - ${x.email}` }))} + defaultValue={{ value: user.id, label: `${user.name} - ${user.email}` }} onChange={(value) => setStatsUserId(value?.value || user.id)} /> - )} - + + )}
{stats.length > 0 && ( @@ -244,8 +248,7 @@ export default function Stats({ user, entities, users, groups }: Props) {
{[...Array(31).keys()].map((day) => { const date = moment( - `${(day + 1).toString().padStart(2, "0")}/${ - moment(monthlyOverallScoreDate).get("month") + 1 + `${(day + 1).toString().padStart(2, "0")}/${moment(monthlyOverallScoreDate).get("month") + 1 }/${moment(monthlyOverallScoreDate).get("year")}`, "DD/MM/yyyy", ); @@ -319,8 +322,7 @@ export default function Stats({ user, entities, users, groups }: Props) { labels: [...Array(31).keys()] .map((day) => { const date = moment( - `${(day + 1).toString().padStart(2, "0")}/${ - moment(monthlyOverallScoreDate).get("month") + 1 + `${(day + 1).toString().padStart(2, "0")}/${moment(monthlyOverallScoreDate).get("month") + 1 }/${moment(monthlyOverallScoreDate).get("year")}`, "DD/MM/yyyy", ); @@ -339,17 +341,16 @@ export default function Stats({ user, entities, users, groups }: Props) { data: [...Array(31).keys()] .map((day) => { const date = moment( - `${(day + 1).toString().padStart(2, "0")}/${ - moment(monthlyOverallScoreDate).get("month") + 1 + `${(day + 1).toString().padStart(2, "0")}/${moment(monthlyOverallScoreDate).get("month") + 1 }/${moment(monthlyOverallScoreDate).get("year")}`, "DD/MM/yyyy", ); return date.isValid() ? calculateTotalScore( - stats.filter((s) => timestampToMoment(s).isBefore(date)), - 5, - ).toFixed(1) + stats.filter((s) => timestampToMoment(s).isBefore(date)), + 5, + ).toFixed(1) : undefined; }) .filter((x) => !!x), @@ -396,7 +397,7 @@ export default function Stats({ user, entities, users, groups }: Props) {
{calculateModuleScore(stats.filter((s) => timestampToMoment(s).isBefore(moment(monthlyModuleScoreDate)))) .sort(sortByModule) - .map(({module, score}) => ( + .map(({ module, score }) => (