From bd6892dcf1889c1370b63d4f907c3c27762926b2 Mon Sep 17 00:00:00 2001 From: Tiago Ribeiro Date: Mon, 30 Oct 2023 15:01:58 +0000 Subject: [PATCH] Created a dashboard for teachers --- src/dashboards/Teacher.tsx | 220 ++++++++++++++++++++++++++ src/pages/(admin)/Lists/GroupList.tsx | 8 +- src/pages/index.tsx | 3 +- 3 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 src/dashboards/Teacher.tsx diff --git a/src/dashboards/Teacher.tsx b/src/dashboards/Teacher.tsx new file mode 100644 index 00000000..742605a8 --- /dev/null +++ b/src/dashboards/Teacher.tsx @@ -0,0 +1,220 @@ +/* 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 TeacherDashboard({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 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 GroupsList = () => { + const filter = (x: Group) => x.admin === 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}; + 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" + /> + 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")} /> +
+ +
+
+ Latest students +
+ {users + .filter(studentFilter) + .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} + {...selectedUser} + /> +
+ )} + +
+ {page === "students" && } + {page === "groups" && } + {page === "" && } + + ); +} diff --git a/src/pages/(admin)/Lists/GroupList.tsx b/src/pages/(admin)/Lists/GroupList.tsx index 221fcfff..114eea53 100644 --- a/src/pages/(admin)/Lists/GroupList.tsx +++ b/src/pages/(admin)/Lists/GroupList.tsx @@ -290,7 +290,13 @@ export default function GroupList({user}: {user: User}) { x.id === editingID) : undefined} user={user} - users={users} + users={users.filter( + (u) => + groups + .filter((g) => g.admin === user.id) + .flatMap((g) => g.participants) + .includes(u.id) || groups.flatMap((g) => g.participants).includes(u.id), + )} onCreate={(group) => { (!editingID ? createGroup : updateGroup)(group).then((result) => { if (result) { diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 29fa8ba5..e3a4a3bb 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -25,6 +25,7 @@ import ProfileSummary from "@/components/ProfileSummary"; import StudentDashboard from "@/dashboards/Student"; import OwnerDashboard from "@/dashboards/Owner"; import CorporateDashboard from "@/dashboards/Corporate"; +import TeacherDashboard from "@/dashboards/Teacher"; export const getServerSideProps = withIronSessionSsr(({req, res}) => { const user = req.session.user; @@ -163,7 +164,7 @@ export default function Home() { {user && ( {user.type === "student" && } - {user.type === "teacher" && } + {user.type === "teacher" && } {user.type === "corporate" && } {user.type === "owner" && } {user.type === "developer" && }