diff --git a/src/dashboards/MasterCorporate.tsx b/src/dashboards/MasterCorporate.tsx index 6c25f391..695e6f7f 100644 --- a/src/dashboards/MasterCorporate.tsx +++ b/src/dashboards/MasterCorporate.tsx @@ -4,9 +4,9 @@ import useStats from "@/hooks/useStats"; import useUsers from "@/hooks/useUsers"; import {CorporateUser, Group, MasterCorporateUser, Stat, User} from "@/interfaces/user"; import UserList from "@/pages/(admin)/Lists/UserList"; -import { dateSorter } from "@/utils"; +import {dateSorter} from "@/utils"; import moment from "moment"; -import { useEffect, useState } from "react"; +import {useEffect, useState} from "react"; import { BsArrowLeft, BsClipboard2Data, @@ -22,7 +22,7 @@ import { BsPlus, BsPersonFillGear, BsFilter, - BsDatabase + BsDatabase, } from "react-icons/bs"; import UserCard from "@/components/UserCard"; import useGroups from "@/hooks/useGroups"; @@ -34,10 +34,10 @@ import {groupByExam} from "@/utils/stats"; import IconCard from "./IconCard"; import GroupList from "@/pages/(admin)/Lists/GroupList"; import useFilterStore from "@/stores/listFilterStore"; -import { useRouter } from "next/router"; +import {useRouter} from "next/router"; import useCodes from "@/hooks/useCodes"; import useAssignments from "@/hooks/useAssignments"; -import { Assignment } from "@/interfaces/results"; +import {Assignment} from "@/interfaces/results"; import AssignmentView from "./AssignmentView"; import AssignmentCreator from "./AssignmentCreator"; import clsx from "clsx"; @@ -54,7 +54,7 @@ import {Popover, PopoverContent, PopoverTrigger} from "@/components/ui/popover"; import MasterStatistical from "./MasterStatistical"; interface Props { - user: MasterCorporateUser; + user: MasterCorporateUser; } const activeFilter = (a: Assignment) => @@ -309,28 +309,18 @@ export default function MasterCorporateDashboard({user}: Props) { const {codes} = useCodes(user.id); const {groups} = useGroups({admin: user.id, userType: user.type}); - const masterCorporateUserGroups = [ - ...new Set( - groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants) - ), - ]; + const masterCorporateUserGroups = [...new Set(groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants))]; - const corporateUserGroups = [ - ...new Set(groups.flatMap((g) => g.participants)), - ]; + const corporateUserGroups = [...new Set(groups.flatMap((g) => g.participants))]; - const { - assignments, - isLoading: isAssignmentsLoading, - reload: reloadAssignments, - } = useAssignments({ corporate: user.id }); + const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({corporate: user.id}); - const appendUserFilters = useFilterStore((state) => state.appendUserFilter); - const router = useRouter(); + const appendUserFilters = useFilterStore((state) => state.appendUserFilter); + const router = useRouter(); - useEffect(() => { - setShowModal(!!selectedUser && page === ""); - }, [selectedUser, page]); + useEffect(() => { + setShowModal(!!selectedUser && page === ""); + }, [selectedUser, page]); useEffect(() => { setCorporateAssignments( @@ -347,135 +337,117 @@ export default function MasterCorporateDashboard({user}: Props) { const teacherFilter = (user: User) => user.type === "teacher" && corporateUserGroups.includes(user.id); const getStatsByStudent = (user: User) => stats.filter((s) => s.user === user.id); - const UserDisplay = (displayUser: User) => ( -
setSelectedUser(displayUser)} - className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300" - > - {displayUser.name} -
- {displayUser.name} - {displayUser.email} -
-
- ); + const UserDisplay = (displayUser: User) => ( +
setSelectedUser(displayUser)} + className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300"> + {displayUser.name} +
+ {displayUser.name} + {displayUser.email} +
+
+ ); - const StudentsList = () => { - const filter = (x: User) => - x.type === "student" && - (!!selectedUser - ? corporateUserGroups.includes(x.id) || false - : corporateUserGroups.includes(x.id)); + const StudentsList = () => { + const filter = (x: User) => + x.type === "student" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id)); - return ( - ( -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" - > - - Back -
-

Students ({total})

-
- )} - /> - ); - }; + return ( + ( +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> + + Back +
+

Students ({total})

+
+ )} + /> + ); + }; - const TeachersList = () => { - const filter = (x: User) => - x.type === "teacher" && - (!!selectedUser - ? corporateUserGroups.includes(x.id) || false - : corporateUserGroups.includes(x.id)); + const TeachersList = () => { + const filter = (x: User) => + x.type === "teacher" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id)); - return ( - ( -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" - > - - Back -
-

Teachers ({total})

-
- )} - /> - ); - }; + return ( + ( +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> + + Back +
+

Teachers ({total})

+
+ )} + /> + ); + }; - const corporateUserFilter = (x: User) => - x.type === "corporate" && - (!!selectedUser - ? masterCorporateUserGroups.includes(x.id) || false - : masterCorporateUserGroups.includes(x.id)); + const corporateUserFilter = (x: User) => + x.type === "corporate" && (!!selectedUser ? masterCorporateUserGroups.includes(x.id) || false : masterCorporateUserGroups.includes(x.id)); - const CorporateList = () => { - return ( - ( -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" - > - - Back -
-

Corporates ({total})

-
- )} - /> - ); - }; + const CorporateList = () => { + return ( + ( +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> + + Back +
+

Corporates ({total})

+
+ )} + /> + ); + }; - const GroupsList = () => { - return ( - <> -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" - > - - Back -
-

Groups ({groups.length})

-
+ const GroupsList = () => { + return ( + <> +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> + + Back +
+

Groups ({groups.length})

+
- - - ); - }; + + + ); + }; - // const AssignmentsPage = () => { - // const activeFilter = (a: Assignment) => - // moment(a.endDate).isAfter(moment()) && - // moment(a.startDate).isBefore(moment()) && - // a.assignees.length > a.results.length; - // const pastFilter = (a: Assignment) => - // (moment(a.endDate).isBefore(moment()) || - // a.assignees.length === a.results.length) && - // !a.archived; - // const archivedFilter = (a: Assignment) => a.archived; - // const futureFilter = (a: Assignment) => - // moment(a.startDate).isAfter(moment()); + // const AssignmentsPage = () => { + // const activeFilter = (a: Assignment) => + // moment(a.endDate).isAfter(moment()) && + // moment(a.startDate).isBefore(moment()) && + // a.assignees.length > a.results.length; + // const pastFilter = (a: Assignment) => + // (moment(a.endDate).isBefore(moment()) || + // a.assignees.length === a.results.length) && + // !a.archived; + // const archivedFilter = (a: Assignment) => a.archived; + // const futureFilter = (a: Assignment) => + // moment(a.startDate).isAfter(moment()); const StudentPerformancePage = () => { const students = users @@ -614,7 +586,7 @@ export default function MasterCorporateDashboard({user}: Props) { allowDownload reload={reloadAssignments} allowArchive - allowExcelDownload + allowExcelDownload /> ))} @@ -631,7 +603,7 @@ export default function MasterCorporateDashboard({user}: Props) { allowDownload reload={reloadAssignments} allowUnarchive - allowExcelDownload + allowExcelDownload /> ))} @@ -640,32 +612,28 @@ export default function MasterCorporateDashboard({user}: Props) { ); }; - const MasterStatisticalPage = () => { - return ( - <> -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" - > - - Back -
-

Master Statistical

-
- { - const user = users.find((u) => u.id === id) as CorporateUser; - if (user) return [...accm, user]; - return accm; - }, - [] - )} - /> - - ); - }; + const MasterStatisticalPage = () => { + return ( + <> +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> + + Back +
+

Master Statistical

+
+ { + const user = users.find((u) => u.id === id) as CorporateUser; + if (user) return [...accm, user]; + return accm; + }, [])} + /> + + ); + }; const DefaultDashboard = () => ( <> @@ -726,13 +694,13 @@ export default function MasterCorporateDashboard({user}: Props) { color="purple" onClick={() => setPage("studentsPerformance")} /> - setPage("statistical")} - /> + setPage("statistical")} + /> -
-
- Latest students -
- {users - .filter(studentFilter) - .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) - .map((x) => ( - - ))} -
-
-
- Latest teachers -
- {users - .filter(teacherFilter) - .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) - .map((x) => ( - - ))} -
-
-
- Highest level students -
- {users - .filter(studentFilter) - .sort( - (a, b) => - calculateAverageLevel(b.levels) - - calculateAverageLevel(a.levels) - ) - .map((x) => ( - - ))} -
-
-
- Highest exam count students -
- {users - .filter(studentFilter) - .sort( - (a, b) => - Object.keys(groupByExam(getStatsByStudent(b))).length - - Object.keys(groupByExam(getStatsByStudent(a))).length - ) - .map((x) => ( - - ))} -
-
-
- - ); +
+
+ Latest students +
+ {users + .filter(studentFilter) + .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) + .map((x) => ( + + ))} +
+
+
+ Latest teachers +
+ {users + .filter(teacherFilter) + .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) + .map((x) => ( + + ))} +
+
+
+ Highest level students +
+ {users + .filter(studentFilter) + .sort((a, b) => calculateAverageLevel(b.levels) - calculateAverageLevel(a.levels)) + .map((x) => ( + + ))} +
+
+
+ Highest exam count students +
+ {users + .filter(studentFilter) + .sort( + (a, b) => + Object.keys(groupByExam(getStatsByStudent(b))).length - Object.keys(groupByExam(getStatsByStudent(a))).length, + ) + .map((x) => ( + + ))} +
+
+
+ + ); - return ( - <> - setSelectedUser(undefined)}> - <> - {selectedUser && ( -
- { - setSelectedUser(undefined); - if (shouldReload) reload(); - }} - onViewStudents={ - selectedUser.type === "corporate" || - selectedUser.type === "teacher" - ? () => { - appendUserFilters({ - id: "view-students", - filter: (x: User) => x.type === "student", - }); - appendUserFilters({ - id: "belongs-to-admin", - filter: (x: User) => - groups - .filter( - (g) => - g.admin === selectedUser.id || - g.participants.includes(selectedUser.id) - ) - .flatMap((g) => g.participants) - .includes(x.id), - }); + return ( + <> + setSelectedUser(undefined)}> + <> + {selectedUser && ( +
+ { + setSelectedUser(undefined); + if (shouldReload) reload(); + }} + onViewStudents={ + selectedUser.type === "corporate" || selectedUser.type === "teacher" + ? () => { + appendUserFilters({ + id: "view-students", + filter: (x: User) => x.type === "student", + }); + appendUserFilters({ + id: "belongs-to-admin", + filter: (x: User) => + groups + .filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id)) + .flatMap((g) => g.participants) + .includes(x.id), + }); - router.push("/list/users"); - } - : undefined - } - onViewTeachers={ - selectedUser.type === "corporate" || - selectedUser.type === "student" - ? () => { - appendUserFilters({ - id: "view-teachers", - filter: (x: User) => x.type === "teacher", - }); - appendUserFilters({ - id: "belongs-to-admin", - filter: (x: User) => - groups - .filter( - (g) => - g.admin === selectedUser.id || - g.participants.includes(selectedUser.id) - ) - .flatMap((g) => g.participants) - .includes(x.id), - }); + router.push("/list/users"); + } + : undefined + } + onViewTeachers={ + selectedUser.type === "corporate" || selectedUser.type === "student" + ? () => { + appendUserFilters({ + id: "view-teachers", + filter: (x: User) => x.type === "teacher", + }); + appendUserFilters({ + id: "belongs-to-admin", + filter: (x: User) => + groups + .filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id)) + .flatMap((g) => g.participants) + .includes(x.id), + }); router.push("/list/users"); } @@ -878,8 +831,8 @@ export default function MasterCorporateDashboard({user}: Props) { {page === "corporate" && } {page === "assignments" && } {page === "studentsPerformance" && } - {page === "statistical" && } + {page === "statistical" && } {page === "" && } ); -} \ No newline at end of file +} diff --git a/src/pages/api/groups/index.ts b/src/pages/api/groups/index.ts index ee5bd098..ede84b30 100644 --- a/src/pages/api/groups/index.ts +++ b/src/pages/api/groups/index.ts @@ -1,94 +1,78 @@ // Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from "next"; -import { app } from "@/firebase"; -import { - getFirestore, - collection, - getDocs, - setDoc, - doc, - query, - where, -} from "firebase/firestore"; -import { withIronSessionApiRoute } from "iron-session/next"; -import { sessionOptions } from "@/lib/session"; -import { Group } from "@/interfaces/user"; -import { v4 } from "uuid"; -import { updateExpiryDateOnGroup, getGroupsForUser } from "@/utils/groups.be"; +import type {NextApiRequest, NextApiResponse} from "next"; +import {app} from "@/firebase"; +import {getFirestore, collection, getDocs, setDoc, doc, query, where} from "firebase/firestore"; +import {withIronSessionApiRoute} from "iron-session/next"; +import {sessionOptions} from "@/lib/session"; +import {Group} from "@/interfaces/user"; +import {v4} from "uuid"; +import {updateExpiryDateOnGroup, getGroupsForUser} from "@/utils/groups.be"; const db = getFirestore(app); export default withIronSessionApiRoute(handler, sessionOptions); async function handler(req: NextApiRequest, res: NextApiResponse) { - if (!req.session.user) { - res.status(401).json({ ok: false }); - return; - } + if (!req.session.user) { + res.status(401).json({ok: false}); + return; + } - if (req.method === "GET") await get(req, res); - if (req.method === "POST") await post(req, res); + if (req.method === "GET") await get(req, res); + if (req.method === "POST") await post(req, res); } async function get(req: NextApiRequest, res: NextApiResponse) { - const { admin, participant } = req.query as { - admin: string; - participant: string; - }; + const {admin, participant} = req.query as { + admin: string; + participant: string; + }; - if (req.session?.user?.type === "mastercorporate") { - try { - const masterCorporateGroups = await getGroupsForUser(admin, participant); - const corporatesFromMaster = masterCorporateGroups - .filter((g) => g.name === "Corporate") - .flatMap((g) => g.participants); + if (req.session?.user?.type === "mastercorporate") { + try { + const masterCorporateGroups = await getGroupsForUser(admin, participant); + const corporatesFromMaster = masterCorporateGroups.filter((g) => g.name === "Corporate").flatMap((g) => g.participants); - if (corporatesFromMaster.length === 0) { - res.status(200).json([]); - return; - } - Promise.all( - corporatesFromMaster.map((c) => getGroupsForUser(c, participant)) - ) - .then((groups) => { - res.status(200).json([...masterCorporateGroups, ...groups.flat()]); - return; - }) - .catch((e) => { - console.error(e); - res.status(500).json({ ok: false }); - return; - }); - } catch (e) { - console.error(e); - res.status(500).json({ ok: false }); - return; - } - return; - } + if (corporatesFromMaster.length === 0) { + res.status(200).json(masterCorporateGroups); + return; + } + Promise.all(corporatesFromMaster.map((c) => getGroupsForUser(c, participant))) + .then((groups) => { + res.status(200).json([...masterCorporateGroups, ...groups.flat()]); + return; + }) + .catch((e) => { + console.error(e); + res.status(500).json({ok: false}); + return; + }); + } catch (e) { + console.error(e); + res.status(500).json({ok: false}); + return; + } + return; + } - try { - const groups = await getGroupsForUser(admin, participant); - res.status(200).json(groups); - } catch (e) { - console.error(e); - res.status(500).json({ ok: false }); - } + try { + const groups = await getGroupsForUser(admin, participant); + res.status(200).json(groups); + } catch (e) { + console.error(e); + res.status(500).json({ok: false}); + } } async function post(req: NextApiRequest, res: NextApiResponse) { - const body = req.body as Group; + const body = req.body as Group; - await Promise.all( - body.participants.map( - async (p) => await updateExpiryDateOnGroup(p, body.admin) - ) - ); + await Promise.all(body.participants.map(async (p) => await updateExpiryDateOnGroup(p, body.admin))); - await setDoc(doc(db, "groups", v4()), { - name: body.name, - admin: body.admin, - participants: body.participants, - }); - res.status(200).json({ ok: true }); + await setDoc(doc(db, "groups", v4()), { + name: body.name, + admin: body.admin, + participants: body.participants, + }); + res.status(200).json({ok: true}); }