diff --git a/src/dashboards/AssignmentCreator.tsx b/src/dashboards/AssignmentCreator.tsx index 445193d9..bf1f9c41 100644 --- a/src/dashboards/AssignmentCreator.tsx +++ b/src/dashboards/AssignmentCreator.tsx @@ -24,14 +24,13 @@ import useExams from "@/hooks/useExams"; interface Props { isCreating: boolean; - assigner: string; users: User[]; groups: Group[]; assignment?: Assignment; cancelCreation: () => void; } -export default function AssignmentCreator({isCreating, assignment, assigner, groups, users, cancelCreation}: Props) { +export default function AssignmentCreator({isCreating, assignment, groups, users, cancelCreation}: Props) { const [selectedModules, setSelectedModules] = useState(assignment?.exams.map((e) => e.module) || []); const [assignees, setAssignees] = useState(assignment?.assignees || []); const [name, setName] = useState( diff --git a/src/dashboards/Corporate.tsx b/src/dashboards/Corporate.tsx index 2f0c0f5e..481f12e1 100644 --- a/src/dashboards/Corporate.tsx +++ b/src/dashboards/Corporate.tsx @@ -2,805 +2,641 @@ import Modal from "@/components/Modal"; import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser"; import useUsers from "@/hooks/useUsers"; -import { CorporateUser, Group, Stat, User } from "@/interfaces/user"; +import {CorporateUser, Group, 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, useMemo, useState} from "react"; import { - BsArrowLeft, - BsClipboard2Data, - BsClipboard2DataFill, - BsClock, - BsGlobeCentralSouthAsia, - BsPaperclip, - BsPerson, - BsPersonAdd, - BsPersonFill, - BsPersonFillGear, - BsPersonGear, - BsPencilSquare, - BsPersonBadge, - BsPersonCheck, - BsPeople, - BsArrowRepeat, - BsPlus, - BsEnvelopePaper, + BsArrowLeft, + BsClipboard2Data, + BsClipboard2DataFill, + BsClock, + BsGlobeCentralSouthAsia, + BsPaperclip, + BsPerson, + BsPersonAdd, + BsPersonFill, + BsPersonFillGear, + BsPersonGear, + BsPencilSquare, + BsPersonBadge, + BsPersonCheck, + BsPeople, + BsArrowRepeat, + BsPlus, + BsEnvelopePaper, } from "react-icons/bs"; import UserCard from "@/components/UserCard"; import useGroups from "@/hooks/useGroups"; -import { - averageLevelCalculator, - calculateAverageLevel, - calculateBandScore, -} from "@/utils/score"; -import { MODULE_ARRAY } from "@/utils/moduleUtils"; -import { Module } from "@/interfaces"; -import { groupByExam } from "@/utils/stats"; +import {averageLevelCalculator, 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"; import useFilterStore from "@/stores/listFilterStore"; -import { useRouter } from "next/router"; +import {useRouter} from "next/router"; import useCodes from "@/hooks/useCodes"; -import { getUserCorporate } from "@/utils/groups"; +import {getUserCorporate} from "@/utils/groups"; 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"; import AssignmentCard from "./AssignmentCard"; -import { createColumnHelper } from "@tanstack/react-table"; +import {createColumnHelper} from "@tanstack/react-table"; import Checkbox from "@/components/Low/Checkbox"; import List from "@/components/List"; -import { getUserCompanyName } from "@/resources/user"; -import { - futureAssignmentFilter, - pastAssignmentFilter, - archivedAssignmentFilter, - activeAssignmentFilter, -} from "@/utils/assignments"; +import {getUserCompanyName} from "@/resources/user"; +import {futureAssignmentFilter, pastAssignmentFilter, archivedAssignmentFilter, activeAssignmentFilter} from "@/utils/assignments"; import useUserBalance from "@/hooks/useUserBalance"; interface Props { - user: CorporateUser; + user: CorporateUser; } -type StudentPerformanceItem = User & { corporateName: string; group: string }; -const StudentPerformanceList = ({ - items, - stats, - users, -}: { - items: StudentPerformanceItem[]; - stats: Stat[]; - users: User[]; -}) => { - const [isShowingAmount, setIsShowingAmount] = useState(false); +type StudentPerformanceItem = User & {corporateName: string; group: string}; +const StudentPerformanceList = ({items, stats, users}: {items: StudentPerformanceItem[]; stats: Stat[]; users: User[]}) => { + const [isShowingAmount, setIsShowingAmount] = useState(false); - const columnHelper = createColumnHelper(); + const columnHelper = createColumnHelper(); - const columns = [ - columnHelper.accessor("name", { - header: "Student Name", - cell: (info) => info.getValue(), - }), - columnHelper.accessor("email", { - header: "E-mail", - cell: (info) => info.getValue(), - }), - columnHelper.accessor("demographicInformation.passport_id", { - header: "ID", - cell: (info) => info.getValue() || "N/A", - }), - columnHelper.accessor("group", { - header: "Group", - cell: (info) => info.getValue(), - }), - columnHelper.accessor("corporateName", { - header: "Corporate", - cell: (info) => info.getValue() || "N/A", - }), - columnHelper.accessor("levels.reading", { - header: "Reading", - cell: (info) => - !isShowingAmount - ? info.getValue() || 0 - : `${ - Object.keys( - groupByExam( - stats.filter( - (x) => - x.module === "reading" && x.user === info.row.original.id - ) - ) - ).length - } exams`, - }), - columnHelper.accessor("levels.listening", { - header: "Listening", - cell: (info) => - !isShowingAmount - ? info.getValue() || 0 - : `${ - Object.keys( - groupByExam( - stats.filter( - (x) => - x.module === "listening" && - x.user === info.row.original.id - ) - ) - ).length - } exams`, - }), - columnHelper.accessor("levels.writing", { - header: "Writing", - cell: (info) => - !isShowingAmount - ? info.getValue() || 0 - : `${ - Object.keys( - groupByExam( - stats.filter( - (x) => - x.module === "writing" && x.user === info.row.original.id - ) - ) - ).length - } exams`, - }), - columnHelper.accessor("levels.speaking", { - header: "Speaking", - cell: (info) => - !isShowingAmount - ? info.getValue() || 0 - : `${ - Object.keys( - groupByExam( - stats.filter( - (x) => - x.module === "speaking" && x.user === info.row.original.id - ) - ) - ).length - } exams`, - }), - columnHelper.accessor("levels.level", { - header: "Level", - cell: (info) => - !isShowingAmount - ? info.getValue() || 0 - : `${ - Object.keys( - groupByExam( - stats.filter( - (x) => - x.module === "level" && x.user === info.row.original.id - ) - ) - ).length - } exams`, - }), - columnHelper.accessor("levels", { - id: "overall_level", - header: "Overall", - cell: (info) => - !isShowingAmount - ? averageLevelCalculator( - users, - stats.filter((x) => x.user === info.row.original.id) - ).toFixed(1) - : `${ - Object.keys( - groupByExam( - stats.filter((x) => x.user === info.row.original.id) - ) - ).length - } exams`, - }), - ]; + const columns = [ + columnHelper.accessor("name", { + header: "Student Name", + cell: (info) => info.getValue(), + }), + columnHelper.accessor("email", { + header: "E-mail", + cell: (info) => info.getValue(), + }), + columnHelper.accessor("demographicInformation.passport_id", { + header: "ID", + cell: (info) => info.getValue() || "N/A", + }), + columnHelper.accessor("group", { + header: "Group", + cell: (info) => info.getValue(), + }), + columnHelper.accessor("corporateName", { + header: "Corporate", + cell: (info) => info.getValue() || "N/A", + }), + columnHelper.accessor("levels.reading", { + header: "Reading", + cell: (info) => + !isShowingAmount + ? info.getValue() || 0 + : `${Object.keys(groupByExam(stats.filter((x) => x.module === "reading" && x.user === info.row.original.id))).length} exams`, + }), + columnHelper.accessor("levels.listening", { + header: "Listening", + cell: (info) => + !isShowingAmount + ? info.getValue() || 0 + : `${Object.keys(groupByExam(stats.filter((x) => x.module === "listening" && x.user === info.row.original.id))).length} exams`, + }), + columnHelper.accessor("levels.writing", { + header: "Writing", + cell: (info) => + !isShowingAmount + ? info.getValue() || 0 + : `${Object.keys(groupByExam(stats.filter((x) => x.module === "writing" && x.user === info.row.original.id))).length} exams`, + }), + columnHelper.accessor("levels.speaking", { + header: "Speaking", + cell: (info) => + !isShowingAmount + ? info.getValue() || 0 + : `${Object.keys(groupByExam(stats.filter((x) => x.module === "speaking" && x.user === info.row.original.id))).length} exams`, + }), + columnHelper.accessor("levels.level", { + header: "Level", + cell: (info) => + !isShowingAmount + ? info.getValue() || 0 + : `${Object.keys(groupByExam(stats.filter((x) => x.module === "level" && x.user === info.row.original.id))).length} exams`, + }), + columnHelper.accessor("levels", { + id: "overall_level", + header: "Overall", + cell: (info) => + !isShowingAmount + ? averageLevelCalculator( + users, + stats.filter((x) => x.user === info.row.original.id), + ).toFixed(1) + : `${Object.keys(groupByExam(stats.filter((x) => x.user === info.row.original.id))).length} exams`, + }), + ]; - return ( -
- - Show Utilization - - - data={items.sort( - (a, b) => - averageLevelCalculator( - users, - stats.filter((x) => x.user === b.id) - ) - - averageLevelCalculator( - users, - stats.filter((x) => x.user === a.id) - ) - )} - columns={columns} - /> -
- ); + return ( +
+ + Show Utilization + + + data={items.sort( + (a, b) => + averageLevelCalculator( + users, + stats.filter((x) => x.user === b.id), + ) - + averageLevelCalculator( + users, + stats.filter((x) => x.user === a.id), + ), + )} + columns={columns} + /> +
+ ); }; -export default function CorporateDashboard({ user }: Props) { - const [page, setPage] = useState(""); - const [selectedUser, setSelectedUser] = useState(); - const [showModal, setShowModal] = useState(false); - const [corporateUserToShow, setCorporateUserToShow] = - useState(); - const [selectedAssignment, setSelectedAssignment] = useState(); - const [isCreatingAssignment, setIsCreatingAssignment] = useState(false); +export default function CorporateDashboard({user}: Props) { + const [page, setPage] = useState(""); + const [selectedUser, setSelectedUser] = useState(); + const [showModal, setShowModal] = useState(false); + const [corporateUserToShow, setCorporateUserToShow] = useState(); + const [selectedAssignment, setSelectedAssignment] = useState(); + const [isCreatingAssignment, setIsCreatingAssignment] = useState(false); - const { data: stats } = useFilterRecordsByUser(); - const { users, reload, isLoading } = useUsers(); - const { codes } = useCodes(user.id); - const { groups } = useGroups({ admin: user.id }); - const { - assignments, - isLoading: isAssignmentsLoading, - reload: reloadAssignments, - } = useAssignments({ corporate: user.id }); - const { balance } = useUserBalance(); + const {data: stats} = useFilterRecordsByUser(); + const {users, reload, isLoading} = useUsers(); + const {codes} = useCodes(user.id); + const {groups} = useGroups({admin: user.id}); + const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({corporate: user.id}); + const {balance} = useUserBalance(); - const appendUserFilters = useFilterStore((state) => state.appendUserFilter); - const router = useRouter(); + const appendUserFilters = useFilterStore((state) => state.appendUserFilter); + const router = useRouter(); - useEffect(() => { - setShowModal(!!selectedUser && page === ""); - }, [selectedUser, page]); + const assignmentsGroups = useMemo(() => groups.filter((x) => x.admin === user.id || x.participants.includes(user.id)), [groups, user.id]); - useEffect(() => { - // in this case it fetches the master corporate account - getUserCorporate(user.id).then(setCorporateUserToShow); - }, [user]); + const assignmentsUsers = useMemo( + () => + users.filter( + (x) => + 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)), + ), + [groups, users, selectedUser], + ); - 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); + useEffect(() => { + setShowModal(!!selectedUser && page === ""); + }, [selectedUser, page]); - const getStatsByStudent = (user: User) => - stats.filter((s) => s.user === user.id); + useEffect(() => { + // in this case it fetches the master corporate account + getUserCorporate(user.id).then(setCorporateUserToShow); + }, [user]); - 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 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 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)); + const getStatsByStudent = (user: User) => stats.filter((s) => s.user === 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 -
-

Students ({total})

-
- )} - /> - ); - }; + 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 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)); + 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 -
-

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 +
+

Students ({total})

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

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

-
+ 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 GroupsList = () => { + const filter = (x: Group) => x.admin === user.id || x.participants.includes(user.id); - const AssignmentsPage = () => { - return ( - <> - { - setSelectedAssignment(undefined); - setIsCreatingAssignment(false); - reloadAssignments(); - }} - assignment={selectedAssignment} - /> - x.admin === user.id || x.participants.includes(user.id) - )} - users={users.filter( - (x) => - 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)) - )} - assigner={user.id} - isCreating={isCreatingAssignment} - cancelCreation={() => { - setIsCreatingAssignment(false); - setSelectedAssignment(undefined); - reloadAssignments(); - }} - /> -
-
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 -
-
- Reload - -
-
-
-

- Active Assignments ( - {assignments.filter(activeAssignmentFilter).length}) -

-
- {assignments.filter(activeAssignmentFilter).map((a) => ( - setSelectedAssignment(a)} - key={a.id} - /> - ))} -
-
-
-

- Planned Assignments ( - {assignments.filter(futureAssignmentFilter).length}) -

-
-
setIsCreatingAssignment(true)} - className="w-[250px] h-[200px] flex flex-col gap-2 items-center justify-center bg-white hover:bg-mti-purple-ultralight text-mti-purple-light hover:text-mti-purple-dark border border-mti-gray-platinum hover:drop-shadow p-4 cursor-pointer rounded-xl transition ease-in-out duration-300" - > - - New Assignment -
- {assignments.filter(futureAssignmentFilter).map((a) => ( - { - setSelectedAssignment(a); - setIsCreatingAssignment(true); - }} - key={a.id} - /> - ))} -
-
-
-

- Past Assignments ({assignments.filter(pastAssignmentFilter).length}) -

-
- {assignments.filter(pastAssignmentFilter).map((a) => ( - setSelectedAssignment(a)} - key={a.id} - allowDownload - reload={reloadAssignments} - allowArchive - allowExcelDownload - /> - ))} -
-
-
-

- Archived Assignments ( - {assignments.filter(archivedAssignmentFilter).length}) -

-
- {assignments.filter(archivedAssignmentFilter).map((a) => ( - setSelectedAssignment(a)} - key={a.id} - allowDownload - reload={reloadAssignments} - allowUnarchive - allowExcelDownload - /> - ))} -
-
- - ); - }; + 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 StudentPerformancePage = () => { - const students = users - .filter( - (x) => - x.type === "student" && - groups.flatMap((g) => g.participants).includes(x.id) - ) - .map((u) => ({ - ...u, - group: groups.find((x) => x.participants.includes(u.id))?.name || "N/A", - corporateName: getUserCompanyName(u, users, groups), - })); + + + ); + }; - 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 -
-
- Reload - -
-
- - - ); - }; + const AssignmentsPage = () => { + return ( + <> + { + setSelectedAssignment(undefined); + setIsCreatingAssignment(false); + reloadAssignments(); + }} + assignment={selectedAssignment} + /> + { + setIsCreatingAssignment(false); + setSelectedAssignment(undefined); + reloadAssignments(); + }} + /> +
+
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 +
+
+ Reload + +
+
+
+

Active Assignments ({assignments.filter(activeAssignmentFilter).length})

+
+ {assignments.filter(activeAssignmentFilter).map((a) => ( + setSelectedAssignment(a)} key={a.id} /> + ))} +
+
+
+

Planned Assignments ({assignments.filter(futureAssignmentFilter).length})

+
+
setIsCreatingAssignment(true)} + className="w-[250px] h-[200px] flex flex-col gap-2 items-center justify-center bg-white hover:bg-mti-purple-ultralight text-mti-purple-light hover:text-mti-purple-dark border border-mti-gray-platinum hover:drop-shadow p-4 cursor-pointer rounded-xl transition ease-in-out duration-300"> + + New Assignment +
+ {assignments.filter(futureAssignmentFilter).map((a) => ( + { + setSelectedAssignment(a); + setIsCreatingAssignment(true); + }} + key={a.id} + /> + ))} +
+
+
+

Past Assignments ({assignments.filter(pastAssignmentFilter).length})

+
+ {assignments.filter(pastAssignmentFilter).map((a) => ( + setSelectedAssignment(a)} + key={a.id} + allowDownload + reload={reloadAssignments} + allowArchive + allowExcelDownload + /> + ))} +
+
+
+

Archived Assignments ({assignments.filter(archivedAssignmentFilter).length})

+
+ {assignments.filter(archivedAssignmentFilter).map((a) => ( + setSelectedAssignment(a)} + key={a.id} + allowDownload + reload={reloadAssignments} + allowUnarchive + allowExcelDownload + /> + ))} +
+
+ + ); + }; - 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 StudentPerformancePage = () => { + const students = users + .filter((x) => x.type === "student" && groups.flatMap((g) => g.participants).includes(x.id)) + .map((u) => ({ + ...u, + group: groups.find((x) => x.participants.includes(u.id))?.name || "N/A", + corporateName: getUserCompanyName(u, users, groups), + })); - 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 ( + <> +
+
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 +
+
+ Reload + +
+
+ + + ); + }; - return calculateAverageLevel(levels); - }; + 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 DefaultDashboard = () => ( - <> - {corporateUserToShow && ( -
- Linked to:{" "} - - {corporateUserToShow?.corporateInformation?.companyInformation - .name || corporateUserToShow.name} - -
- )} -
- setPage("students")} - Icon={BsPersonFill} - label="Students" - value={users.filter(studentFilter).length} - color="purple" - /> - setPage("teachers")} - Icon={BsPencilSquare} - 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={BsPeople} - label="Groups" - value={groups.length} - color="purple" - /> - - - setPage("studentsPerformance")} - /> - -
+ const levels: {[key in Module]: number} = { + reading: 0, + listening: 0, + writing: 0, + speaking: 0, + level: 0, + }; + bandScores.forEach((b) => (levels[b.module] += b.level)); -
-
- 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 calculateAverageLevel(levels); + }; - 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), - }); + const DefaultDashboard = () => ( + <> + {corporateUserToShow && ( +
+ Linked to: {corporateUserToShow?.corporateInformation?.companyInformation.name || corporateUserToShow.name} +
+ )} +
+ setPage("students")} + Icon={BsPersonFill} + label="Students" + value={users.filter(studentFilter).length} + color="purple" + /> + setPage("teachers")} + Icon={BsPencilSquare} + 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={BsPeople} label="Groups" value={groups.length} color="purple" /> + + + setPage("studentsPerformance")} + /> + +
- 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), - }); +
+
+ 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) => ( + + ))} +
+
+
+ + ); - router.push("/list/users"); - } - : undefined - } - user={selectedUser} - /> -
- )} - -
- {page === "students" && } - {page === "teachers" && } - {page === "groups" && } - {page === "assignments" && } - {page === "studentsPerformance" && } - {page === "" && } - - ); + 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 + } + user={selectedUser} + /> +
+ )} + +
+ {page === "students" && } + {page === "teachers" && } + {page === "groups" && } + {page === "assignments" && } + {page === "studentsPerformance" && } + {page === "" && } + + ); } diff --git a/src/dashboards/MasterCorporate.tsx b/src/dashboards/MasterCorporate.tsx index 7770e8c1..f3dd3534 100644 --- a/src/dashboards/MasterCorporate.tsx +++ b/src/dashboards/MasterCorporate.tsx @@ -2,1102 +2,841 @@ import Modal from "@/components/Modal"; import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser"; import useUsers from "@/hooks/useUsers"; -import { - CorporateUser, - Group, - MasterCorporateUser, - Stat, - User, -} from "@/interfaces/user"; +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, useMemo } from "react"; +import {useEffect, useState, useMemo} from "react"; import { - BsArrowLeft, - BsClipboard2Data, - BsClock, - BsPaperclip, - BsPersonFill, - BsPencilSquare, - BsPersonCheck, - BsPeople, - BsBank, - BsEnvelopePaper, - BsArrowRepeat, - BsPlus, - BsPersonFillGear, - BsFilter, - BsDatabase, + BsArrowLeft, + BsClipboard2Data, + BsClock, + BsPaperclip, + BsPersonFill, + BsPencilSquare, + BsPersonCheck, + BsPeople, + BsBank, + BsEnvelopePaper, + BsArrowRepeat, + BsPlus, + BsPersonFillGear, + BsFilter, + BsDatabase, } from "react-icons/bs"; import UserCard from "@/components/UserCard"; import useGroups from "@/hooks/useGroups"; -import { - averageLevelCalculator, - calculateAverageLevel, - calculateBandScore, -} from "@/utils/score"; -import { MODULE_ARRAY } from "@/utils/moduleUtils"; -import { Module } from "@/interfaces"; -import { groupByExam } from "@/utils/stats"; +import {averageLevelCalculator, 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"; 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"; import AssignmentCard from "./AssignmentCard"; -import { createColumn, createColumnHelper } from "@tanstack/react-table"; +import {createColumn, createColumnHelper} from "@tanstack/react-table"; import List from "@/components/List"; -import { getUserCorporate } from "@/utils/groups"; -import { getCorporateUser, getUserCompanyName } from "@/resources/user"; +import {getUserCorporate} from "@/utils/groups"; +import {getCorporateUser, getUserCompanyName} from "@/resources/user"; import Checkbox from "@/components/Low/Checkbox"; -import { groupBy, uniq, uniqBy } from "lodash"; +import {groupBy, uniq, uniqBy} from "lodash"; import Select from "@/components/Low/Select"; -import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; +import {Menu, MenuButton, MenuItem, MenuItems} from "@headlessui/react"; +import {Popover, PopoverContent, PopoverTrigger} from "@/components/ui/popover"; import MasterStatistical from "./MasterStatistical"; -import { - futureAssignmentFilter, - pastAssignmentFilter, - archivedAssignmentFilter, - activeAssignmentFilter, -} from "@/utils/assignments"; +import {futureAssignmentFilter, pastAssignmentFilter, archivedAssignmentFilter, activeAssignmentFilter} from "@/utils/assignments"; import useUserBalance from "@/hooks/useUserBalance"; interface Props { - user: MasterCorporateUser; + user: MasterCorporateUser; } type StudentPerformanceItem = User & { - corporate?: CorporateUser; - group?: Group; + corporate?: CorporateUser; + group?: Group; }; -const StudentPerformanceList = ({ - items, - stats, - users, - groups, -}: { - items: StudentPerformanceItem[]; - stats: Stat[]; - users: User[]; - groups: Group[]; -}) => { - const [isShowingAmount, setIsShowingAmount] = useState(false); - const [availableCorporates] = useState( - uniqBy( - items.map((x) => x.corporate), - "id" - ) - ); - const [availableGroups] = useState( - uniqBy( - items.map((x) => x.group), - "id" - ) - ); +const StudentPerformanceList = ({items, stats, users, groups}: {items: StudentPerformanceItem[]; stats: Stat[]; users: User[]; groups: Group[]}) => { + const [isShowingAmount, setIsShowingAmount] = useState(false); + const [availableCorporates] = useState( + uniqBy( + items.map((x) => x.corporate), + "id", + ), + ); + const [availableGroups] = useState( + uniqBy( + items.map((x) => x.group), + "id", + ), + ); - const [selectedCorporate, setSelectedCorporate] = useState< - CorporateUser | null | undefined - >(null); - const [selectedGroup, setSelectedGroup] = useState( - null - ); + const [selectedCorporate, setSelectedCorporate] = useState(null); + const [selectedGroup, setSelectedGroup] = useState(null); - const columnHelper = createColumnHelper(); + const columnHelper = createColumnHelper(); - const columns = [ - columnHelper.accessor("name", { - header: "Student Name", - cell: (info) => info.getValue(), - }), - columnHelper.accessor("email", { - header: "E-mail", - cell: (info) => info.getValue(), - }), - columnHelper.accessor("demographicInformation.passport_id", { - header: "ID", - cell: (info) => info.getValue() || "N/A", - }), - columnHelper.accessor("group", { - header: "Group", - cell: (info) => info.getValue()?.name || "N/A", - }), - columnHelper.accessor("corporate", { - header: "Corporate", - cell: (info) => - !!info.getValue() - ? getUserCompanyName(info.getValue() as User, users, groups) - : "N/A", - }), - columnHelper.accessor("levels.reading", { - header: "Reading", - cell: (info) => - !isShowingAmount - ? calculateBandScore( - stats - .filter( - (x) => - x.module === "reading" && x.user === info.row.original.id - ) - .reduce((acc, curr) => acc + curr.score.correct, 0), - stats - .filter( - (x) => - x.module === "reading" && x.user === info.row.original.id - ) - .reduce((acc, curr) => acc + curr.score.total, 0), - "level", - info.row.original.focus || "academic" - ) || 0 - : `${ - Object.keys( - groupByExam( - stats.filter( - (x) => - x.module === "reading" && x.user === info.row.original.id - ) - ) - ).length - } exams`, - }), - columnHelper.accessor("levels.listening", { - header: "Listening", - cell: (info) => - !isShowingAmount - ? calculateBandScore( - stats - .filter( - (x) => - x.module === "listening" && x.user === info.row.original.id - ) - .reduce((acc, curr) => acc + curr.score.correct, 0), - stats - .filter( - (x) => - x.module === "listening" && x.user === info.row.original.id - ) - .reduce((acc, curr) => acc + curr.score.total, 0), - "level", - info.row.original.focus || "academic" - ) || 0 - : `${ - Object.keys( - groupByExam( - stats.filter( - (x) => - x.module === "listening" && - x.user === info.row.original.id - ) - ) - ).length - } exams`, - }), - columnHelper.accessor("levels.writing", { - header: "Writing", - cell: (info) => - !isShowingAmount - ? calculateBandScore( - stats - .filter( - (x) => - x.module === "writing" && x.user === info.row.original.id - ) - .reduce((acc, curr) => acc + curr.score.correct, 0), - stats - .filter( - (x) => - x.module === "writing" && x.user === info.row.original.id - ) - .reduce((acc, curr) => acc + curr.score.total, 0), - "level", - info.row.original.focus || "academic" - ) || 0 - : `${ - Object.keys( - groupByExam( - stats.filter( - (x) => - x.module === "writing" && x.user === info.row.original.id - ) - ) - ).length - } exams`, - }), - columnHelper.accessor("levels.speaking", { - header: "Speaking", - cell: (info) => - !isShowingAmount - ? calculateBandScore( - stats - .filter( - (x) => - x.module === "speaking" && x.user === info.row.original.id - ) - .reduce((acc, curr) => acc + curr.score.correct, 0), - stats - .filter( - (x) => - x.module === "speaking" && x.user === info.row.original.id - ) - .reduce((acc, curr) => acc + curr.score.total, 0), - "level", - info.row.original.focus || "academic" - ) || 0 - : `${ - Object.keys( - groupByExam( - stats.filter( - (x) => - x.module === "speaking" && x.user === info.row.original.id - ) - ) - ).length - } exams`, - }), - columnHelper.accessor("levels.level", { - header: "Level", - cell: (info) => - !isShowingAmount - ? calculateBandScore( - stats - .filter( - (x) => x.module === "level" && x.user === info.row.original.id - ) - .reduce((acc, curr) => acc + curr.score.correct, 0), - stats - .filter( - (x) => x.module === "level" && x.user === info.row.original.id - ) - .reduce((acc, curr) => acc + curr.score.total, 0), - "level", - info.row.original.focus || "academic" - ) || 0 - : `${ - Object.keys( - groupByExam( - stats.filter( - (x) => - x.module === "level" && x.user === info.row.original.id - ) - ) - ).length - } exams`, - }), - columnHelper.accessor("levels", { - id: "overall_level", - header: "Overall", - cell: (info) => - !isShowingAmount - ? averageLevelCalculator( - users, - stats.filter((x) => x.user === info.row.original.id) - ).toFixed(1) - : `${ - Object.keys( - groupByExam( - stats.filter((x) => x.user === info.row.original.id) - ) - ).length - } exams`, - }), - ]; + const columns = [ + columnHelper.accessor("name", { + header: "Student Name", + cell: (info) => info.getValue(), + }), + columnHelper.accessor("email", { + header: "E-mail", + cell: (info) => info.getValue(), + }), + columnHelper.accessor("demographicInformation.passport_id", { + header: "ID", + cell: (info) => info.getValue() || "N/A", + }), + columnHelper.accessor("group", { + header: "Group", + cell: (info) => info.getValue()?.name || "N/A", + }), + columnHelper.accessor("corporate", { + header: "Corporate", + cell: (info) => (!!info.getValue() ? getUserCompanyName(info.getValue() as User, users, groups) : "N/A"), + }), + columnHelper.accessor("levels.reading", { + header: "Reading", + cell: (info) => + !isShowingAmount + ? calculateBandScore( + stats + .filter((x) => x.module === "reading" && x.user === info.row.original.id) + .reduce((acc, curr) => acc + curr.score.correct, 0), + stats + .filter((x) => x.module === "reading" && x.user === info.row.original.id) + .reduce((acc, curr) => acc + curr.score.total, 0), + "level", + info.row.original.focus || "academic", + ) || 0 + : `${Object.keys(groupByExam(stats.filter((x) => x.module === "reading" && x.user === info.row.original.id))).length} exams`, + }), + columnHelper.accessor("levels.listening", { + header: "Listening", + cell: (info) => + !isShowingAmount + ? calculateBandScore( + stats + .filter((x) => x.module === "listening" && x.user === info.row.original.id) + .reduce((acc, curr) => acc + curr.score.correct, 0), + stats + .filter((x) => x.module === "listening" && x.user === info.row.original.id) + .reduce((acc, curr) => acc + curr.score.total, 0), + "level", + info.row.original.focus || "academic", + ) || 0 + : `${Object.keys(groupByExam(stats.filter((x) => x.module === "listening" && x.user === info.row.original.id))).length} exams`, + }), + columnHelper.accessor("levels.writing", { + header: "Writing", + cell: (info) => + !isShowingAmount + ? calculateBandScore( + stats + .filter((x) => x.module === "writing" && x.user === info.row.original.id) + .reduce((acc, curr) => acc + curr.score.correct, 0), + stats + .filter((x) => x.module === "writing" && x.user === info.row.original.id) + .reduce((acc, curr) => acc + curr.score.total, 0), + "level", + info.row.original.focus || "academic", + ) || 0 + : `${Object.keys(groupByExam(stats.filter((x) => x.module === "writing" && x.user === info.row.original.id))).length} exams`, + }), + columnHelper.accessor("levels.speaking", { + header: "Speaking", + cell: (info) => + !isShowingAmount + ? calculateBandScore( + stats + .filter((x) => x.module === "speaking" && x.user === info.row.original.id) + .reduce((acc, curr) => acc + curr.score.correct, 0), + stats + .filter((x) => x.module === "speaking" && x.user === info.row.original.id) + .reduce((acc, curr) => acc + curr.score.total, 0), + "level", + info.row.original.focus || "academic", + ) || 0 + : `${Object.keys(groupByExam(stats.filter((x) => x.module === "speaking" && x.user === info.row.original.id))).length} exams`, + }), + columnHelper.accessor("levels.level", { + header: "Level", + cell: (info) => + !isShowingAmount + ? calculateBandScore( + stats + .filter((x) => x.module === "level" && x.user === info.row.original.id) + .reduce((acc, curr) => acc + curr.score.correct, 0), + stats + .filter((x) => x.module === "level" && x.user === info.row.original.id) + .reduce((acc, curr) => acc + curr.score.total, 0), + "level", + info.row.original.focus || "academic", + ) || 0 + : `${Object.keys(groupByExam(stats.filter((x) => x.module === "level" && x.user === info.row.original.id))).length} exams`, + }), + columnHelper.accessor("levels", { + id: "overall_level", + header: "Overall", + cell: (info) => + !isShowingAmount + ? averageLevelCalculator( + users, + stats.filter((x) => x.user === info.row.original.id), + ).toFixed(1) + : `${Object.keys(groupByExam(stats.filter((x) => x.user === info.row.original.id))).length} exams`, + }), + ]; - const filterUsers = (data: StudentPerformanceItem[]) => { - console.log(data, selectedCorporate); - const filterByCorporate = (item: StudentPerformanceItem) => - item.corporate?.id === selectedCorporate?.id; - const filterByGroup = (item: StudentPerformanceItem) => - item.group?.id === selectedGroup?.id; + const filterUsers = (data: StudentPerformanceItem[]) => { + console.log(data, selectedCorporate); + const filterByCorporate = (item: StudentPerformanceItem) => item.corporate?.id === selectedCorporate?.id; + const filterByGroup = (item: StudentPerformanceItem) => item.group?.id === selectedGroup?.id; - const filters: ((item: StudentPerformanceItem) => boolean)[] = []; - if (selectedCorporate !== null) filters.push(filterByCorporate); - if (selectedGroup !== null) filters.push(filterByGroup); + const filters: ((item: StudentPerformanceItem) => boolean)[] = []; + if (selectedCorporate !== null) filters.push(filterByCorporate); + if (selectedGroup !== null) filters.push(filterByGroup); - return filters.reduce((d, f) => d.filter(f), data); - }; + return filters.reduce((d, f) => d.filter(f), data); + }; - return ( -
-
- - Show Utilization - - - -
- -
-
- -
- Filters - ({ - value: x?.id || "N/A", - label: x?.name || "N/A", - }))} - isClearable - value={ - selectedGroup === null - ? null - : { - value: selectedGroup?.id || "N/A", - label: selectedGroup?.name || "N/A", - } - } - placeholder="Select a Group..." - onChange={(value) => - !value - ? setSelectedGroup(null) - : setSelectedGroup( - value.value === "N/A" - ? undefined - : availableGroups.find((x) => x?.id === value.value) - ) - } - /> -
-
-
-
- - data={filterUsers( - items.sort( - (a, b) => - averageLevelCalculator( - users, - stats.filter((x) => x.user === b.id) - ) - - averageLevelCalculator( - users, - stats.filter((x) => x.user === a.id) - ) - ) - )} - columns={columns} - /> -
- ); + return ( +
+
+ + Show Utilization + + + +
+ +
+
+ +
+ Filters + ({ + value: x?.id || "N/A", + label: x?.name || "N/A", + }))} + isClearable + value={ + selectedGroup === null + ? null + : { + value: selectedGroup?.id || "N/A", + label: selectedGroup?.name || "N/A", + } + } + placeholder="Select a Group..." + onChange={(value) => + !value + ? setSelectedGroup(null) + : setSelectedGroup(value.value === "N/A" ? undefined : availableGroups.find((x) => x?.id === value.value)) + } + /> +
+
+
+
+ + data={filterUsers( + items.sort( + (a, b) => + averageLevelCalculator( + users, + stats.filter((x) => x.user === b.id), + ) - + averageLevelCalculator( + users, + stats.filter((x) => x.user === a.id), + ), + ), + )} + columns={columns} + /> +
+ ); }; -export default function MasterCorporateDashboard({ user }: Props) { - const [page, setPage] = useState(""); - const [selectedUser, setSelectedUser] = useState(); - const [showModal, setShowModal] = useState(false); - const [selectedAssignment, setSelectedAssignment] = useState(); - const [isCreatingAssignment, setIsCreatingAssignment] = useState(false); - const [corporateAssignments, setCorporateAssignments] = useState< - (Assignment & { corporate?: CorporateUser })[] - >([]); +export default function MasterCorporateDashboard({user}: Props) { + const [page, setPage] = useState(""); + const [selectedUser, setSelectedUser] = useState(); + const [showModal, setShowModal] = useState(false); + const [selectedAssignment, setSelectedAssignment] = useState(); + const [isCreatingAssignment, setIsCreatingAssignment] = useState(false); + const [corporateAssignments, setCorporateAssignments] = useState<(Assignment & {corporate?: CorporateUser})[]>([]); - const { data: stats } = useFilterRecordsByUser(); - const { users, reload } = useUsers(); - const { groups } = useGroups({ admin: user.id, userType: user.type }); - const { balance } = useUserBalance(); + const {data: stats} = useFilterRecordsByUser(); + const {users, reload} = useUsers(); + const {groups} = useGroups({admin: user.id, userType: user.type}); + const {balance} = useUserBalance(); - const masterCorporateUserGroups = useMemo(() => [ - ...new Set( - groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants) - ), - ], [groups, user.id]); + const masterCorporateUserGroups = useMemo( + () => [...new Set(groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants))], + [groups, user.id], + ); - const corporateUserGroups = useMemo(() => [ - ...new Set(groups.flatMap((g) => g.participants)), - ], [groups]) + const corporateUserGroups = useMemo(() => [...new Set(groups.flatMap((g) => g.participants))], [groups]); - 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 assignmentsGroups = useMemo(() => groups.filter((x) => x.admin === user.id || x.participants.includes(user.id)), [groups, user.id]); + const assignmentsUsers = useMemo( + () => + users.filter( + (x) => + 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)), + ), + [groups, users, selectedUser], + ); - useEffect(() => { - setShowModal(!!selectedUser && page === ""); - }, [selectedUser, page]); + const appendUserFilters = useFilterStore((state) => state.appendUserFilter); + const router = useRouter(); - useEffect(() => { - setCorporateAssignments( - assignments.filter(activeAssignmentFilter).map((a) => ({ - ...a, - corporate: !!users.find((x) => x.id === a.assigner) - ? getCorporateUser( - users.find((x) => x.id === a.assigner)!, - users, - groups - ) - : undefined, - })) - ); - }, [assignments, groups, users]); + useEffect(() => { + setShowModal(!!selectedUser && page === ""); + }, [selectedUser, page]); - const studentFilter = (user: User) => - user.type === "student" && corporateUserGroups.includes(user.id); - const teacherFilter = (user: User) => - user.type === "teacher" && corporateUserGroups.includes(user.id); - const getStatsByStudent = (user: User) => - stats.filter((s) => s.user === user.id); + useEffect(() => { + setCorporateAssignments( + assignments.filter(activeAssignmentFilter).map((a) => ({ + ...a, + corporate: !!users.find((x) => x.id === a.assigner) + ? getCorporateUser(users.find((x) => x.id === a.assigner)!, users, groups) + : undefined, + })), + ); + }, [assignments, groups, users]); - 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 studentFilter = (user: User) => user.type === "student" && corporateUserGroups.includes(user.id); + const teacherFilter = (user: User) => user.type === "teacher" && corporateUserGroups.includes(user.id); + const getStatsByStudent = (user: User) => stats.filter((s) => s.user === user.id); - const StudentsList = () => { - const filter = (x: User) => - x.type === "student" && - (!!selectedUser - ? corporateUserGroups.includes(x.id) || false - : corporateUserGroups.includes(x.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} +
+
+ ); - 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 StudentsList = () => { + const filter = (x: User) => + x.type === "student" && (!!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 +
+

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 -
-

Teachers ({total})

-
- )} - /> - ); - }; + const TeachersList = () => { + const filter = (x: User) => + x.type === "teacher" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id)); - const corporateUserFilter = (x: User) => - x.type === "corporate" && - (!!selectedUser - ? masterCorporateUserGroups.includes(x.id) || false - : masterCorporateUserGroups.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})

+
+ )} + /> + ); + }; - 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 corporateUserFilter = (x: User) => + x.type === "corporate" && (!!selectedUser ? masterCorporateUserGroups.includes(x.id) || false : masterCorporateUserGroups.includes(x.id)); - 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 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 StudentPerformancePage = () => { - const students = users - .filter( - (x) => - x.type === "student" && - groups.flatMap((g) => g.participants).includes(x.id) - ) - .map((u) => ({ - ...u, - group: groups.find((x) => x.participants.includes(u.id)), - corporate: getCorporateUser(u, users, groups), - })); + + + ); + }; - 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 -
-
- Reload - -
-
- - - ); - }; + const StudentPerformancePage = () => { + const students = users + .filter((x) => x.type === "student" && groups.flatMap((g) => g.participants).includes(x.id)) + .map((u) => ({ + ...u, + group: groups.find((x) => x.participants.includes(u.id)), + corporate: getCorporateUser(u, users, groups), + })); - const AssignmentsPage = () => { - return ( - <> - { - setSelectedAssignment(undefined); - setIsCreatingAssignment(false); - reloadAssignments(); - }} - assignment={selectedAssignment} - /> - x.admin === user.id || x.participants.includes(user.id) - )} - users={users.filter( - (x) => - 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)) - )} - assigner={user.id} - isCreating={isCreatingAssignment} - cancelCreation={() => { - setIsCreatingAssignment(false); - setSelectedAssignment(undefined); - reloadAssignments(); - }} - /> -
-
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 -
-
- Reload - -
-
-
- Active Assignments Status -
- - Total:{" "} - {assignments - .filter(activeAssignmentFilter) - .reduce((acc, curr) => acc + curr.results.length, 0)} - / - {assignments - .filter(activeAssignmentFilter) - .reduce((acc, curr) => curr.exams.length + acc, 0)} - - {Object.keys( - groupBy(corporateAssignments, (x) => x.corporate?.id) - ).map((x) => ( -
- - {getUserCompanyName( - users.find((u) => u.id === x)!, - users, - groups - )} - :{" "} - - - {groupBy(corporateAssignments, (x) => x.corporate?.id)[ - x - ].reduce((acc, curr) => curr.results.length + acc, 0)} - / - {groupBy(corporateAssignments, (x) => x.corporate?.id)[ - x - ].reduce((acc, curr) => curr.exams.length + acc, 0)} - -
- ))} -
-
-
-

- Active Assignments ( - {assignments.filter(activeAssignmentFilter).length}) -

-
- {assignments.filter(activeAssignmentFilter).map((a) => ( - setSelectedAssignment(a)} - key={a.id} - /> - ))} -
-
-
-

- Planned Assignments ( - {assignments.filter(futureAssignmentFilter).length}) -

-
-
setIsCreatingAssignment(true)} - className="w-[250px] h-[200px] flex flex-col gap-2 items-center justify-center bg-white hover:bg-mti-purple-ultralight text-mti-purple-light hover:text-mti-purple-dark border border-mti-gray-platinum hover:drop-shadow p-4 cursor-pointer rounded-xl transition ease-in-out duration-300" - > - - New Assignment -
- {assignments.filter(futureAssignmentFilter).map((a) => ( - { - setSelectedAssignment(a); - setIsCreatingAssignment(true); - }} - key={a.id} - /> - ))} -
-
-
-

- Past Assignments ({assignments.filter(pastAssignmentFilter).length}) -

-
- {assignments.filter(pastAssignmentFilter).map((a) => ( - setSelectedAssignment(a)} - key={a.id} - allowDownload - reload={reloadAssignments} - allowArchive - allowExcelDownload - /> - ))} -
-
-
-

- Archived Assignments ( - {assignments.filter(archivedAssignmentFilter).length}) -

-
- {assignments.filter(archivedAssignmentFilter).map((a) => ( - setSelectedAssignment(a)} - key={a.id} - allowDownload - reload={reloadAssignments} - allowUnarchive - allowExcelDownload - /> - ))} -
-
- - ); - }; + 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 +
+
+ Reload + +
+
+ + + ); + }; - const masterCorporateUsers = useMemo( - () => - masterCorporateUserGroups.reduce((accm: CorporateUser[], id) => { - const user = users.find((u) => u.id === id) as CorporateUser; - if (user) return [...accm, user]; - return accm; - }, []), - [masterCorporateUserGroups, users] - ); + const AssignmentsPage = () => { + return ( + <> + { + setSelectedAssignment(undefined); + setIsCreatingAssignment(false); + reloadAssignments(); + }} + assignment={selectedAssignment} + /> + { + setIsCreatingAssignment(false); + setSelectedAssignment(undefined); + reloadAssignments(); + }} + /> +
+
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 +
+
+ Reload + +
+
+
+ Active Assignments Status +
+ + Total: {assignments.filter(activeAssignmentFilter).reduce((acc, curr) => acc + curr.results.length, 0)}/ + {assignments.filter(activeAssignmentFilter).reduce((acc, curr) => curr.exams.length + acc, 0)} + + {Object.keys(groupBy(corporateAssignments, (x) => x.corporate?.id)).map((x) => ( +
+ {getUserCompanyName(users.find((u) => u.id === x)!, users, groups)}: + + {groupBy(corporateAssignments, (x) => x.corporate?.id)[x].reduce((acc, curr) => curr.results.length + acc, 0)}/ + {groupBy(corporateAssignments, (x) => x.corporate?.id)[x].reduce((acc, curr) => curr.exams.length + acc, 0)} + +
+ ))} +
+
+
+

Active Assignments ({assignments.filter(activeAssignmentFilter).length})

+
+ {assignments.filter(activeAssignmentFilter).map((a) => ( + setSelectedAssignment(a)} key={a.id} /> + ))} +
+
+
+

Planned Assignments ({assignments.filter(futureAssignmentFilter).length})

+
+
setIsCreatingAssignment(true)} + className="w-[250px] h-[200px] flex flex-col gap-2 items-center justify-center bg-white hover:bg-mti-purple-ultralight text-mti-purple-light hover:text-mti-purple-dark border border-mti-gray-platinum hover:drop-shadow p-4 cursor-pointer rounded-xl transition ease-in-out duration-300"> + + New Assignment +
+ {assignments.filter(futureAssignmentFilter).map((a) => ( + { + setSelectedAssignment(a); + setIsCreatingAssignment(true); + }} + key={a.id} + /> + ))} +
+
+
+

Past Assignments ({assignments.filter(pastAssignmentFilter).length})

+
+ {assignments.filter(pastAssignmentFilter).map((a) => ( + setSelectedAssignment(a)} + key={a.id} + allowDownload + reload={reloadAssignments} + allowArchive + allowExcelDownload + /> + ))} +
+
+
+

Archived Assignments ({assignments.filter(archivedAssignmentFilter).length})

+
+ {assignments.filter(archivedAssignmentFilter).map((a) => ( + setSelectedAssignment(a)} + key={a.id} + allowDownload + reload={reloadAssignments} + allowUnarchive + allowExcelDownload + /> + ))} +
+
+ + ); + }; - 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 masterCorporateUsers = useMemo( + () => + masterCorporateUserGroups.reduce((accm: CorporateUser[], id) => { + const user = users.find((u) => u.id === id) as CorporateUser; + if (user) return [...accm, user]; + return accm; + }, []), + [masterCorporateUserGroups, users], + ); - const DefaultDashboard = () => ( - <> -
- setPage("students")} - Icon={BsPersonFill} - label="Students" - value={users.filter(studentFilter).length} - color="purple" - /> - setPage("teachers")} - Icon={BsPencilSquare} - 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={BsPeople} - label="Groups" - value={groups.length} - color="purple" - /> - - - setPage("corporate")} - /> - setPage("studentsPerformance")} - /> - setPage("statistical")} - /> - -
+ 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

+
+ + + ); + }; -
-
- 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) => ( - - ))} -
-
-
- - ); + const DefaultDashboard = () => ( + <> +
+ setPage("students")} + Icon={BsPersonFill} + label="Students" + value={users.filter(studentFilter).length} + color="purple" + /> + setPage("teachers")} + Icon={BsPencilSquare} + 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={BsPeople} label="Groups" value={groups.length} color="purple" /> + + + setPage("corporate")} + /> + setPage("studentsPerformance")} + /> + setPage("statistical")} + /> + +
- 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), - }); +
+
+ 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) => ( + + ))} +
+
+
+ + ); - 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), - }); + 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 - } - user={selectedUser} - /> -
- )} - -
- {page === "students" && } - {page === "teachers" && } - {page === "groups" && } - {page === "corporate" && } - {page === "assignments" && } - {page === "studentsPerformance" && } - {page === "statistical" && } - {page === "" && } - - ); + 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 + } + user={selectedUser} + /> +
+ )} + +
+ {page === "students" && } + {page === "teachers" && } + {page === "groups" && } + {page === "corporate" && } + {page === "assignments" && } + {page === "studentsPerformance" && } + {page === "statistical" && } + {page === "" && } + + ); } diff --git a/src/dashboards/Teacher.tsx b/src/dashboards/Teacher.tsx index 0bd894d1..72daa370 100644 --- a/src/dashboards/Teacher.tsx +++ b/src/dashboards/Teacher.tsx @@ -2,486 +2,410 @@ import Modal from "@/components/Modal"; import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser"; import useUsers from "@/hooks/useUsers"; -import { CorporateUser, Group, Stat, User } from "@/interfaces/user"; +import {CorporateUser, Group, 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, useMemo, useState} from "react"; import { - BsArrowLeft, - BsArrowRepeat, - BsClipboard2Data, - BsClipboard2DataFill, - BsClipboard2Heart, - BsClipboard2X, - BsClipboardPulse, - BsClock, - BsEnvelopePaper, - BsGlobeCentralSouthAsia, - BsPaperclip, - BsPeople, - BsPerson, - BsPersonAdd, - BsPersonFill, - BsPersonFillGear, - BsPersonGear, - BsPlus, - BsRepeat, - BsRepeat1, + BsArrowLeft, + BsArrowRepeat, + BsClipboard2Data, + BsClipboard2DataFill, + BsClipboard2Heart, + BsClipboard2X, + BsClipboardPulse, + BsClock, + BsEnvelopePaper, + BsGlobeCentralSouthAsia, + BsPaperclip, + BsPeople, + BsPerson, + BsPersonAdd, + BsPersonFill, + BsPersonFillGear, + BsPersonGear, + BsPlus, + BsRepeat, + BsRepeat1, } 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 {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"; import useAssignments from "@/hooks/useAssignments"; -import { Assignment } from "@/interfaces/results"; +import {Assignment} from "@/interfaces/results"; import AssignmentCard from "./AssignmentCard"; import Button from "@/components/Low/Button"; import clsx from "clsx"; import ProgressBar from "@/components/Low/ProgressBar"; import AssignmentCreator from "./AssignmentCreator"; import AssignmentView from "./AssignmentView"; -import { getUserCorporate } from "@/utils/groups"; -import { checkAccess } from "@/utils/permissions"; +import {getUserCorporate} from "@/utils/groups"; +import {checkAccess} from "@/utils/permissions"; import usePermissions from "@/hooks/usePermissions"; -import { - futureAssignmentFilter, - pastAssignmentFilter, - archivedAssignmentFilter, - activeAssignmentFilter -} from '@/utils/assignments'; +import {futureAssignmentFilter, pastAssignmentFilter, archivedAssignmentFilter, activeAssignmentFilter} from "@/utils/assignments"; interface Props { - user: User; + user: User; } -export default function TeacherDashboard({ user }: Props) { - const [page, setPage] = useState(""); - const [selectedUser, setSelectedUser] = useState(); - const [showModal, setShowModal] = useState(false); - const [selectedAssignment, setSelectedAssignment] = useState(); - const [isCreatingAssignment, setIsCreatingAssignment] = useState(false); - const [corporateUserToShow, setCorporateUserToShow] = - useState(); +export default function TeacherDashboard({user}: Props) { + const [page, setPage] = useState(""); + const [selectedUser, setSelectedUser] = useState(); + const [showModal, setShowModal] = useState(false); + const [selectedAssignment, setSelectedAssignment] = useState(); + const [isCreatingAssignment, setIsCreatingAssignment] = useState(false); + const [corporateUserToShow, setCorporateUserToShow] = useState(); - const { data: stats } = useFilterRecordsByUser(); - const { users, reload } = useUsers(); - const { groups } = useGroups({ adminAdmins: user.id }); - const { permissions } = usePermissions(user.id); - const { - assignments, - isLoading: isAssignmentsLoading, - reload: reloadAssignments, - } = useAssignments({ assigner: user.id }); + const {data: stats} = useFilterRecordsByUser(); + const {users, reload} = useUsers(); + const {groups} = useGroups({adminAdmins: user.id}); + const {permissions} = usePermissions(user.id); + const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({assigner: user.id}); - useEffect(() => { - setShowModal(!!selectedUser && page === ""); - }, [selectedUser, page]); + const assignmentsGroups = useMemo(() => groups.filter((x) => x.admin === user.id || x.participants.includes(user.id)), [groups, user.id]); - useEffect(() => { - getUserCorporate(user.id).then(setCorporateUserToShow); - }, [user]); + const assignmentsUsers = useMemo( + () => + users.filter( + (x) => + x.type === "student" && + (!!selectedUser + ? groups + .filter((g) => g.admin === selectedUser.id) + .flatMap((g) => g.participants) + .includes(x.id) + : groups.flatMap((g) => g.participants).includes(x.id)), + ), + [groups, users, selectedUser], + ); - const studentFilter = (user: User) => - user.type === "student" && - groups.flatMap((g) => g.participants).includes(user.id); + useEffect(() => { + setShowModal(!!selectedUser && page === ""); + }, [selectedUser, page]); - const getStatsByStudent = (user: User) => - stats.filter((s) => s.user === user.id); + useEffect(() => { + getUserCorporate(user.id).then(setCorporateUserToShow); + }, [user]); - 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 studentFilter = (user: User) => user.type === "student" && groups.flatMap((g) => g.participants).includes(user.id); - 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)); + const getStatsByStudent = (user: User) => stats.filter((s) => s.user === 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 -
-

Students ({total})

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

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

-
+ 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 GroupsList = () => { + const filter = (x: Group) => x.admin === user.id; - 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! - ), - })); + 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 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 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 AssignmentsPage = () => { - return ( - <> - { - setSelectedAssignment(undefined); - setIsCreatingAssignment(false); - reloadAssignments(); - }} - assignment={selectedAssignment} - /> - x.admin === user.id || x.participants.includes(user.id) - )} - users={users.filter( - (x) => - x.type === "student" && - (!!selectedUser - ? groups - .filter((g) => g.admin === selectedUser.id) - .flatMap((g) => g.participants) - .includes(x.id) - : groups.flatMap((g) => g.participants).includes(x.id)) - )} - assigner={user.id} - isCreating={isCreatingAssignment} - cancelCreation={() => { - setIsCreatingAssignment(false); - setSelectedAssignment(undefined); - reloadAssignments(); - }} - /> -
-
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 -
-
- Reload - -
-
-
-

- Active Assignments ({assignments.filter(activeAssignmentFilter).length}) -

-
- {assignments.filter(activeAssignmentFilter).map((a) => ( - setSelectedAssignment(a)} - key={a.id} - /> - ))} -
-
-
-

- Planned Assignments ({assignments.filter(futureAssignmentFilter).length}) -

-
-
setIsCreatingAssignment(true)} - className="w-[250px] h-[200px] flex flex-col gap-2 items-center justify-center bg-white hover:bg-mti-purple-ultralight text-mti-purple-light hover:text-mti-purple-dark border border-mti-gray-platinum hover:drop-shadow p-4 cursor-pointer rounded-xl transition ease-in-out duration-300" - > - - New Assignment -
- {assignments.filter(futureAssignmentFilter).map((a) => ( - { - setSelectedAssignment(a); - setIsCreatingAssignment(true); - }} - key={a.id} - /> - ))} -
-
-
-

- Past Assignments ({assignments.filter(pastAssignmentFilter).length}) -

-
- {assignments.filter(pastAssignmentFilter).map((a) => ( - setSelectedAssignment(a)} - key={a.id} - allowDownload - reload={reloadAssignments} - allowArchive - allowExcelDownload - /> - ))} -
-
-
-

- Archived Assignments ({assignments.filter(archivedAssignmentFilter).length}) -

-
- {assignments.filter(archivedAssignmentFilter).map((a) => ( - setSelectedAssignment(a)} - key={a.id} - allowDownload - reload={reloadAssignments} - allowUnarchive - allowExcelDownload - /> - ))} -
-
- - ); - }; + const levels: {[key in Module]: number} = { + reading: 0, + listening: 0, + writing: 0, + speaking: 0, + level: 0, + }; + bandScores.forEach((b) => (levels[b.module] += b.level)); - const DefaultDashboard = () => ( - <> - {corporateUserToShow && ( -
- Linked to:{" "} - - {corporateUserToShow?.corporateInformation?.companyInformation - .name || corporateUserToShow.name} - -
- )} -
- 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" - /> - {checkAccess( - user, - ["teacher", "developer"], - permissions, - "viewGroup" - ) && ( - x.admin === user.id).length} - color="purple" - onClick={() => setPage("groups")} - /> - )} -
setPage("assignments")} - className="bg-white rounded-xl shadow p-4 flex flex-col gap-4 items-center w-96 h-52 justify-center cursor-pointer hover:shadow-xl transition ease-in-out duration-300" - > - - - Assignments - - {assignments.filter((a) => !a.archived).length} - - -
-
+ return calculateAverageLevel(levels); + }; -
-
- 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) => ( - - ))} -
-
-
- - ); + const AssignmentsPage = () => { + return ( + <> + { + setSelectedAssignment(undefined); + setIsCreatingAssignment(false); + reloadAssignments(); + }} + assignment={selectedAssignment} + /> + { + setIsCreatingAssignment(false); + setSelectedAssignment(undefined); + reloadAssignments(); + }} + /> +
+
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 +
+
+ Reload + +
+
+
+

Active Assignments ({assignments.filter(activeAssignmentFilter).length})

+
+ {assignments.filter(activeAssignmentFilter).map((a) => ( + setSelectedAssignment(a)} key={a.id} /> + ))} +
+
+
+

Planned Assignments ({assignments.filter(futureAssignmentFilter).length})

+
+
setIsCreatingAssignment(true)} + className="w-[250px] h-[200px] flex flex-col gap-2 items-center justify-center bg-white hover:bg-mti-purple-ultralight text-mti-purple-light hover:text-mti-purple-dark border border-mti-gray-platinum hover:drop-shadow p-4 cursor-pointer rounded-xl transition ease-in-out duration-300"> + + New Assignment +
+ {assignments.filter(futureAssignmentFilter).map((a) => ( + { + setSelectedAssignment(a); + setIsCreatingAssignment(true); + }} + key={a.id} + /> + ))} +
+
+
+

Past Assignments ({assignments.filter(pastAssignmentFilter).length})

+
+ {assignments.filter(pastAssignmentFilter).map((a) => ( + setSelectedAssignment(a)} + key={a.id} + allowDownload + reload={reloadAssignments} + allowArchive + allowExcelDownload + /> + ))} +
+
+
+

Archived Assignments ({assignments.filter(archivedAssignmentFilter).length})

+
+ {assignments.filter(archivedAssignmentFilter).map((a) => ( + setSelectedAssignment(a)} + key={a.id} + allowDownload + reload={reloadAssignments} + allowUnarchive + allowExcelDownload + /> + ))} +
+
+ + ); + }; - 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 === "groups" && } - {page === "assignments" && } - {page === "" && } - - ); + const DefaultDashboard = () => ( + <> + {corporateUserToShow && ( +
+ Linked to: {corporateUserToShow?.corporateInformation?.companyInformation.name || corporateUserToShow.name} +
+ )} +
+ 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" + /> + {checkAccess(user, ["teacher", "developer"], permissions, "viewGroup") && ( + x.admin === user.id).length} + color="purple" + onClick={() => setPage("groups")} + /> + )} +
setPage("assignments")} + className="bg-white rounded-xl shadow p-4 flex flex-col gap-4 items-center w-96 h-52 justify-center cursor-pointer hover:shadow-xl transition ease-in-out duration-300"> + + + Assignments + {assignments.filter((a) => !a.archived).length} + +
+
+ +
+
+ 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} + user={selectedUser} + /> +
+ )} + +
+ {page === "students" && } + {page === "groups" && } + {page === "assignments" && } + {page === "" && } + + ); }