diff --git a/src/dashboards/IconCard.tsx b/src/dashboards/IconCard.tsx
index 5fd55486..afc09cee 100644
--- a/src/dashboards/IconCard.tsx
+++ b/src/dashboards/IconCard.tsx
@@ -1,36 +1,49 @@
import clsx from "clsx";
-import {IconType} from "react-icons";
+import { IconType } from "react-icons";
interface Props {
- Icon: IconType;
- label: string;
- value?: string | number;
- color: "purple" | "rose" | "red" | "green";
- tooltip?: string;
- onClick?: () => void;
+ Icon: IconType;
+ label: string;
+ value?: string | number;
+ color: "purple" | "rose" | "red" | "green";
+ tooltip?: string;
+ onClick?: () => void;
+ isSelected?: boolean;
}
-export default function IconCard({Icon, label, value, color, tooltip, onClick}: Props) {
- const colorClasses: {[key in typeof color]: string} = {
- purple: "text-mti-purple-light",
- red: "text-mti-red-light",
- rose: "text-mti-rose-light",
- green: "text-mti-green-light",
- };
+export default function IconCard({
+ Icon,
+ label,
+ value,
+ color,
+ tooltip,
+ onClick,
+ isSelected,
+}: Props) {
+ const colorClasses: { [key in typeof color]: string } = {
+ purple: "mti-purple-light",
+ red: "mti-red-light",
+ rose: "mti-rose-light",
+ green: "mti-green-light",
+ };
- return (
-
-
-
- {label}
- {value}
-
-
- );
+ return (
+
+
+
+ {label}
+
+ {value}
+
+
+
+ );
}
diff --git a/src/dashboards/MasterCorporate.tsx b/src/dashboards/MasterCorporate.tsx
index 4f61f02d..b5ad4275 100644
--- a/src/dashboards/MasterCorporate.tsx
+++ b/src/dashboards/MasterCorporate.tsx
@@ -2,838 +2,1110 @@
import Modal from "@/components/Modal";
import useStats from "@/hooks/useStats";
import useUsers from "@/hooks/useUsers";
-import {CorporateUser, Group, MasterCorporateUser, Stat, User} from "@/interfaces/user";
-import UserList from "@/pages/(admin)/Lists/UserList";
-import {dateSorter} from "@/utils";
-import moment from "moment";
-import {useEffect, useState} from "react";
import {
- BsArrowLeft,
- BsClipboard2Data,
- BsClock,
- BsPaperclip,
- BsPersonFill,
- BsPencilSquare,
- BsPersonCheck,
- BsPeople,
- BsBank,
- BsEnvelopePaper,
- BsArrowRepeat,
- BsPlus,
- BsPersonFillGear,
- BsFilter,
- BsDatabase,
+ CorporateUser,
+ Group,
+ MasterCorporateUser,
+ Stat,
+ User,
+} from "@/interfaces/user";
+import UserList from "@/pages/(admin)/Lists/UserList";
+import { dateSorter } from "@/utils";
+import moment from "moment";
+import { useEffect, useState, useMemo } from "react";
+import {
+ 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";
interface Props {
- user: MasterCorporateUser;
+ user: MasterCorporateUser;
}
const activeFilter = (a: Assignment) =>
- moment(a.endDate).isAfter(moment()) && moment(a.startDate).isBefore(moment()) && a.assignees.length > a.results.length;
-const pastFilter = (a: Assignment) => (moment(a.endDate).isBefore(moment()) || a.assignees.length === a.results.length) && !a.archived;
+ moment(a.endDate).isAfter(moment()) &&
+ moment(a.startDate).isBefore(moment()) &&
+ a.assignees.length > a.results.length;
+const pastFilter = (a: Assignment) =>
+ (moment(a.endDate).isBefore(moment()) ||
+ a.assignees.length === a.results.length) &&
+ !a.archived;
const archivedFilter = (a: Assignment) => a.archived;
const futureFilter = (a: Assignment) => moment(a.startDate).isAfter(moment());
-type StudentPerformanceItem = User & {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",
- ),
- );
+type StudentPerformanceItem = User & {
+ 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 [selectedCorporate, setSelectedCorporate] = useState(null);
- const [selectedGroup, setSelectedGroup] = useState(null);
+ const [selectedCorporate, setSelectedCorporate] = useState<
+ CorporateUser | null | undefined
+ >(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?.corporateInformation?.companyInformation?.name || x?.name || "N/A",
- }))}
- isClearable
- value={
- selectedCorporate === null
- ? null
- : {
- value: selectedCorporate?.id || "N/A",
- label:
- selectedCorporate?.corporateInformation?.companyInformation?.name ||
- selectedCorporate?.name ||
- "N/A",
- }
- }
- placeholder="Select a Corporate..."
- onChange={(value) =>
- !value
- ? setSelectedCorporate(null)
- : setSelectedCorporate(
- value.value === "N/A" ? undefined : availableCorporates.find((x) => x?.id === value.value),
- )
- }
- />
- ({
- 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?.corporateInformation?.companyInformation?.name ||
+ x?.name ||
+ "N/A",
+ }))}
+ isClearable
+ value={
+ selectedCorporate === null
+ ? null
+ : {
+ value: selectedCorporate?.id || "N/A",
+ label:
+ selectedCorporate?.corporateInformation
+ ?.companyInformation?.name ||
+ selectedCorporate?.name ||
+ "N/A",
+ }
+ }
+ placeholder="Select a Corporate..."
+ onChange={(value) =>
+ !value
+ ? setSelectedCorporate(null)
+ : setSelectedCorporate(
+ value.value === "N/A"
+ ? undefined
+ : availableCorporates.find(
+ (x) => x?.id === value.value
+ )
+ )
+ }
+ />
+ ({
+ 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 {stats} = useStats();
- const {users, reload} = useUsers();
- const {codes} = useCodes(user.id);
- const {groups} = useGroups({admin: user.id, userType: user.type});
+ const { stats } = useStats();
+ const { users, reload } = useUsers();
+ const { codes } = useCodes(user.id);
+ const { groups } = useGroups({ admin: user.id, userType: user.type });
- const masterCorporateUserGroups = [...new Set(groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants))];
+ const masterCorporateUserGroups = [
+ ...new Set(
+ groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants)
+ ),
+ ];
- const corporateUserGroups = [...new Set(groups.flatMap((g) => g.participants))];
+ const corporateUserGroups = [
+ ...new Set(groups.flatMap((g) => g.participants)),
+ ];
- const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({corporate: user.id});
+ const {
+ assignments,
+ isLoading: isAssignmentsLoading,
+ reload: reloadAssignments,
+ } = useAssignments({ corporate: user.id });
- const appendUserFilters = useFilterStore((state) => state.appendUserFilter);
- const router = useRouter();
+ const appendUserFilters = useFilterStore((state) => state.appendUserFilter);
+ const router = useRouter();
- useEffect(() => {
- setShowModal(!!selectedUser && page === "");
- }, [selectedUser, page]);
+ useEffect(() => {
+ setShowModal(!!selectedUser && page === "");
+ }, [selectedUser, page]);
- useEffect(() => {
- setCorporateAssignments(
- assignments.filter(activeFilter).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(() => {
+ setCorporateAssignments(
+ assignments.filter(activeFilter).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 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 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 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.email}
-
-
- );
+ const UserDisplay = (displayUser: User) => (
+ setSelectedUser(displayUser)}
+ className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300"
+ >
+
+
+ {displayUser.name}
+ {displayUser.email}
+
+
+ );
- const StudentsList = () => {
- const filter = (x: User) =>
- x.type === "student" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id));
+ const StudentsList = () => {
+ const filter = (x: User) =>
+ x.type === "student" &&
+ (!!selectedUser
+ ? corporateUserGroups.includes(x.id) || false
+ : corporateUserGroups.includes(x.id));
- return (
- (
-
-
setPage("")}
- className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
-
- Back
-
-
Students ({total})
-
- )}
- />
- );
- };
+ return (
+ (
+
+
setPage("")}
+ className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"
+ >
+
+ Back
+
+
Students ({total})
+
+ )}
+ />
+ );
+ };
- const TeachersList = () => {
- const filter = (x: User) =>
- x.type === "teacher" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id));
+ const TeachersList = () => {
+ const filter = (x: User) =>
+ x.type === "teacher" &&
+ (!!selectedUser
+ ? corporateUserGroups.includes(x.id) || false
+ : corporateUserGroups.includes(x.id));
- return (
- (
-
-
setPage("")}
- className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
-
- Back
-
-
Teachers ({total})
-
- )}
- />
- );
- };
+ return (
+ (
+
+
setPage("")}
+ className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"
+ >
+
+ Back
+
+
Teachers ({total})
+
+ )}
+ />
+ );
+ };
- const corporateUserFilter = (x: User) =>
- x.type === "corporate" && (!!selectedUser ? masterCorporateUserGroups.includes(x.id) || false : masterCorporateUserGroups.includes(x.id));
+ const corporateUserFilter = (x: User) =>
+ x.type === "corporate" &&
+ (!!selectedUser
+ ? masterCorporateUserGroups.includes(x.id) || false
+ : masterCorporateUserGroups.includes(x.id));
- const CorporateList = () => {
- return (
- (
-
-
setPage("")}
- className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
-
- Back
-
-
Corporates ({total})
-
- )}
- />
- );
- };
+ const CorporateList = () => {
+ return (
+ (
+
+
setPage("")}
+ className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"
+ >
+
+ Back
+
+
Corporates ({total})
+
+ )}
+ />
+ );
+ };
- const GroupsList = () => {
- return (
- <>
-
-
setPage("")}
- className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
-
- Back
-
-
Groups ({groups.length})
-
+ const GroupsList = () => {
+ return (
+ <>
+
+
setPage("")}
+ className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"
+ >
+
+ Back
+
+
Groups ({groups.length})
+
-
- >
- );
- };
+
+ >
+ );
+ };
- // const AssignmentsPage = () => {
- // const activeFilter = (a: Assignment) =>
- // moment(a.endDate).isAfter(moment()) &&
- // moment(a.startDate).isBefore(moment()) &&
- // a.assignees.length > a.results.length;
- // const pastFilter = (a: Assignment) =>
- // (moment(a.endDate).isBefore(moment()) ||
- // a.assignees.length === a.results.length) &&
- // !a.archived;
- // const archivedFilter = (a: Assignment) => a.archived;
- // const futureFilter = (a: Assignment) =>
- // moment(a.startDate).isAfter(moment());
+ // const AssignmentsPage = () => {
+ // const activeFilter = (a: Assignment) =>
+ // moment(a.endDate).isAfter(moment()) &&
+ // moment(a.startDate).isBefore(moment()) &&
+ // a.assignees.length > a.results.length;
+ // const pastFilter = (a: Assignment) =>
+ // (moment(a.endDate).isBefore(moment()) ||
+ // a.assignees.length === a.results.length) &&
+ // !a.archived;
+ // const archivedFilter = (a: Assignment) => a.archived;
+ // const futureFilter = (a: Assignment) =>
+ // moment(a.startDate).isAfter(moment());
- const StudentPerformancePage = () => {
- const students = users
- .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 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
-
-
-
-
- >
- );
- };
+ 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}
- />
- 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(activeFilter).reduce((acc, curr) => acc + curr.results.length, 0)}/
- {assignments.filter(activeFilter).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(activeFilter).length})
-
- {assignments.filter(activeFilter).map((a) => (
-
setSelectedAssignment(a)} key={a.id} />
- ))}
-
-
-
- Planned Assignments ({assignments.filter(futureFilter).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(futureFilter).map((a) => (
-
{
- setSelectedAssignment(a);
- setIsCreatingAssignment(true);
- }}
- key={a.id}
- />
- ))}
-
-
-
- Past Assignments ({assignments.filter(pastFilter).length})
-
- {assignments.filter(pastFilter).map((a) => (
-
setSelectedAssignment(a)}
- key={a.id}
- allowDownload
- reload={reloadAssignments}
- allowArchive
- allowExcelDownload
- />
- ))}
-
-
-
- Archived Assignments ({assignments.filter(archivedFilter).length})
-
- {assignments.filter(archivedFilter).map((a) => (
-
setSelectedAssignment(a)}
- key={a.id}
- allowDownload
- reload={reloadAssignments}
- allowUnarchive
- allowExcelDownload
- />
- ))}
-
-
- >
- );
- };
+ 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(activeFilter)
+ .reduce((acc, curr) => acc + curr.results.length, 0)}
+ /
+ {assignments
+ .filter(activeFilter)
+ .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(activeFilter).length})
+
+
+ {assignments.filter(activeFilter).map((a) => (
+
setSelectedAssignment(a)}
+ key={a.id}
+ />
+ ))}
+
+
+
+
+ Planned Assignments ({assignments.filter(futureFilter).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(futureFilter).map((a) => (
+
{
+ setSelectedAssignment(a);
+ setIsCreatingAssignment(true);
+ }}
+ key={a.id}
+ />
+ ))}
+
+
+
+
+ Past Assignments ({assignments.filter(pastFilter).length})
+
+
+ {assignments.filter(pastFilter).map((a) => (
+
setSelectedAssignment(a)}
+ key={a.id}
+ allowDownload
+ reload={reloadAssignments}
+ allowArchive
+ allowExcelDownload
+ />
+ ))}
+
+
+
+
+ Archived Assignments ({assignments.filter(archivedFilter).length})
+
+
+ {assignments.filter(archivedFilter).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 user = users.find((u) => u.id === id) as CorporateUser;
- if (user) return [...accm, user];
- return accm;
- }, [])}
- />
- >
- );
- };
+ 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")}
- />
- setPage("assignments")}
- className="bg-white col-span-2 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
-
- {isAssignmentsLoading ? "Loading..." : assignments.filter((a) => !a.archived).length}
-
-
-
-
+ 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")}
+ />
+ setPage("assignments")}
+ className="bg-white col-span-2 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
+
+ {isAssignmentsLoading
+ ? "Loading..."
+ : assignments.filter((a) => !a.archived).length}
+
+
+
+
- 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/MasterStatistical.tsx b/src/dashboards/MasterStatistical.tsx
index c3f6800a..71537fb4 100644
--- a/src/dashboards/MasterStatistical.tsx
+++ b/src/dashboards/MasterStatistical.tsx
@@ -5,11 +5,20 @@ import IconCard from "./IconCard";
import useAssignmentsCorporates from "@/hooks/useAssignmentCorporates";
import ReactDatePicker from "react-datepicker";
import moment from "moment";
-import { groupBySession } from "@/utils/stats";
-import { Assignment, AssignmentResult } from "@/interfaces/results";
+import { Assignment, AssignmentWithCorporateId } from "@/interfaces/results";
+import {
+ CellContext,
+ createColumnHelper,
+ flexRender,
+ getCoreRowModel,
+ HeaderGroup,
+ Table,
+ useReactTable,
+} from "@tanstack/react-table";
+import Checkbox from "@/components/Low/Checkbox";
interface Props {
- corporateUsers: CorporateUser[];
+ corporateUsers: User[];
users: User[];
}
@@ -20,11 +29,29 @@ interface TableData {
submitted: boolean;
date: moment.Moment;
assignment: string;
+ corporateId: string;
}
+
+interface UserCount {
+ userCount: number;
+ maxUserCount: number;
+}
+
const MasterStatistical = (props: Props) => {
const { users, corporateUsers } = props;
- const corporates = React.useMemo(() => corporateUsers.map((x) => x.id), [corporateUsers]);
+ const corporateRelevantUsers = React.useMemo(
+ () => corporateUsers.filter((x) => x.type !== "student") as CorporateUser[],
+ [corporateUsers]
+ );
+
+ const corporates = React.useMemo(
+ () => corporateRelevantUsers.map((x) => x.id),
+ [corporateRelevantUsers]
+ );
+
+ const [selectedCorporates, setSelectedCorporates] =
+ React.useState(corporates);
const [startDate, setStartDate] = React.useState(
moment("01/01/2023").toDate()
);
@@ -33,75 +60,249 @@ const MasterStatistical = (props: Props) => {
);
const { assignments } = useAssignmentsCorporates({
- corporates,
+ // corporates: [...corporates, "tYU0HTiJdjMsS8SB7XJsUdMMP892"],
+ corporates: selectedCorporates,
startDate,
endDate,
});
-
- const x = assignments.reduce((accmA: TableData[], a: Assignment) => {
- const userResults = a.results.reduce((accmB: TableData[], r: AssignmentResult) => {
- const userStats = groupBySession(r.stats);
- const data = Object.keys(userStats).map((key) => ({
- user: users.find((u) => u.id === r.user)?.name || "",
- correct: userStats[key].reduce((n, e) => n + e.score.correct, 0),
- corporate: users.find((u) => u.id === a.assigner)?.name || "",
- submitted: false,
- date: moment.max(userStats[key].map((e) => moment(e.date))),
- assignment: a.name,
- }));
- return [...accmB, ...data];
- }, []);
-
- return [...accmA, ...userResults];
- }, []);
- return (
-
- console.log("clicked")}
- />
- {corporateUsers.map((group) => (
- console.log("clicked", group)}
- />
- ))}
-
- {
- setStartDate(initialDate ?? moment("01/01/2023").toDate());
- if (finalDate) {
- // basicly selecting a final day works as if I'm selecting the first
- // minute of that day. this way it covers the whole day
- setEndDate(moment(finalDate).endOf("day").toDate());
- return;
+ const tableResults = React.useMemo(
+ () =>
+ assignments.reduce((accmA: TableData[], a: AssignmentWithCorporateId) => {
+ const userResults = a.assignees.map((assignee) => {
+ const userStats =
+ a.results.find((r) => r.user === assignee)?.stats || [];
+ const userName = users.find((u) => u.id === assignee)?.name || "";
+ const corporate = users.find((u) => u.id === a.assigner)?.name || "";
+ const commonData = {
+ user: userName,
+ corporateId: a.corporateId,
+ corporate,
+ assignment: a.name,
+ };
+ if (userStats.length === 0) {
+ return {
+ ...commonData,
+ correct: 0,
+ submitted: false,
+ // date: moment(),
+ };
}
- setEndDate(null);
- }}
- />
- console.log("clicked")}
- Icon={BsPersonFill}
- label="Consolidate Highest Student"
- color="purple"
- />
-
+ return {
+ ...commonData,
+ correct: userStats.reduce((n, e) => n + e.score.correct, 0),
+ submitted: true,
+ date: moment.max(userStats.map((e) => moment(e.date))),
+ };
+ }) as TableData[];
+
+ return [...accmA, ...userResults];
+ }, []),
+ [assignments, users]
+ );
+
+ const getCorporateScores = (corporateId: string): UserCount => {
+ const corporateAssignmentsUsers = assignments
+ .filter((a) => a.corporateId === corporateId)
+ .reduce((acc, a) => acc + a.assignees.length, 0);
+
+ const corporateResults = tableResults.filter(
+ (r) => r.corporateId === corporateId
+ ).length;
+
+ return {
+ maxUserCount: corporateAssignmentsUsers,
+ userCount: corporateResults,
+ };
+ };
+
+ const corporateScores = corporates.reduce(
+ (accm, id) => ({
+ ...accm,
+ [id]: getCorporateScores(id),
+ }),
+ {}
+ ) as Record;
+
+ const consolidateScore = Object.values(corporateScores).reduce(
+ (acc: UserCount, { userCount, maxUserCount }: UserCount) => ({
+ userCount: acc.userCount + userCount,
+ maxUserCount: acc.maxUserCount + maxUserCount,
+ }),
+ { userCount: 0, maxUserCount: 0 }
+ );
+
+ const getConsolidateScoreStr = (data: UserCount) =>
+ `${data.userCount}/${data.maxUserCount}`;
+
+ const columnHelper = createColumnHelper();
+
+ const defaultColumns = [
+ columnHelper.accessor("user", {
+ header: "User",
+ id: "user",
+ cell: (info) => {
+ return {info.getValue()} ;
+ },
+ }),
+ columnHelper.accessor("corporate", {
+ header: "Corporate",
+ id: "corporate",
+ cell: (info) => {
+ return {info.getValue()} ;
+ },
+ }),
+ columnHelper.accessor("assignment", {
+ header: "Assignment",
+ id: "assignment",
+ cell: (info) => {
+ return {info.getValue()} ;
+ },
+ }),
+ columnHelper.accessor("submitted", {
+ header: "Submitted",
+ id: "submitted",
+ cell: (info) => {
+ return (
+ {}}>
+
+
+ );
+ },
+ }),
+ columnHelper.accessor("correct", {
+ header: "Correct",
+ id: "correct",
+ cell: (info) => {
+ return {info.getValue()} ;
+ },
+ }),
+ columnHelper.accessor("date", {
+ header: "Date",
+ id: "date",
+ cell: (info) => {
+ const date = info.getValue();
+ if (date) {
+ return {date.format("DD/MM/YYYY")} ;
+ }
+
+ return {""} ;
+ },
+ }),
+ ];
+
+ const table = useReactTable({
+ data: tableResults,
+ columns: defaultColumns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+
+ const areAllSelected = selectedCorporates.length === corporates.length;
+ return (
+ <>
+
+ {
+ if (areAllSelected) {
+ setSelectedCorporates([]);
+ return;
+ }
+ setSelectedCorporates(corporates);
+ }}
+ isSelected={areAllSelected}
+ />
+ {corporateRelevantUsers.map((group) => {
+ const isSelected = selectedCorporates.includes(group.id);
+ return (
+ {
+ if (isSelected) {
+ setSelectedCorporates(
+ selectedCorporates.filter((x) => x !== group.id)
+ );
+ return;
+ }
+ setSelectedCorporates([...selectedCorporates, group.id]);
+ }}
+ isSelected={isSelected}
+ />
+ );
+ })}
+
+
+ {
+ setStartDate(initialDate ?? moment("01/01/2023").toDate());
+ if (finalDate) {
+ // basicly selecting a final day works as if I'm selecting the first
+ // minute of that day. this way it covers the whole day
+ setEndDate(moment(finalDate).endOf("day").toDate());
+ return;
+ }
+ setEndDate(null);
+ }}
+ />
+
+
+
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => (
+
+ {header.isPlaceholder
+ ? null
+ : flexRender(
+ header.column.columnDef.header,
+ header.getContext()
+ )}
+
+ ))}
+
+ ))}
+
+
+ {table.getRowModel().rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => (
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ ))}
+
+ ))}
+
+
+
+
+ console.log("clicked")}
+ Icon={BsPersonFill}
+ label="Consolidate Highest Student"
+ color="purple"
+ />
+
+ >
);
};
diff --git a/src/hooks/useAssignmentCorporates.tsx b/src/hooks/useAssignmentCorporates.tsx
index d6b7dc33..524b31ef 100644
--- a/src/hooks/useAssignmentCorporates.tsx
+++ b/src/hooks/useAssignmentCorporates.tsx
@@ -1,6 +1,5 @@
-import { Assignment } from "@/interfaces/results";
+import { AssignmentWithCorporateId } from "@/interfaces/results";
import axios from "axios";
-import moment from "moment";
import { useEffect, useState } from "react";
export default function useAssignmentsCorporates({
@@ -12,7 +11,7 @@ export default function useAssignmentsCorporates({
startDate: Date | null;
endDate: Date | null;
}) {
- const [assignments, setAssignments] = useState([]);
+ const [assignments, setAssignments] = useState([]);
const [isLoading, setIsLoading] = useState(false);
const [isError, setIsError] = useState(false);
@@ -30,7 +29,7 @@ export default function useAssignmentsCorporates({
});
axios
- .get(
+ .get(
`/api/assignments/corporate?${urlSearchParams.toString()}`
)
.then(async (response) => {
diff --git a/src/interfaces/results.ts b/src/interfaces/results.ts
index 77a92bde..fa4a60d0 100644
--- a/src/interfaces/results.ts
+++ b/src/interfaces/results.ts
@@ -29,3 +29,5 @@ export interface Assignment {
archived?: boolean;
released?: boolean;
}
+
+export type AssignmentWithCorporateId = Assignment & { corporateId: string };
diff --git a/src/pages/api/assignments/corporate/index.ts b/src/pages/api/assignments/corporate/index.ts
index babea6c2..631878f6 100644
--- a/src/pages/api/assignments/corporate/index.ts
+++ b/src/pages/api/assignments/corporate/index.ts
@@ -5,7 +5,6 @@ import { sessionOptions } from "@/lib/session";
import { getAllAssignersByCorporate } from "@/utils/groups.be";
import { getAssignmentsByAssigners } from "@/utils/assignments.be";
-
export default withIronSessionApiRoute(handler, sessionOptions);
async function handler(req: NextApiRequest, res: NextApiResponse) {
@@ -20,17 +19,49 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
}
async function GET(req: NextApiRequest, res: NextApiResponse) {
- const { ids, startDate, endDate } = req.query as { ids: string, startDate?: string, endDate?: string };
+ const { ids, startDate, endDate } = req.query as {
+ ids: string;
+ startDate?: string;
+ endDate?: string;
+ };
const startDateParsed = startDate ? new Date(startDate) : undefined;
const endDateParsed = endDate ? new Date(endDate) : undefined;
try {
const idsList = ids.split(",");
- const assigners = await Promise.all(idsList.map(getAllAssignersByCorporate));
- const assignmentList = [...assigners.flat(), ...idsList];
- const assignments = await getAssignmentsByAssigners(assignmentList, startDateParsed, endDateParsed);
- res.status(200).json(assignments);
+ const assigners = await Promise.all(
+ idsList.map(async (id) => {
+ const assigners = await getAllAssignersByCorporate(id);
+ return {
+ corporateId: id,
+ assigners,
+ };
+ })
+ );
+
+ const assignments = await Promise.all(assigners.map(async (data) => {
+ try {
+ const assigners = [...new Set([...data.assigners, data.corporateId])];
+ const assignments = await getAssignmentsByAssigners(
+ assigners,
+ startDateParsed,
+ endDateParsed
+ );
+ return assignments.map((assignment) => ({
+ ...assignment,
+ corporateId: data.corporateId,
+ }));
+ } catch (err) {
+ console.error(err);
+ return [];
+ }
+ }));
+
+ console.log(assignments);
+
+ // const assignments = await getAssignmentsByAssigners(assignmentList, startDateParsed, endDateParsed);
+ res.status(200).json(assignments.flat());
} catch (err: any) {
res.status(500).json({ error: err.message });
}
diff --git a/src/utils/stats.ts b/src/utils/stats.ts
index e60fcec7..08ba03e8 100644
--- a/src/utils/stats.ts
+++ b/src/utils/stats.ts
@@ -128,6 +128,7 @@ export const groupBySession = (stats: Stat[]) => groupBy(stats, "session");
export const groupByDate = (stats: Stat[]) => groupBy(stats, "date");
export const groupByExam = (stats: Stat[]) => groupBy(stats, "exam");
export const groupByModule = (stats: Stat[]) => groupBy(stats, "module");
+export const groupByUser = (stats: Stat[]) => groupBy(stats, "user");
export const convertToUserSolutions = (stats: Stat[]): UserSolution[] => {
return stats.map((stat) => ({