Corrected a bug related to groups of a master corporate
This commit is contained in:
@@ -4,9 +4,9 @@ import useStats from "@/hooks/useStats";
|
|||||||
import useUsers from "@/hooks/useUsers";
|
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 UserList from "@/pages/(admin)/Lists/UserList";
|
||||||
import { dateSorter } from "@/utils";
|
import {dateSorter} from "@/utils";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { useEffect, useState } from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {
|
import {
|
||||||
BsArrowLeft,
|
BsArrowLeft,
|
||||||
BsClipboard2Data,
|
BsClipboard2Data,
|
||||||
@@ -22,7 +22,7 @@ import {
|
|||||||
BsPlus,
|
BsPlus,
|
||||||
BsPersonFillGear,
|
BsPersonFillGear,
|
||||||
BsFilter,
|
BsFilter,
|
||||||
BsDatabase
|
BsDatabase,
|
||||||
} from "react-icons/bs";
|
} from "react-icons/bs";
|
||||||
import UserCard from "@/components/UserCard";
|
import UserCard from "@/components/UserCard";
|
||||||
import useGroups from "@/hooks/useGroups";
|
import useGroups from "@/hooks/useGroups";
|
||||||
@@ -34,10 +34,10 @@ import {groupByExam} from "@/utils/stats";
|
|||||||
import IconCard from "./IconCard";
|
import IconCard from "./IconCard";
|
||||||
import GroupList from "@/pages/(admin)/Lists/GroupList";
|
import GroupList from "@/pages/(admin)/Lists/GroupList";
|
||||||
import useFilterStore from "@/stores/listFilterStore";
|
import useFilterStore from "@/stores/listFilterStore";
|
||||||
import { useRouter } from "next/router";
|
import {useRouter} from "next/router";
|
||||||
import useCodes from "@/hooks/useCodes";
|
import useCodes from "@/hooks/useCodes";
|
||||||
import useAssignments from "@/hooks/useAssignments";
|
import useAssignments from "@/hooks/useAssignments";
|
||||||
import { Assignment } from "@/interfaces/results";
|
import {Assignment} from "@/interfaces/results";
|
||||||
import AssignmentView from "./AssignmentView";
|
import AssignmentView from "./AssignmentView";
|
||||||
import AssignmentCreator from "./AssignmentCreator";
|
import AssignmentCreator from "./AssignmentCreator";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
@@ -54,7 +54,7 @@ import {Popover, PopoverContent, PopoverTrigger} from "@/components/ui/popover";
|
|||||||
import MasterStatistical from "./MasterStatistical";
|
import MasterStatistical from "./MasterStatistical";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
user: MasterCorporateUser;
|
user: MasterCorporateUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeFilter = (a: Assignment) =>
|
const activeFilter = (a: Assignment) =>
|
||||||
@@ -309,28 +309,18 @@ export default function MasterCorporateDashboard({user}: Props) {
|
|||||||
const {codes} = useCodes(user.id);
|
const {codes} = useCodes(user.id);
|
||||||
const {groups} = useGroups({admin: user.id, userType: user.type});
|
const {groups} = useGroups({admin: user.id, userType: user.type});
|
||||||
|
|
||||||
const masterCorporateUserGroups = [
|
const masterCorporateUserGroups = [...new Set(groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants))];
|
||||||
...new Set(
|
|
||||||
groups.filter((u) => u.admin === user.id).flatMap((g) => g.participants)
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
const corporateUserGroups = [
|
const corporateUserGroups = [...new Set(groups.flatMap((g) => g.participants))];
|
||||||
...new Set(groups.flatMap((g) => g.participants)),
|
|
||||||
];
|
|
||||||
|
|
||||||
const {
|
const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({corporate: user.id});
|
||||||
assignments,
|
|
||||||
isLoading: isAssignmentsLoading,
|
|
||||||
reload: reloadAssignments,
|
|
||||||
} = useAssignments({ corporate: user.id });
|
|
||||||
|
|
||||||
const appendUserFilters = useFilterStore((state) => state.appendUserFilter);
|
const appendUserFilters = useFilterStore((state) => state.appendUserFilter);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setShowModal(!!selectedUser && page === "");
|
setShowModal(!!selectedUser && page === "");
|
||||||
}, [selectedUser, page]);
|
}, [selectedUser, page]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCorporateAssignments(
|
setCorporateAssignments(
|
||||||
@@ -347,135 +337,117 @@ export default function MasterCorporateDashboard({user}: Props) {
|
|||||||
const teacherFilter = (user: User) => user.type === "teacher" && 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 getStatsByStudent = (user: User) => stats.filter((s) => s.user === user.id);
|
||||||
|
|
||||||
const UserDisplay = (displayUser: User) => (
|
const UserDisplay = (displayUser: User) => (
|
||||||
<div
|
<div
|
||||||
onClick={() => setSelectedUser(displayUser)}
|
onClick={() => 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"
|
className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300">
|
||||||
>
|
<img src={displayUser.profilePicture} alt={displayUser.name} className="rounded-full w-10 h-10" />
|
||||||
<img
|
<div className="flex flex-col gap-1 items-start">
|
||||||
src={displayUser.profilePicture}
|
<span>{displayUser.name}</span>
|
||||||
alt={displayUser.name}
|
<span className="text-sm opacity-75">{displayUser.email}</span>
|
||||||
className="rounded-full w-10 h-10"
|
</div>
|
||||||
/>
|
</div>
|
||||||
<div className="flex flex-col gap-1 items-start">
|
);
|
||||||
<span>{displayUser.name}</span>
|
|
||||||
<span className="text-sm opacity-75">{displayUser.email}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const StudentsList = () => {
|
const StudentsList = () => {
|
||||||
const filter = (x: User) =>
|
const filter = (x: User) =>
|
||||||
x.type === "student" &&
|
x.type === "student" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id));
|
||||||
(!!selectedUser
|
|
||||||
? corporateUserGroups.includes(x.id) || false
|
|
||||||
: corporateUserGroups.includes(x.id));
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UserList
|
<UserList
|
||||||
user={user}
|
user={user}
|
||||||
filters={[filter]}
|
filters={[filter]}
|
||||||
renderHeader={(total) => (
|
renderHeader={(total) => (
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div
|
<div
|
||||||
onClick={() => setPage("")}
|
onClick={() => setPage("")}
|
||||||
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"
|
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
|
||||||
>
|
<BsArrowLeft className="text-xl" />
|
||||||
<BsArrowLeft className="text-xl" />
|
<span>Back</span>
|
||||||
<span>Back</span>
|
</div>
|
||||||
</div>
|
<h2 className="text-2xl font-semibold">Students ({total})</h2>
|
||||||
<h2 className="text-2xl font-semibold">Students ({total})</h2>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
/>
|
||||||
/>
|
);
|
||||||
);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const TeachersList = () => {
|
const TeachersList = () => {
|
||||||
const filter = (x: User) =>
|
const filter = (x: User) =>
|
||||||
x.type === "teacher" &&
|
x.type === "teacher" && (!!selectedUser ? corporateUserGroups.includes(x.id) || false : corporateUserGroups.includes(x.id));
|
||||||
(!!selectedUser
|
|
||||||
? corporateUserGroups.includes(x.id) || false
|
|
||||||
: corporateUserGroups.includes(x.id));
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UserList
|
<UserList
|
||||||
user={user}
|
user={user}
|
||||||
filters={[filter]}
|
filters={[filter]}
|
||||||
renderHeader={(total) => (
|
renderHeader={(total) => (
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div
|
<div
|
||||||
onClick={() => setPage("")}
|
onClick={() => setPage("")}
|
||||||
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"
|
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
|
||||||
>
|
<BsArrowLeft className="text-xl" />
|
||||||
<BsArrowLeft className="text-xl" />
|
<span>Back</span>
|
||||||
<span>Back</span>
|
</div>
|
||||||
</div>
|
<h2 className="text-2xl font-semibold">Teachers ({total})</h2>
|
||||||
<h2 className="text-2xl font-semibold">Teachers ({total})</h2>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
/>
|
||||||
/>
|
);
|
||||||
);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const corporateUserFilter = (x: User) =>
|
const corporateUserFilter = (x: User) =>
|
||||||
x.type === "corporate" &&
|
x.type === "corporate" && (!!selectedUser ? masterCorporateUserGroups.includes(x.id) || false : masterCorporateUserGroups.includes(x.id));
|
||||||
(!!selectedUser
|
|
||||||
? masterCorporateUserGroups.includes(x.id) || false
|
|
||||||
: masterCorporateUserGroups.includes(x.id));
|
|
||||||
|
|
||||||
const CorporateList = () => {
|
const CorporateList = () => {
|
||||||
return (
|
return (
|
||||||
<UserList
|
<UserList
|
||||||
user={user}
|
user={user}
|
||||||
filters={[corporateUserFilter]}
|
filters={[corporateUserFilter]}
|
||||||
renderHeader={(total) => (
|
renderHeader={(total) => (
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div
|
<div
|
||||||
onClick={() => setPage("")}
|
onClick={() => setPage("")}
|
||||||
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"
|
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
|
||||||
>
|
<BsArrowLeft className="text-xl" />
|
||||||
<BsArrowLeft className="text-xl" />
|
<span>Back</span>
|
||||||
<span>Back</span>
|
</div>
|
||||||
</div>
|
<h2 className="text-2xl font-semibold">Corporates ({total})</h2>
|
||||||
<h2 className="text-2xl font-semibold">Corporates ({total})</h2>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
/>
|
||||||
/>
|
);
|
||||||
);
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const GroupsList = () => {
|
const GroupsList = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div
|
<div
|
||||||
onClick={() => setPage("")}
|
onClick={() => setPage("")}
|
||||||
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"
|
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
|
||||||
>
|
<BsArrowLeft className="text-xl" />
|
||||||
<BsArrowLeft className="text-xl" />
|
<span>Back</span>
|
||||||
<span>Back</span>
|
</div>
|
||||||
</div>
|
<h2 className="text-2xl font-semibold">Groups ({groups.length})</h2>
|
||||||
<h2 className="text-2xl font-semibold">Groups ({groups.length})</h2>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<GroupList user={user} />
|
<GroupList user={user} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// const AssignmentsPage = () => {
|
// const AssignmentsPage = () => {
|
||||||
// const activeFilter = (a: Assignment) =>
|
// const activeFilter = (a: Assignment) =>
|
||||||
// moment(a.endDate).isAfter(moment()) &&
|
// moment(a.endDate).isAfter(moment()) &&
|
||||||
// moment(a.startDate).isBefore(moment()) &&
|
// moment(a.startDate).isBefore(moment()) &&
|
||||||
// a.assignees.length > a.results.length;
|
// a.assignees.length > a.results.length;
|
||||||
// const pastFilter = (a: Assignment) =>
|
// const pastFilter = (a: Assignment) =>
|
||||||
// (moment(a.endDate).isBefore(moment()) ||
|
// (moment(a.endDate).isBefore(moment()) ||
|
||||||
// a.assignees.length === a.results.length) &&
|
// a.assignees.length === a.results.length) &&
|
||||||
// !a.archived;
|
// !a.archived;
|
||||||
// const archivedFilter = (a: Assignment) => a.archived;
|
// const archivedFilter = (a: Assignment) => a.archived;
|
||||||
// const futureFilter = (a: Assignment) =>
|
// const futureFilter = (a: Assignment) =>
|
||||||
// moment(a.startDate).isAfter(moment());
|
// moment(a.startDate).isAfter(moment());
|
||||||
|
|
||||||
const StudentPerformancePage = () => {
|
const StudentPerformancePage = () => {
|
||||||
const students = users
|
const students = users
|
||||||
@@ -614,7 +586,7 @@ export default function MasterCorporateDashboard({user}: Props) {
|
|||||||
allowDownload
|
allowDownload
|
||||||
reload={reloadAssignments}
|
reload={reloadAssignments}
|
||||||
allowArchive
|
allowArchive
|
||||||
allowExcelDownload
|
allowExcelDownload
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -631,7 +603,7 @@ export default function MasterCorporateDashboard({user}: Props) {
|
|||||||
allowDownload
|
allowDownload
|
||||||
reload={reloadAssignments}
|
reload={reloadAssignments}
|
||||||
allowUnarchive
|
allowUnarchive
|
||||||
allowExcelDownload
|
allowExcelDownload
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -640,32 +612,28 @@ export default function MasterCorporateDashboard({user}: Props) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const MasterStatisticalPage = () => {
|
const MasterStatisticalPage = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div
|
<div
|
||||||
onClick={() => setPage("")}
|
onClick={() => setPage("")}
|
||||||
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"
|
className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300">
|
||||||
>
|
<BsArrowLeft className="text-xl" />
|
||||||
<BsArrowLeft className="text-xl" />
|
<span>Back</span>
|
||||||
<span>Back</span>
|
</div>
|
||||||
</div>
|
<h2 className="text-2xl font-semibold">Master Statistical</h2>
|
||||||
<h2 className="text-2xl font-semibold">Master Statistical</h2>
|
</div>
|
||||||
</div>
|
<MasterStatistical
|
||||||
<MasterStatistical
|
users={masterCorporateUserGroups.reduce((accm: CorporateUser[], id) => {
|
||||||
users={masterCorporateUserGroups.reduce(
|
const user = users.find((u) => u.id === id) as CorporateUser;
|
||||||
(accm: CorporateUser[], id) => {
|
if (user) return [...accm, user];
|
||||||
const user = users.find((u) => u.id === id) as CorporateUser;
|
return accm;
|
||||||
if (user) return [...accm, user];
|
}, [])}
|
||||||
return accm;
|
/>
|
||||||
},
|
</>
|
||||||
[]
|
);
|
||||||
)}
|
};
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const DefaultDashboard = () => (
|
const DefaultDashboard = () => (
|
||||||
<>
|
<>
|
||||||
@@ -726,13 +694,13 @@ export default function MasterCorporateDashboard({user}: Props) {
|
|||||||
color="purple"
|
color="purple"
|
||||||
onClick={() => setPage("studentsPerformance")}
|
onClick={() => setPage("studentsPerformance")}
|
||||||
/>
|
/>
|
||||||
<IconCard
|
<IconCard
|
||||||
Icon={BsDatabase}
|
Icon={BsDatabase}
|
||||||
label="Master Statistical"
|
label="Master Statistical"
|
||||||
// value={masterCorporateUserGroups.length}
|
// value={masterCorporateUserGroups.length}
|
||||||
color="purple"
|
color="purple"
|
||||||
onClick={() => setPage("statistical")}
|
onClick={() => setPage("statistical")}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
disabled={isAssignmentsLoading}
|
disabled={isAssignmentsLoading}
|
||||||
onClick={() => setPage("assignments")}
|
onClick={() => setPage("assignments")}
|
||||||
@@ -747,120 +715,105 @@ export default function MasterCorporateDashboard({user}: Props) {
|
|||||||
</button>
|
</button>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="grid grid-cols-1 md:grid-cols-2 gap-4 w-full justify-between">
|
<section className="grid grid-cols-1 md:grid-cols-2 gap-4 w-full justify-between">
|
||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Latest students</span>
|
<span className="p-4">Latest students</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{users
|
||||||
.filter(studentFilter)
|
.filter(studentFilter)
|
||||||
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
|
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
|
||||||
.map((x) => (
|
.map((x) => (
|
||||||
<UserDisplay key={x.id} {...x} />
|
<UserDisplay key={x.id} {...x} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Latest teachers</span>
|
<span className="p-4">Latest teachers</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{users
|
||||||
.filter(teacherFilter)
|
.filter(teacherFilter)
|
||||||
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
|
.sort((a, b) => dateSorter(a, b, "desc", "registrationDate"))
|
||||||
.map((x) => (
|
.map((x) => (
|
||||||
<UserDisplay key={x.id} {...x} />
|
<UserDisplay key={x.id} {...x} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
<span className="p-4">Highest level students</span>
|
<span className="p-4">Highest level students</span>
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
{users
|
{users
|
||||||
.filter(studentFilter)
|
.filter(studentFilter)
|
||||||
.sort(
|
.sort((a, b) => calculateAverageLevel(b.levels) - calculateAverageLevel(a.levels))
|
||||||
(a, b) =>
|
.map((x) => (
|
||||||
calculateAverageLevel(b.levels) -
|
<UserDisplay key={x.id} {...x} />
|
||||||
calculateAverageLevel(a.levels)
|
))}
|
||||||
)
|
</div>
|
||||||
.map((x) => (
|
</div>
|
||||||
<UserDisplay key={x.id} {...x} />
|
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
||||||
))}
|
<span className="p-4">Highest exam count students</span>
|
||||||
</div>
|
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
||||||
</div>
|
{users
|
||||||
<div className="bg-white shadow flex flex-col rounded-xl w-full">
|
.filter(studentFilter)
|
||||||
<span className="p-4">Highest exam count students</span>
|
.sort(
|
||||||
<div className="flex flex-col items-start h-96 overflow-scroll scrollbar-hide">
|
(a, b) =>
|
||||||
{users
|
Object.keys(groupByExam(getStatsByStudent(b))).length - Object.keys(groupByExam(getStatsByStudent(a))).length,
|
||||||
.filter(studentFilter)
|
)
|
||||||
.sort(
|
.map((x) => (
|
||||||
(a, b) =>
|
<UserDisplay key={x.id} {...x} />
|
||||||
Object.keys(groupByExam(getStatsByStudent(b))).length -
|
))}
|
||||||
Object.keys(groupByExam(getStatsByStudent(a))).length
|
</div>
|
||||||
)
|
</div>
|
||||||
.map((x) => (
|
</section>
|
||||||
<UserDisplay key={x.id} {...x} />
|
</>
|
||||||
))}
|
);
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal isOpen={showModal} onClose={() => setSelectedUser(undefined)}>
|
<Modal isOpen={showModal} onClose={() => setSelectedUser(undefined)}>
|
||||||
<>
|
<>
|
||||||
{selectedUser && (
|
{selectedUser && (
|
||||||
<div className="w-full flex flex-col gap-8">
|
<div className="w-full flex flex-col gap-8">
|
||||||
<UserCard
|
<UserCard
|
||||||
loggedInUser={user}
|
loggedInUser={user}
|
||||||
onClose={(shouldReload) => {
|
onClose={(shouldReload) => {
|
||||||
setSelectedUser(undefined);
|
setSelectedUser(undefined);
|
||||||
if (shouldReload) reload();
|
if (shouldReload) reload();
|
||||||
}}
|
}}
|
||||||
onViewStudents={
|
onViewStudents={
|
||||||
selectedUser.type === "corporate" ||
|
selectedUser.type === "corporate" || selectedUser.type === "teacher"
|
||||||
selectedUser.type === "teacher"
|
? () => {
|
||||||
? () => {
|
appendUserFilters({
|
||||||
appendUserFilters({
|
id: "view-students",
|
||||||
id: "view-students",
|
filter: (x: User) => x.type === "student",
|
||||||
filter: (x: User) => x.type === "student",
|
});
|
||||||
});
|
appendUserFilters({
|
||||||
appendUserFilters({
|
id: "belongs-to-admin",
|
||||||
id: "belongs-to-admin",
|
filter: (x: User) =>
|
||||||
filter: (x: User) =>
|
groups
|
||||||
groups
|
.filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
|
||||||
.filter(
|
.flatMap((g) => g.participants)
|
||||||
(g) =>
|
.includes(x.id),
|
||||||
g.admin === selectedUser.id ||
|
});
|
||||||
g.participants.includes(selectedUser.id)
|
|
||||||
)
|
|
||||||
.flatMap((g) => g.participants)
|
|
||||||
.includes(x.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
router.push("/list/users");
|
router.push("/list/users");
|
||||||
}
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
onViewTeachers={
|
onViewTeachers={
|
||||||
selectedUser.type === "corporate" ||
|
selectedUser.type === "corporate" || selectedUser.type === "student"
|
||||||
selectedUser.type === "student"
|
? () => {
|
||||||
? () => {
|
appendUserFilters({
|
||||||
appendUserFilters({
|
id: "view-teachers",
|
||||||
id: "view-teachers",
|
filter: (x: User) => x.type === "teacher",
|
||||||
filter: (x: User) => x.type === "teacher",
|
});
|
||||||
});
|
appendUserFilters({
|
||||||
appendUserFilters({
|
id: "belongs-to-admin",
|
||||||
id: "belongs-to-admin",
|
filter: (x: User) =>
|
||||||
filter: (x: User) =>
|
groups
|
||||||
groups
|
.filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id))
|
||||||
.filter(
|
.flatMap((g) => g.participants)
|
||||||
(g) =>
|
.includes(x.id),
|
||||||
g.admin === selectedUser.id ||
|
});
|
||||||
g.participants.includes(selectedUser.id)
|
|
||||||
)
|
|
||||||
.flatMap((g) => g.participants)
|
|
||||||
.includes(x.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
router.push("/list/users");
|
router.push("/list/users");
|
||||||
}
|
}
|
||||||
@@ -878,8 +831,8 @@ export default function MasterCorporateDashboard({user}: Props) {
|
|||||||
{page === "corporate" && <CorporateList />}
|
{page === "corporate" && <CorporateList />}
|
||||||
{page === "assignments" && <AssignmentsPage />}
|
{page === "assignments" && <AssignmentsPage />}
|
||||||
{page === "studentsPerformance" && <StudentPerformancePage />}
|
{page === "studentsPerformance" && <StudentPerformancePage />}
|
||||||
{page === "statistical" && <MasterStatisticalPage />}
|
{page === "statistical" && <MasterStatisticalPage />}
|
||||||
{page === "" && <DefaultDashboard />}
|
{page === "" && <DefaultDashboard />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,94 +1,78 @@
|
|||||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import type {NextApiRequest, NextApiResponse} from "next";
|
||||||
import { app } from "@/firebase";
|
import {app} from "@/firebase";
|
||||||
import {
|
import {getFirestore, collection, getDocs, setDoc, doc, query, where} from "firebase/firestore";
|
||||||
getFirestore,
|
import {withIronSessionApiRoute} from "iron-session/next";
|
||||||
collection,
|
import {sessionOptions} from "@/lib/session";
|
||||||
getDocs,
|
import {Group} from "@/interfaces/user";
|
||||||
setDoc,
|
import {v4} from "uuid";
|
||||||
doc,
|
import {updateExpiryDateOnGroup, getGroupsForUser} from "@/utils/groups.be";
|
||||||
query,
|
|
||||||
where,
|
|
||||||
} from "firebase/firestore";
|
|
||||||
import { withIronSessionApiRoute } from "iron-session/next";
|
|
||||||
import { sessionOptions } from "@/lib/session";
|
|
||||||
import { Group } from "@/interfaces/user";
|
|
||||||
import { v4 } from "uuid";
|
|
||||||
import { updateExpiryDateOnGroup, getGroupsForUser } from "@/utils/groups.be";
|
|
||||||
|
|
||||||
const db = getFirestore(app);
|
const db = getFirestore(app);
|
||||||
|
|
||||||
export default withIronSessionApiRoute(handler, sessionOptions);
|
export default withIronSessionApiRoute(handler, sessionOptions);
|
||||||
|
|
||||||
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
if (!req.session.user) {
|
if (!req.session.user) {
|
||||||
res.status(401).json({ ok: false });
|
res.status(401).json({ok: false});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.method === "GET") await get(req, res);
|
if (req.method === "GET") await get(req, res);
|
||||||
if (req.method === "POST") await post(req, res);
|
if (req.method === "POST") await post(req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function get(req: NextApiRequest, res: NextApiResponse) {
|
async function get(req: NextApiRequest, res: NextApiResponse) {
|
||||||
const { admin, participant } = req.query as {
|
const {admin, participant} = req.query as {
|
||||||
admin: string;
|
admin: string;
|
||||||
participant: string;
|
participant: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (req.session?.user?.type === "mastercorporate") {
|
if (req.session?.user?.type === "mastercorporate") {
|
||||||
try {
|
try {
|
||||||
const masterCorporateGroups = await getGroupsForUser(admin, participant);
|
const masterCorporateGroups = await getGroupsForUser(admin, participant);
|
||||||
const corporatesFromMaster = masterCorporateGroups
|
const corporatesFromMaster = masterCorporateGroups.filter((g) => g.name === "Corporate").flatMap((g) => g.participants);
|
||||||
.filter((g) => g.name === "Corporate")
|
|
||||||
.flatMap((g) => g.participants);
|
|
||||||
|
|
||||||
if (corporatesFromMaster.length === 0) {
|
if (corporatesFromMaster.length === 0) {
|
||||||
res.status(200).json([]);
|
res.status(200).json(masterCorporateGroups);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Promise.all(
|
Promise.all(corporatesFromMaster.map((c) => getGroupsForUser(c, participant)))
|
||||||
corporatesFromMaster.map((c) => getGroupsForUser(c, participant))
|
.then((groups) => {
|
||||||
)
|
res.status(200).json([...masterCorporateGroups, ...groups.flat()]);
|
||||||
.then((groups) => {
|
return;
|
||||||
res.status(200).json([...masterCorporateGroups, ...groups.flat()]);
|
})
|
||||||
return;
|
.catch((e) => {
|
||||||
})
|
console.error(e);
|
||||||
.catch((e) => {
|
res.status(500).json({ok: false});
|
||||||
console.error(e);
|
return;
|
||||||
res.status(500).json({ ok: false });
|
});
|
||||||
return;
|
} catch (e) {
|
||||||
});
|
console.error(e);
|
||||||
} catch (e) {
|
res.status(500).json({ok: false});
|
||||||
console.error(e);
|
return;
|
||||||
res.status(500).json({ ok: false });
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const groups = await getGroupsForUser(admin, participant);
|
const groups = await getGroupsForUser(admin, participant);
|
||||||
res.status(200).json(groups);
|
res.status(200).json(groups);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
res.status(500).json({ ok: false });
|
res.status(500).json({ok: false});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function post(req: NextApiRequest, res: NextApiResponse) {
|
async function post(req: NextApiRequest, res: NextApiResponse) {
|
||||||
const body = req.body as Group;
|
const body = req.body as Group;
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(body.participants.map(async (p) => await updateExpiryDateOnGroup(p, body.admin)));
|
||||||
body.participants.map(
|
|
||||||
async (p) => await updateExpiryDateOnGroup(p, body.admin)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
await setDoc(doc(db, "groups", v4()), {
|
await setDoc(doc(db, "groups", v4()), {
|
||||||
name: body.name,
|
name: body.name,
|
||||||
admin: body.admin,
|
admin: body.admin,
|
||||||
participants: body.participants,
|
participants: body.participants,
|
||||||
});
|
});
|
||||||
res.status(200).json({ ok: true });
|
res.status(200).json({ok: true});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user