diff --git a/src/dashboards/Agent.tsx b/src/dashboards/Agent.tsx new file mode 100644 index 00000000..a08ba4a6 --- /dev/null +++ b/src/dashboards/Agent.tsx @@ -0,0 +1,274 @@ +/* eslint-disable @next/next/no-img-element */ +import Modal from "@/components/Modal"; +import useStats from "@/hooks/useStats"; +import useUsers from "@/hooks/useUsers"; +import {Group, Stat, User} from "@/interfaces/user"; +import UserList from "@/pages/(admin)/Lists/UserList"; +import {dateSorter} from "@/utils"; +import moment from "moment"; +import {useEffect, useState} from "react"; +import { + BsArrowLeft, + BsClipboard2Data, + BsClipboard2DataFill, + BsClock, + BsGlobeCentralSouthAsia, + BsPaperclip, + BsPerson, + BsPersonAdd, + BsPersonFill, + BsPersonFillGear, + BsPersonGear, + BsPersonLinesFill, +} from "react-icons/bs"; +import UserCard from "@/components/UserCard"; +import useGroups from "@/hooks/useGroups"; +import {calculateAverageLevel, calculateBandScore} from "@/utils/score"; +import {MODULE_ARRAY} from "@/utils/moduleUtils"; +import {Module} from "@/interfaces"; +import {groupByExam} from "@/utils/stats"; +import IconCard from "./IconCard"; +import GroupList from "@/pages/(admin)/Lists/GroupList"; + +interface Props { + user: User; +} + +export default function AgentDashboard({user}: Props) { + const [page, setPage] = useState(""); + const [selectedUser, setSelectedUser] = useState(); + const [showModal, setShowModal] = useState(false); + + const {stats} = useStats(); + const {users, reload} = useUsers(); + const {groups} = useGroups(user.id); + + useEffect(() => { + setShowModal(!!selectedUser && page === ""); + }, [selectedUser, page]); + + const studentFilter = (user: User) => user.type === "student" && groups.flatMap((g) => g.participants).includes(user.id); + const teacherFilter = (user: User) => user.type === "teacher" && groups.flatMap((g) => g.participants).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 StudentsList = () => { + const filter = (x: User) => + x.type === "student" && + (!!selectedUser + ? groups + .filter((g) => g.admin === selectedUser.id) + .flatMap((g) => g.participants) + .includes(x.id) || false + : groups.flatMap((g) => g.participants).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 ({users.filter(filter).length})

+
+ + + + ); + }; + + const TeachersList = () => { + const filter = (x: User) => + x.type === "teacher" && + (!!selectedUser + ? groups + .filter((g) => g.admin === selectedUser.id) + .flatMap((g) => g.participants) + .includes(x.id) || false + : groups.flatMap((g) => g.participants).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 ({users.filter(filter).length})

+
+ + + + ); + }; + + const GroupsList = () => { + const filter = (x: Group) => x.admin === user.id || x.participants.includes(user.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 +
+

Groups ({groups.filter(filter).length})

+
+ + + + ); + }; + + const averageLevelCalculator = (studentStats: Stat[]) => { + const formattedStats = studentStats + .map((s) => ({focus: users.find((u) => u.id === s.user)?.focus, score: s.score, module: s.module})) + .filter((f) => !!f.focus); + const bandScores = formattedStats.map((s) => ({ + module: s.module, + level: calculateBandScore(s.score.correct, s.score.total, s.module, s.focus!), + })); + + const levels: {[key in Module]: number} = {reading: 0, listening: 0, writing: 0, speaking: 0, level: 0}; + bandScores.forEach((b) => (levels[b.module] += b.level)); + + return calculateAverageLevel(levels); + }; + + const DefaultDashboard = () => ( + <> +
+ setPage("students")} + Icon={BsPersonFill} + label="Students" + value={users.filter(studentFilter).length} + color="purple" + /> + setPage("teachers")} + Icon={BsPersonLinesFill} + label="Teachers" + value={users.filter(teacherFilter).length} + color="purple" + /> + groups.flatMap((g) => g.participants).includes(s.user)).length} + color="purple" + /> + groups.flatMap((g) => g.participants).includes(s.user))).toFixed(1)} + color="purple" + /> + setPage("groups")} Icon={BsPersonAdd} label="Groups" value={groups.length} color="purple" /> + +
+ +
+
+ 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" ? () => setPage("students") : undefined + } + onViewTeachers={selectedUser.type === "corporate" ? () => setPage("teachers") : undefined} + user={selectedUser} + /> +
+ )} + +
+ {page === "students" && } + {page === "teachers" && } + {page === "groups" && } + {page === "" && } + + ); +} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 9c0659dc..7160f65e 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -26,6 +26,7 @@ import StudentDashboard from "@/dashboards/Student"; import AdminDashboard from "@/dashboards/Admin"; import CorporateDashboard from "@/dashboards/Corporate"; import TeacherDashboard from "@/dashboards/Teacher"; +import AgentDashboard from "@/dashboards/Agent"; export const getServerSideProps = withIronSessionSsr(({req, res}) => { const user = req.session.user; @@ -166,6 +167,7 @@ export default function Home() { {user.type === "student" && } {user.type === "teacher" && } {user.type === "corporate" && } + {user.type === "agent" && } {user.type === "admin" && } {user.type === "developer" && }