diff --git a/src/dashboards/Admin.tsx b/src/dashboards/Admin.tsx index 7613a5dd..96d1cfb2 100644 --- a/src/dashboards/Admin.tsx +++ b/src/dashboards/Admin.tsx @@ -2,576 +2,686 @@ import Modal from "@/components/Modal"; import useStats from "@/hooks/useStats"; import useUsers from "@/hooks/useUsers"; -import {User} from "@/interfaces/user"; +import { 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, useState } from "react"; import { - BsArrowLeft, - BsBriefcaseFill, - BsGlobeCentralSouthAsia, - BsPerson, - BsPersonFill, - BsPencilSquare, - BsBank, - BsCurrencyDollar, - BsLayoutWtf, - BsLayoutSidebar, + BsArrowLeft, + BsBriefcaseFill, + BsGlobeCentralSouthAsia, + BsPerson, + BsPersonFill, + BsPencilSquare, + BsBank, + BsCurrencyDollar, + BsLayoutWtf, + BsLayoutSidebar, } from "react-icons/bs"; import UserCard from "@/components/UserCard"; import useGroups from "@/hooks/useGroups"; import IconCard from "./IconCard"; import useFilterStore from "@/stores/listFilterStore"; -import {useRouter} from "next/router"; +import { useRouter } from "next/router"; import usePaymentStatusUsers from "@/hooks/usePaymentStatusUsers"; interface Props { - user: User; + user: User; } -export default function AdminDashboard({user}: Props) { - const [page, setPage] = useState(""); - const [selectedUser, setSelectedUser] = useState(); - const [showModal, setShowModal] = useState(false); +export default function AdminDashboard({ user }: Props) { + const [page, setPage] = useState(""); + const [selectedUser, setSelectedUser] = useState(); + const [showModal, setShowModal] = useState(false); - const {stats} = useStats(user.id); - const {users, reload} = useUsers(); - const {groups} = useGroups(); - const {pending, done} = usePaymentStatusUsers(); + const { stats } = useStats(user.id); + const { users, reload } = useUsers(); + const { groups } = useGroups(); + const { pending, done } = usePaymentStatusUsers(); - 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]); - // eslint-disable-next-line react-hooks/exhaustive-deps - useEffect(reload, [page]); + // eslint-disable-next-line react-hooks/exhaustive-deps + useEffect(reload, [page]); - const inactiveCountryManagerFilter = (x: User) => - x.type === "agent" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); + const inactiveCountryManagerFilter = (x: User) => + x.type === "agent" && + (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); - 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.type === "corporate" - ? displayUser.corporateInformation?.companyInformation?.name || displayUser.name - : 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.type === "corporate" + ? displayUser.corporateInformation?.companyInformation?.name || + displayUser.name + : displayUser.name} + + {displayUser.email} +
+
+ ); - const StudentsList = () => { - const filter = (x: User) => - x.type === "student" && - (!!selectedUser - ? groups - .filter((g) => g.admin === selectedUser.id || g.participants.includes(selectedUser.id)) - .flatMap((g) => g.participants) - .includes(x.id) - : true); + const StudentsList = () => { + const filter = (x: User) => + x.type === "student" && + (!!selectedUser + ? groups + .filter( + (g) => + g.admin === selectedUser.id || + g.participants.includes(selectedUser.id) + ) + .flatMap((g) => g.participants) + .includes(x.id) + : true); - return ( - <> -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> - - Back -
-

Students ({users.filter(filter).length})

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

-
+ const AgentsList = () => { + const filter = (x: User) => x.type === "agent"; - - - ); - }; + 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 +
+

+ Country Managers ({total}) +

+
+ )} + /> + ); + }; - const AgentsList = () => { - const filter = (x: User) => x.type === "agent"; + const CorporateList = () => ( + x.type === "corporate"]} + renderHeader={(total) => ( +
+
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 +
+

Corporate ({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 -
-

Country Managers ({users.filter(filter).length})

-
+ const CorporatePaidStatusList = ({ paid }: { paid: Boolean }) => { + const list = paid ? done : pending; + const filter = (x: User) => x.type === "corporate" && list.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 +
+

+ {paid ? "Payment Done" : "Pending Payment"} ({total}) +

+
+ )} + /> + ); + }; - const CorporateList = () => ( - <> -
-
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 -
-

Corporate ({users.filter((x) => x.type === "corporate").length})

-
+ const InactiveCountryManagerList = () => { + 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 +
+

+ Inactive Country Managers ({total}) +

+
+ )} + /> + ); + }; - x.type === "corporate"]} /> - - ); + const InactiveStudentsList = () => { + const filter = (x: User) => + x.type === "student" && + (x.status === "disabled" || + moment().isAfter(x.subscriptionExpirationDate)); - const CorporatePaidStatusList = ({paid}: {paid: Boolean}) => { - const list = paid ? done : pending; - const filter = (x: User) => x.type === "corporate" && list.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 +
+

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

- {paid ? "Payment Done" : "Pending Payment"} ({list.length}) -

-
- - - ); - }; + const InactiveCorporateList = () => { + const filter = (x: User) => + x.type === "corporate" && + (x.status === "disabled" || + moment().isAfter(x.subscriptionExpirationDate)); - const InactiveCountryManagerList = () => { - 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 -
-

Inactive Country Managers ({users.filter(inactiveCountryManagerFilter).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 +
+

+ Inactive Corporate ({total}) +

+
+ )} + /> + ); + }; - - - ); - }; + const DefaultDashboard = () => ( + <> +
+ x.type === "student").length} + onClick={() => setPage("students")} + color="purple" + /> + x.type === "teacher").length} + onClick={() => setPage("teachers")} + color="purple" + /> + x.type === "corporate").length} + onClick={() => setPage("corporate")} + color="purple" + /> + x.type === "agent").length} + onClick={() => setPage("agents")} + color="purple" + /> + x.demographicInformation) + .map((x) => x.demographicInformation?.country) + ), + ].length + } + color="purple" + /> + setPage("inactiveStudents")} + Icon={BsPersonFill} + label="Inactive Students" + value={ + users.filter( + (x) => + x.type === "student" && + (x.status === "disabled" || + moment().isAfter(x.subscriptionExpirationDate)) + ).length + } + color="rose" + /> + setPage("inactiveCountryManagers")} + Icon={BsBriefcaseFill} + label="Inactive Country Managers" + value={users.filter(inactiveCountryManagerFilter).length} + color="rose" + /> + setPage("inactiveCorporate")} + Icon={BsBank} + label="Inactive Corporate" + value={ + users.filter( + (x) => + x.type === "corporate" && + (x.status === "disabled" || + moment().isAfter(x.subscriptionExpirationDate)) + ).length + } + color="rose" + /> + setPage("paymentdone")} + Icon={BsCurrencyDollar} + label="Payment Done" + value={done.length} + color="purple" + /> + setPage("paymentpending")} + Icon={BsCurrencyDollar} + label="Pending Payment" + value={pending.length} + color="rose" + /> + router.push("https://cms.encoach.com/admin")} + Icon={BsLayoutSidebar} + label="Content Management System (CMS)" + color="green" + /> +
- const InactiveStudentsList = () => { - const filter = (x: User) => x.type === "student" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); +
+
+ Latest students +
+ {users + .filter((x) => x.type === "student") + .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) + .map((x) => ( + + ))} +
+
+
+ Latest teachers +
+ {users + .filter((x) => x.type === "teacher") + .sort((a, b) => { + return dateSorter(a, b, "desc", "registrationDate"); + }) + .map((x) => ( + + ))} +
+
+
+ Latest corporate +
+ {users + .filter((x) => x.type === "corporate") + .sort((a, b) => { + return dateSorter(a, b, "desc", "registrationDate"); + }) + .map((x) => ( + + ))} +
+
+
+ Unpaid Corporate +
+ {users + .filter( + (x) => x.type === "corporate" && x.status === "paymentDue" + ) + .map((x) => ( + + ))} +
+
+
+ Students expiring in 1 month +
+ {users + .filter( + (x) => + x.type === "student" && + x.subscriptionExpirationDate && + moment().isAfter( + moment(x.subscriptionExpirationDate).subtract(30, "days") + ) && + moment().isBefore(moment(x.subscriptionExpirationDate)) + ) + .map((x) => ( + + ))} +
+
+
+ Teachers expiring in 1 month +
+ {users + .filter( + (x) => + x.type === "teacher" && + x.subscriptionExpirationDate && + moment().isAfter( + moment(x.subscriptionExpirationDate).subtract(30, "days") + ) && + moment().isBefore(moment(x.subscriptionExpirationDate)) + ) + .map((x) => ( + + ))} +
+
+
+ Country Manager expiring in 1 month +
+ {users + .filter( + (x) => + x.type === "agent" && + x.subscriptionExpirationDate && + moment().isAfter( + moment(x.subscriptionExpirationDate).subtract(30, "days") + ) && + moment().isBefore(moment(x.subscriptionExpirationDate)) + ) + .map((x) => ( + + ))} +
+
+
+ Corporate expiring in 1 month +
+ {users + .filter( + (x) => + x.type === "corporate" && + x.subscriptionExpirationDate && + moment().isAfter( + moment(x.subscriptionExpirationDate).subtract(30, "days") + ) && + moment().isBefore(moment(x.subscriptionExpirationDate)) + ) + .map((x) => ( + + ))} +
+
+
+ Expired Students +
+ {users + .filter( + (x) => + x.type === "student" && + x.subscriptionExpirationDate && + moment().isAfter(moment(x.subscriptionExpirationDate)) + ) + .map((x) => ( + + ))} +
+
+
+ Expired Teachers +
+ {users + .filter( + (x) => + x.type === "teacher" && + x.subscriptionExpirationDate && + moment().isAfter(moment(x.subscriptionExpirationDate)) + ) + .map((x) => ( + + ))} +
+
+
+ Expired Country Manager +
+ {users + .filter( + (x) => + x.type === "agent" && + x.subscriptionExpirationDate && + moment().isAfter(moment(x.subscriptionExpirationDate)) + ) + .map((x) => ( + + ))} +
+
+
+ Expired Corporate +
+ {users + .filter( + (x) => + x.type === "corporate" && + x.subscriptionExpirationDate && + moment().isAfter(moment(x.subscriptionExpirationDate)) + ) + .map((x) => ( + + ))} +
+
+
+ + ); - 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 -
-

Inactive Students ({users.filter(filter).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), + }); - - - ); - }; + 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), + }); - const InactiveCorporateList = () => { - const filter = (x: User) => x.type === "corporate" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); + router.push("/list/users"); + } + : undefined + } + onViewCorporate={ + selectedUser.type === "teacher" || + selectedUser.type === "student" + ? () => { + appendUserFilters({ + id: "view-corporate", + filter: (x: User) => x.type === "corporate", + }); + appendUserFilters({ + id: "belongs-to-admin", + filter: (x: User) => + groups + .filter((g) => + g.participants.includes(selectedUser.id) + ) + .flatMap((g) => [g.admin, ...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 -
-

Inactive Corporate ({users.filter(filter).length})

-
- - - - ); - }; - - const DefaultDashboard = () => ( - <> -
- x.type === "student").length} - onClick={() => setPage("students")} - color="purple" - /> - x.type === "teacher").length} - onClick={() => setPage("teachers")} - color="purple" - /> - x.type === "corporate").length} - onClick={() => setPage("corporate")} - color="purple" - /> - x.type === "agent").length} - onClick={() => setPage("agents")} - color="purple" - /> - x.demographicInformation).map((x) => x.demographicInformation?.country))].length} - color="purple" - /> - setPage("inactiveStudents")} - Icon={BsPersonFill} - label="Inactive Students" - value={ - users.filter((x) => x.type === "student" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate))) - .length - } - color="rose" - /> - setPage("inactiveCountryManagers")} - Icon={BsBriefcaseFill} - label="Inactive Country Managers" - value={users.filter(inactiveCountryManagerFilter).length} - color="rose" - /> - setPage("inactiveCorporate")} - Icon={BsBank} - label="Inactive Corporate" - value={ - users.filter((x) => x.type === "corporate" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate))) - .length - } - color="rose" - /> - setPage("paymentdone")} Icon={BsCurrencyDollar} label="Payment Done" value={done.length} color="purple" /> - setPage("paymentpending")} - Icon={BsCurrencyDollar} - label="Pending Payment" - value={pending.length} - color="rose" - /> - router.push("https://cms.encoach.com/admin")} - Icon={BsLayoutSidebar} - label="Content Management System (CMS)" - color="green" - /> -
- -
-
- Latest students -
- {users - .filter((x) => x.type === "student") - .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) - .map((x) => ( - - ))} -
-
-
- Latest teachers -
- {users - .filter((x) => x.type === "teacher") - .sort((a, b) => { - return dateSorter(a, b, "desc", "registrationDate"); - }) - .map((x) => ( - - ))} -
-
-
- Latest corporate -
- {users - .filter((x) => x.type === "corporate") - .sort((a, b) => { - return dateSorter(a, b, "desc", "registrationDate"); - }) - .map((x) => ( - - ))} -
-
-
- Unpaid Corporate -
- {users - .filter((x) => x.type === "corporate" && x.status === "paymentDue") - .map((x) => ( - - ))} -
-
-
- Students expiring in 1 month -
- {users - .filter( - (x) => - x.type === "student" && - x.subscriptionExpirationDate && - moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) && - moment().isBefore(moment(x.subscriptionExpirationDate)), - ) - .map((x) => ( - - ))} -
-
-
- Teachers expiring in 1 month -
- {users - .filter( - (x) => - x.type === "teacher" && - x.subscriptionExpirationDate && - moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) && - moment().isBefore(moment(x.subscriptionExpirationDate)), - ) - .map((x) => ( - - ))} -
-
-
- Country Manager expiring in 1 month -
- {users - .filter( - (x) => - x.type === "agent" && - x.subscriptionExpirationDate && - moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) && - moment().isBefore(moment(x.subscriptionExpirationDate)), - ) - .map((x) => ( - - ))} -
-
-
- Corporate expiring in 1 month -
- {users - .filter( - (x) => - x.type === "corporate" && - x.subscriptionExpirationDate && - moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) && - moment().isBefore(moment(x.subscriptionExpirationDate)), - ) - .map((x) => ( - - ))} -
-
-
- Expired Students -
- {users - .filter( - (x) => x.type === "student" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)), - ) - .map((x) => ( - - ))} -
-
-
- Expired Teachers -
- {users - .filter( - (x) => x.type === "teacher" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)), - ) - .map((x) => ( - - ))} -
-
-
- Expired Country Manager -
- {users - .filter( - (x) => x.type === "agent" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)), - ) - .map((x) => ( - - ))} -
-
-
- Expired Corporate -
- {users - .filter( - (x) => - x.type === "corporate" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)), - ) - .map((x) => ( - - ))} -
-
-
- - ); - - 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 - } - onViewCorporate={ - selectedUser.type === "teacher" || selectedUser.type === "student" - ? () => { - appendUserFilters({ - id: "view-corporate", - filter: (x: User) => x.type === "corporate", - }); - appendUserFilters({ - id: "belongs-to-admin", - filter: (x: User) => - groups - .filter((g) => g.participants.includes(selectedUser.id)) - .flatMap((g) => [g.admin, ...g.participants]) - .includes(x.id), - }); - - router.push("/list/users"); - } - : undefined - } - user={selectedUser} - /> -
- )} - -
- {page === "students" && } - {page === "teachers" && } - {page === "corporate" && } - {page === "agents" && } - {page === "inactiveStudents" && } - {page === "inactiveCorporate" && } - {page === "inactiveCountryManagers" && } - {page === "paymentdone" && } - {page === "paymentpending" && } - {page === "" && } - - ); + router.push("/list/users"); + } + : undefined + } + user={selectedUser} + /> +
+ )} + +
+ {page === "students" && } + {page === "teachers" && } + {page === "corporate" && } + {page === "agents" && } + {page === "inactiveStudents" && } + {page === "inactiveCorporate" && } + {page === "inactiveCountryManagers" && } + {page === "paymentdone" && } + {page === "paymentpending" && } + {page === "" && } + + ); } diff --git a/src/dashboards/Agent.tsx b/src/dashboards/Agent.tsx index 88148158..bff2c46d 100644 --- a/src/dashboards/Agent.tsx +++ b/src/dashboards/Agent.tsx @@ -2,243 +2,294 @@ import Modal from "@/components/Modal"; import useStats from "@/hooks/useStats"; import useUsers from "@/hooks/useUsers"; -import { User} from "@/interfaces/user"; +import { 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 {BsArrowLeft, BsPersonFill, BsBank, BsCurrencyDollar} from "react-icons/bs"; +import { useEffect, useState } from "react"; +import { + BsArrowLeft, + BsPersonFill, + BsBank, + BsCurrencyDollar, +} from "react-icons/bs"; import UserCard from "@/components/UserCard"; import useGroups from "@/hooks/useGroups"; import IconCard from "./IconCard"; -import usePaymentStatusUsers from '@/hooks/usePaymentStatusUsers'; +import usePaymentStatusUsers from "@/hooks/usePaymentStatusUsers"; interface Props { - user: User; + user: User; } -export default function AgentDashboard({user}: Props) { - const [page, setPage] = useState(""); - const [selectedUser, setSelectedUser] = useState(); - const [showModal, setShowModal] = useState(false); +export default function AgentDashboard({ user }: Props) { + const [page, setPage] = useState(""); + const [selectedUser, setSelectedUser] = useState(); + const [showModal, setShowModal] = useState(false); - const {stats} = useStats(); - const {users, reload} = useUsers(); - const {groups} = useGroups(user.id); - const { pending, done } = usePaymentStatusUsers(); + const { stats } = useStats(); + const { users, reload } = useUsers(); + const { groups } = useGroups(user.id); + const { pending, done } = usePaymentStatusUsers(); - useEffect(() => { - setShowModal(!!selectedUser && page === ""); - }, [selectedUser, page]); + useEffect(() => { + setShowModal(!!selectedUser && page === ""); + }, [selectedUser, page]); - const corporateFilter = (user: User) => user.type === "corporate"; - const referredCorporateFilter = (x: User) => - x.type === "corporate" && !!x.corporateInformation && x.corporateInformation.referralAgent === user.id; - const inactiveReferredCorporateFilter = (x: User) => - referredCorporateFilter(x) && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); + const corporateFilter = (user: User) => user.type === "corporate"; + const referredCorporateFilter = (x: User) => + x.type === "corporate" && + !!x.corporateInformation && + x.corporateInformation.referralAgent === user.id; + const inactiveReferredCorporateFilter = (x: User) => + referredCorporateFilter(x) && + (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); - const UserDisplay = ({ displayUser, allowClick = true }: {displayUser: User, allowClick?: boolean}) => ( -
allowClick && 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.type === "corporate" - ? displayUser.corporateInformation?.companyInformation?.name || displayUser.name - : displayUser.name} - - {displayUser.email} -
-
- ); + const UserDisplay = ({ + displayUser, + allowClick = true, + }: { + displayUser: User; + allowClick?: boolean; + }) => ( +
allowClick && 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.type === "corporate" + ? displayUser.corporateInformation?.companyInformation?.name || + displayUser.name + : displayUser.name} + + {displayUser.email} +
+
+ ); - const ReferredCorporateList = () => { - 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 -
-

Referred Corporate ({users.filter(referredCorporateFilter).length})

-
+ const ReferredCorporateList = () => { + 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 +
+

+ Referred Corporate ({total}) +

+
+ )} + /> + ); + }; - - - ); - }; + const InactiveReferredCorporateList = () => { + 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 +
+

+ Inactive Referred Corporate ({total}) +

+
+ )} + /> + ); + }; - const InactiveReferredCorporateList = () => { - 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 -
-

Inactive Referred Corporate ({users.filter(inactiveReferredCorporateFilter).length})

-
+ const CorporateList = () => { + const filter = (x: User) => x.type === "corporate"; - - - ); - }; + 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 +
+

Corporate ({total})

+
+ )} + /> + ); + }; - const CorporateList = () => { - const filter = (x: User) => x.type === "corporate"; + const CorporatePaidStatusList = ({ paid }: { paid: Boolean }) => { + const list = paid ? done : pending; + const filter = (x: User) => x.type === "corporate" && list.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 -
-

Corporate ({users.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 +
+

+ {paid ? "Payment Done" : "Pending Payment"} ({total}) +

+
+ )} + /> + ); + }; - const CorporatePaidStatusList = ({ paid }: {paid: Boolean}) => { - const list = paid ? done : pending; - const filter = (x: User) => x.type === "corporate" && list.includes(x.id); + const DefaultDashboard = () => ( + <> +
+ setPage("referredCorporate")} + Icon={BsBank} + label="Referred Corporate" + value={users.filter(referredCorporateFilter).length} + color="purple" + /> + setPage("inactiveReferredCorporate")} + Icon={BsBank} + label="Inactive Referred Corporate" + value={users.filter(inactiveReferredCorporateFilter).length} + color="rose" + /> + setPage("corporate")} + Icon={BsBank} + label="Corporate" + value={users.filter(corporateFilter).length} + color="purple" + /> + setPage("paymentdone")} + Icon={BsCurrencyDollar} + label="Payment Done" + value={done.length} + color="purple" + /> + setPage("paymentpending")} + Icon={BsCurrencyDollar} + label="Pending Payment" + value={pending.length} + color="rose" + /> +
- 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 -
-

{paid ? 'Payment Done' : 'Pending Payment'} ({list.length})

-
- - - ); - }; +
+
+ Latest Referred Corporate +
+ {users + .filter(referredCorporateFilter) + .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) + .map((x) => ( + + ))} +
+
+
+ Latest corporate +
+ {users + .filter(corporateFilter) + .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) + .map((x) => ( + + ))} +
+
+
+ Referenced corporate expiring in 1 month +
+ {users + .filter( + (x) => + referredCorporateFilter(x) && + moment().isAfter( + moment(x.subscriptionExpirationDate).subtract(30, "days") + ) && + moment().isBefore(moment(x.subscriptionExpirationDate)) + ) + .map((x) => ( + + ))} +
+
+
+ + ); - const DefaultDashboard = () => ( - <> -
- setPage("referredCorporate")} - Icon={BsBank} - label="Referred Corporate" - value={users.filter(referredCorporateFilter).length} - color="purple" - /> - setPage("inactiveReferredCorporate")} - Icon={BsBank} - label="Inactive Referred Corporate" - value={users.filter(inactiveReferredCorporateFilter).length} - color="rose" - /> - setPage("corporate")} - Icon={BsBank} - label="Corporate" - value={users.filter(corporateFilter).length} - color="purple" - /> - setPage("paymentdone")} - Icon={BsCurrencyDollar} - label="Payment Done" - value={done.length} - color="purple" - /> - setPage("paymentpending")} - Icon={BsCurrencyDollar} - label="Pending Payment" - value={pending.length} - color="rose" - /> -
- -
-
- Latest Referred Corporate -
- {users - .filter(referredCorporateFilter) - .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) - .map((x) => ( - - ))} -
-
-
- Latest corporate -
- {users - .filter(corporateFilter) - .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) - .map((x) => ( - - ))} -
-
-
- Referenced corporate expiring in 1 month -
- {users - .filter( - (x) => - referredCorporateFilter(x) && - moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) && - moment().isBefore(moment(x.subscriptionExpirationDate)), - ) - .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 === "referredCorporate" && } - {page === "corporate" && } - {page === "inactiveReferredCorporate" && } - {page === "paymentdone" && } - {page === "paymentpending" && } - {page === "" && } - - ); + 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 === "referredCorporate" && } + {page === "corporate" && } + {page === "inactiveReferredCorporate" && ( + + )} + {page === "paymentdone" && } + {page === "paymentpending" && } + {page === "" && } + + ); } diff --git a/src/dashboards/Corporate.tsx b/src/dashboards/Corporate.tsx index 49bad1e8..94d5e5ab 100644 --- a/src/dashboards/Corporate.tsx +++ b/src/dashboards/Corporate.tsx @@ -2,325 +2,395 @@ import Modal from "@/components/Modal"; import useStats from "@/hooks/useStats"; 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, useState } from "react"; import { - BsArrowLeft, - BsClipboard2Data, - BsClipboard2DataFill, - BsClock, - BsGlobeCentralSouthAsia, - BsPaperclip, - BsPerson, - BsPersonAdd, - BsPersonFill, - BsPersonFillGear, - BsPersonGear, - BsPencilSquare, - BsPersonBadge, - BsPersonCheck, - BsPeople, + BsArrowLeft, + BsClipboard2Data, + BsClipboard2DataFill, + BsClock, + BsGlobeCentralSouthAsia, + BsPaperclip, + BsPerson, + BsPersonAdd, + BsPersonFill, + BsPersonFillGear, + BsPersonGear, + BsPencilSquare, + BsPersonBadge, + BsPersonCheck, + BsPeople, } 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 useFilterStore from "@/stores/listFilterStore"; -import {useRouter} from "next/router"; +import { useRouter } from "next/router"; import useCodes from "@/hooks/useCodes"; interface Props { - user: CorporateUser; + user: CorporateUser; } -export default function CorporateDashboard({user}: Props) { - const [page, setPage] = useState(""); - const [selectedUser, setSelectedUser] = useState(); - const [showModal, setShowModal] = useState(false); +export default function CorporateDashboard({ user }: Props) { + const [page, setPage] = useState(""); + const [selectedUser, setSelectedUser] = useState(); + const [showModal, setShowModal] = useState(false); - const {stats} = useStats(); - const {users, reload} = useUsers(); - const {codes} = useCodes(user.id); - const {groups} = useGroups(user.id); + const { stats } = useStats(); + const { users, reload } = useUsers(); + const { codes } = useCodes(user.id); + const { groups } = useGroups(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]); - 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 studentFilter = (user: User) => + user.type === "student" && + groups.flatMap((g) => g.participants).includes(user.id); + const teacherFilter = (user: User) => + user.type === "teacher" && + groups.flatMap((g) => g.participants).includes(user.id); - const getStatsByStudent = (user: User) => stats.filter((s) => s.user === user.id); + const getStatsByStudent = (user: User) => + stats.filter((s) => s.user === user.id); - const UserDisplay = (displayUser: User) => ( -
setSelectedUser(displayUser)} - className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300"> - {displayUser.name} -
- {displayUser.name} - {displayUser.email} -
-
- ); + const UserDisplay = (displayUser: User) => ( +
setSelectedUser(displayUser)} + className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300" + > + {displayUser.name} +
+ {displayUser.name} + {displayUser.email} +
+
+ ); - const StudentsList = () => { - const filter = (x: User) => - x.type === "student" && - (!!selectedUser - ? groups - .filter((g) => g.admin === selectedUser.id) - .flatMap((g) => g.participants) - .includes(x.id) || false - : groups.flatMap((g) => g.participants).includes(x.id)); + const StudentsList = () => { + const filter = (x: User) => + x.type === "student" && + (!!selectedUser + ? groups + .filter((g) => g.admin === selectedUser.id) + .flatMap((g) => g.participants) + .includes(x.id) || false + : groups.flatMap((g) => g.participants).includes(x.id)); - return ( - <> -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> - - Back -
-

Students ({users.filter(filter).length})

-
+ 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 + ? groups + .filter((g) => g.admin === selectedUser.id) + .flatMap((g) => g.participants) + .includes(x.id) || false + : groups.flatMap((g) => g.participants).includes(x.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 +
+

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 ({users.filter(filter).length})

-
+ const GroupsList = () => { + const filter = (x: Group) => + x.admin === user.id || x.participants.includes(user.id); - - - ); - }; + return ( + <> +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" + > + + Back +
+

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

+
- const GroupsList = () => { - const filter = (x: Group) => x.admin === user.id || x.participants.includes(user.id); + + + ); + }; - return ( - <> -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> - - Back -
-

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

-
+ const averageLevelCalculator = (studentStats: Stat[]) => { + const formattedStats = studentStats + .map((s) => ({ + focus: users.find((u) => u.id === s.user)?.focus, + score: s.score, + module: s.module, + })) + .filter((f) => !!f.focus); + const bandScores = formattedStats.map((s) => ({ + module: s.module, + level: calculateBandScore( + s.score.correct, + s.score.total, + s.module, + s.focus! + ), + })); - - - ); - }; + const levels: { [key in Module]: number } = { + reading: 0, + listening: 0, + writing: 0, + speaking: 0, + level: 0, + }; + bandScores.forEach((b) => (levels[b.module] += b.level)); - 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 calculateAverageLevel(levels); + }; - 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 = () => ( + <> +
+ 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" + /> + + +
- return calculateAverageLevel(levels); - }; +
+
+ 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" /> - - -
+ 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 - } - 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 === "" && } - - ); + router.push("/list/users"); + } + : undefined + } + user={selectedUser} + /> +
+ )} + +
+ {page === "students" && } + {page === "teachers" && } + {page === "groups" && } + {page === "" && } + + ); } diff --git a/src/dashboards/Teacher.tsx b/src/dashboards/Teacher.tsx index f5c64125..855dfc69 100644 --- a/src/dashboards/Teacher.tsx +++ b/src/dashboards/Teacher.tsx @@ -2,380 +2,477 @@ import Modal from "@/components/Modal"; import useStats from "@/hooks/useStats"; 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, 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 { getUserCorporate } from "@/utils/groups"; 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 {stats} = useStats(); - const {users, reload} = useUsers(); - const {groups} = useGroups(user.id); - const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({assigner: user.id}); + const { stats } = useStats(); + const { users, reload } = useUsers(); + const { groups } = useGroups(user.id); + const { + assignments, + isLoading: isAssignmentsLoading, + reload: reloadAssignments, + } = useAssignments({ assigner: user.id }); - useEffect(() => { - setShowModal(!!selectedUser && page === ""); - }, [selectedUser, page]); + useEffect(() => { + setShowModal(!!selectedUser && page === ""); + }, [selectedUser, page]); - useEffect(() => { - getUserCorporate(user.id).then(setCorporateUserToShow); - }, [user]); + useEffect(() => { + getUserCorporate(user.id).then(setCorporateUserToShow); + }, [user]); - const studentFilter = (user: User) => user.type === "student" && groups.flatMap((g) => g.participants).includes(user.id); + const studentFilter = (user: User) => + user.type === "student" && + groups.flatMap((g) => g.participants).includes(user.id); - const getStatsByStudent = (user: User) => stats.filter((s) => s.user === user.id); + const getStatsByStudent = (user: User) => + stats.filter((s) => s.user === user.id); - const UserDisplay = (displayUser: User) => ( -
setSelectedUser(displayUser)} - className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300"> - {displayUser.name} -
- {displayUser.name} - {displayUser.email} -
-
- ); + const UserDisplay = (displayUser: User) => ( +
setSelectedUser(displayUser)} + className="flex w-full p-4 gap-4 items-center hover:bg-mti-purple-ultralight cursor-pointer transition ease-in-out duration-300" + > + {displayUser.name} +
+ {displayUser.name} + {displayUser.email} +
+
+ ); - const StudentsList = () => { - const filter = (x: User) => - x.type === "student" && - (!!selectedUser - ? groups - .filter((g) => g.admin === selectedUser.id) - .flatMap((g) => g.participants) - .includes(x.id) || false - : groups.flatMap((g) => g.participants).includes(x.id)); + const StudentsList = () => { + const filter = (x: User) => + x.type === "student" && + (!!selectedUser + ? groups + .filter((g) => g.admin === selectedUser.id) + .flatMap((g) => g.participants) + .includes(x.id) || false + : groups.flatMap((g) => g.participants).includes(x.id)); - return ( - <> -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> - - Back -
-

Students ({users.filter(filter).length})

-
+ 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 GroupsList = () => { - const filter = (x: Group) => x.admin === user.id || x.participants.includes(user.id); + return ( + <> +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" + > + + Back +
+

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

+
- return ( - <> -
-
setPage("")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> - - Back -
-

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

-
+ + + ); + }; - - - ); - }; + const averageLevelCalculator = (studentStats: Stat[]) => { + const formattedStats = studentStats + .map((s) => ({ + focus: users.find((u) => u.id === s.user)?.focus, + score: s.score, + module: s.module, + })) + .filter((f) => !!f.focus); + const bandScores = formattedStats.map((s) => ({ + module: s.module, + level: calculateBandScore( + s.score.correct, + s.score.total, + s.module, + s.focus! + ), + })); - const averageLevelCalculator = (studentStats: Stat[]) => { - const formattedStats = studentStats - .map((s) => ({focus: users.find((u) => u.id === s.user)?.focus, score: s.score, module: s.module})) - .filter((f) => !!f.focus); - const bandScores = formattedStats.map((s) => ({ - module: s.module, - level: calculateBandScore(s.score.correct, s.score.total, s.module, s.focus!), - })); + const levels: { [key in Module]: number } = { + reading: 0, + listening: 0, + writing: 0, + speaking: 0, + level: 0, + }; + bandScores.forEach((b) => (levels[b.module] += b.level)); - 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); + }; - return calculateAverageLevel(levels); - }; + 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()); + 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(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 + /> + ))} +
+
+
+

+ Archived Assignments ({assignments.filter(archivedFilter).length}) +

+
+ {assignments.filter(archivedFilter).map((a) => ( + setSelectedAssignment(a)} + key={a.id} + allowDownload + reload={reloadAssignments} + allowUnarchive + /> + ))} +
+
+ + ); + }; - 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(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 - /> - ))} -
-
-
-

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

-
- {assignments.filter(archivedFilter).map((a) => ( - setSelectedAssignment(a)} - key={a.id} - allowDownload - reload={reloadAssignments} - allowUnarchive - /> - ))} -
-
- - ); - }; + 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" + /> + 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} + + +
+
- 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" - /> - 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) => ( + + ))} +
+
+
+ + ); -
-
- 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 === "" && } - - ); + 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 === "" && } + + ); } diff --git a/src/pages/(admin)/Lists/UserList.tsx b/src/pages/(admin)/Lists/UserList.tsx index 08d3a59c..7749631d 100644 --- a/src/pages/(admin)/Lists/UserList.tsx +++ b/src/pages/(admin)/Lists/UserList.tsx @@ -1,625 +1,930 @@ import Button from "@/components/Low/Button"; -import {PERMISSIONS} from "@/constants/userPermissions"; +import { PERMISSIONS } from "@/constants/userPermissions"; import useGroups from "@/hooks/useGroups"; import useUsers from "@/hooks/useUsers"; -import {Type, User, userTypes, CorporateUser, Group} from "@/interfaces/user"; -import {Popover, Transition} from "@headlessui/react"; -import {createColumnHelper, flexRender, getCoreRowModel, useReactTable} from "@tanstack/react-table"; +import { Type, User, userTypes, CorporateUser, Group } from "@/interfaces/user"; +import { Popover, Transition } from "@headlessui/react"; +import { + createColumnHelper, + flexRender, + getCoreRowModel, + useReactTable, +} from "@tanstack/react-table"; import axios from "axios"; import clsx from "clsx"; -import {capitalize, reverse} from "lodash"; +import { capitalize, reverse } from "lodash"; import moment from "moment"; -import {Fragment, useEffect, useState} from "react"; -import {BsArrowDown, BsArrowDownUp, BsArrowUp, BsCheck, BsCheckCircle, BsEye, BsFillExclamationOctagonFill, BsPerson, BsTrash} from "react-icons/bs"; -import {toast} from "react-toastify"; -import {countries, TCountries} from "countries-list"; +import { Fragment, useEffect, useState } from "react"; +import { + BsArrowDown, + BsArrowDownUp, + BsArrowUp, + BsCheck, + BsCheckCircle, + BsEye, + BsFillExclamationOctagonFill, + BsPerson, + BsTrash, +} from "react-icons/bs"; +import { toast } from "react-toastify"; +import { countries, TCountries } from "countries-list"; import countryCodes from "country-codes-list"; import Modal from "@/components/Modal"; import UserCard from "@/components/UserCard"; -import {getUserCompanyName, isAgentUser, USER_TYPE_LABELS} from "@/resources/user"; +import { + getUserCompanyName, + isAgentUser, + USER_TYPE_LABELS, +} from "@/resources/user"; import useFilterStore from "@/stores/listFilterStore"; -import {useRouter} from "next/router"; -import {isCorporateUser} from "@/resources/user"; -import {useListSearch} from "@/hooks/useListSearch"; -import {getUserCorporate} from "@/utils/groups"; -import {asyncSorter} from "@/utils"; -import {exportListToExcel, UserListRow} from "@/utils/users"; +import { useRouter } from "next/router"; +import { isCorporateUser } from "@/resources/user"; +import { useListSearch } from "@/hooks/useListSearch"; +import { getUserCorporate } from "@/utils/groups"; +import { asyncSorter } from "@/utils"; +import { exportListToExcel, UserListRow } from "@/utils/users"; const columnHelper = createColumnHelper(); -const searchFields = [["name"], ["email"], ["corporateInformation", "companyInformation", "name"]]; +const searchFields = [ + ["name"], + ["email"], + ["corporateInformation", "companyInformation", "name"], +]; -const CompanyNameCell = ({users, user, groups}: {user: User; users: User[]; groups: Group[]}) => { - const [companyName, setCompanyName] = useState(""); - const [isLoading, setIsLoading] = useState(false); +const CompanyNameCell = ({ + users, + user, + groups, +}: { + user: User; + users: User[]; + groups: Group[]; +}) => { + const [companyName, setCompanyName] = useState(""); + const [isLoading, setIsLoading] = useState(false); - useEffect(() => { - const name = getUserCompanyName(user, users, groups); - setCompanyName(name); - }, [user, users, groups]); + useEffect(() => { + const name = getUserCompanyName(user, users, groups); + setCompanyName(name); + }, [user, users, groups]); - return isLoading ? Loading... : <>{companyName}; + return isLoading ? ( + Loading... + ) : ( + <>{companyName} + ); }; -export default function UserList({user, filters = []}: {user: User; filters?: ((user: User) => boolean)[]}) { - const [showDemographicInformation, setShowDemographicInformation] = useState(false); - const [sorter, setSorter] = useState(); - const [displayUsers, setDisplayUsers] = useState([]); - const [selectedUser, setSelectedUser] = useState(); +export default function UserList({ + user, + filters = [], + renderHeader, +}: { + user: User; + filters?: ((user: User) => boolean)[]; + renderHeader?: (total: number) => JSX.Element; +}) { + const [showDemographicInformation, setShowDemographicInformation] = + useState(false); + const [sorter, setSorter] = useState(); + const [displayUsers, setDisplayUsers] = useState([]); + const [selectedUser, setSelectedUser] = useState(); - const {users, reload} = useUsers(); - const {groups} = useGroups(user && (user?.type === "corporate" || user?.type === "teacher") ? user.id : undefined); + const { users, reload } = useUsers(); + const { groups } = useGroups( + user && (user?.type === "corporate" || user?.type === "teacher") + ? user.id + : undefined + ); - const appendUserFilters = useFilterStore((state) => state.appendUserFilter); - const router = useRouter(); + const appendUserFilters = useFilterStore((state) => state.appendUserFilter); + const router = useRouter(); - const expirationDateColor = (date: Date) => { - const momentDate = moment(date); - const today = moment(new Date()); + const expirationDateColor = (date: Date) => { + const momentDate = moment(date); + const today = moment(new Date()); - if (today.isAfter(momentDate)) return "!text-mti-red-light font-bold line-through"; - if (today.add(1, "weeks").isAfter(momentDate)) return "!text-mti-red-light"; - if (today.add(2, "weeks").isAfter(momentDate)) return "!text-mti-rose-light"; - if (today.add(1, "months").isAfter(momentDate)) return "!text-mti-orange-light"; - }; + if (today.isAfter(momentDate)) + return "!text-mti-red-light font-bold line-through"; + if (today.add(1, "weeks").isAfter(momentDate)) return "!text-mti-red-light"; + if (today.add(2, "weeks").isAfter(momentDate)) + return "!text-mti-rose-light"; + if (today.add(1, "months").isAfter(momentDate)) + return "!text-mti-orange-light"; + }; - useEffect(() => { - (async () => { - if (user && users) { - const filterUsers = - user.type === "corporate" || user.type === "teacher" - ? users.filter((u) => groups.flatMap((g) => g.participants).includes(u.id)) - : users; + useEffect(() => { + (async () => { + if (user && users) { + const filterUsers = + user.type === "corporate" || user.type === "teacher" + ? users.filter((u) => + groups.flatMap((g) => g.participants).includes(u.id) + ) + : users; - const filteredUsers = filters.reduce((d, f) => d.filter(f), filterUsers); - const sortedUsers = await asyncSorter(filteredUsers, sortFunction); - console.log(sortedUsers); + const filteredUsers = filters.reduce( + (d, f) => d.filter(f), + filterUsers + ); + const sortedUsers = await asyncSorter( + filteredUsers, + sortFunction + ); + console.log(sortedUsers); - setDisplayUsers([...sortedUsers]); - } - })(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [user, users, sorter, groups]); + setDisplayUsers([...sortedUsers]); + } + })(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [user, users, sorter, groups]); - const deleteAccount = (user: User) => { - if (!confirm(`Are you sure you want to delete ${user.name}'s account?`)) return; + const deleteAccount = (user: User) => { + if (!confirm(`Are you sure you want to delete ${user.name}'s account?`)) + return; - axios - .delete<{ok: boolean}>(`/api/user?id=${user.id}`) - .then(() => { - toast.success("User deleted successfully!"); - reload(); - }) - .catch(() => { - toast.error("Something went wrong!", {toastId: "delete-error"}); - }) - .finally(reload); - }; + axios + .delete<{ ok: boolean }>(`/api/user?id=${user.id}`) + .then(() => { + toast.success("User deleted successfully!"); + reload(); + }) + .catch(() => { + toast.error("Something went wrong!", { toastId: "delete-error" }); + }) + .finally(reload); + }; - const updateAccountType = (user: User, type: Type) => { - if (!confirm(`Are you sure you want to update ${user.name}'s account from ${capitalize(user.type)} to ${capitalize(type)}?`)) return; + const updateAccountType = (user: User, type: Type) => { + if ( + !confirm( + `Are you sure you want to update ${ + user.name + }'s account from ${capitalize(user.type)} to ${capitalize(type)}?` + ) + ) + return; - axios - .post<{user?: User; ok?: boolean}>(`/api/users/update?id=${user.id}`, {...user, type}) - .then(() => { - toast.success("User type updated successfully!"); - reload(); - }) - .catch(() => { - toast.error("Something went wrong!", {toastId: "update-error"}); - }); - }; + axios + .post<{ user?: User; ok?: boolean }>(`/api/users/update?id=${user.id}`, { + ...user, + type, + }) + .then(() => { + toast.success("User type updated successfully!"); + reload(); + }) + .catch(() => { + toast.error("Something went wrong!", { toastId: "update-error" }); + }); + }; - const verifyAccount = (user: User) => { - axios - .post<{user?: User; ok?: boolean}>(`/api/users/update?id=${user.id}`, {...user, isVerified: true}) - .then(() => { - toast.success("User verified successfully!"); - reload(); - }) - .catch(() => { - toast.error("Something went wrong!", {toastId: "update-error"}); - }); - }; + const verifyAccount = (user: User) => { + axios + .post<{ user?: User; ok?: boolean }>(`/api/users/update?id=${user.id}`, { + ...user, + isVerified: true, + }) + .then(() => { + toast.success("User verified successfully!"); + reload(); + }) + .catch(() => { + toast.error("Something went wrong!", { toastId: "update-error" }); + }); + }; - const toggleDisableAccount = (user: User) => { - if ( - !confirm( - `Are you sure you want to ${user.status === "disabled" ? "enable" : "disable"} ${ - user.name - }'s account? This change is usually related to their payment state.`, - ) - ) - return; + const toggleDisableAccount = (user: User) => { + if ( + !confirm( + `Are you sure you want to ${ + user.status === "disabled" ? "enable" : "disable" + } ${ + user.name + }'s account? This change is usually related to their payment state.` + ) + ) + return; - axios - .post<{user?: User; ok?: boolean}>(`/api/users/update?id=${user.id}`, { - ...user, - status: user.status === "disabled" ? "active" : "disabled", - }) - .then(() => { - toast.success(`User ${user.status === "disabled" ? "enabled" : "disabled"} successfully!`); - reload(); - }) - .catch(() => { - toast.error("Something went wrong!", {toastId: "update-error"}); - }); - }; + axios + .post<{ user?: User; ok?: boolean }>(`/api/users/update?id=${user.id}`, { + ...user, + status: user.status === "disabled" ? "active" : "disabled", + }) + .then(() => { + toast.success( + `User ${ + user.status === "disabled" ? "enabled" : "disabled" + } successfully!` + ); + reload(); + }) + .catch(() => { + toast.error("Something went wrong!", { toastId: "update-error" }); + }); + }; - const SorterArrow = ({name}: {name: string}) => { - if (sorter === name) return ; - if (sorter === reverseString(name)) return ; + const SorterArrow = ({ name }: { name: string }) => { + if (sorter === name) return ; + if (sorter === reverseString(name)) return ; - return ; - }; + return ; + }; - const actionColumn = ({row}: {row: {original: User}}) => { - return ( -
- {PERMISSIONS.updateUser[row.original.type].includes(user.type) && ( - - -
- -
-
- - -
- - - - -
-
-
-
- )} - {!row.original.isVerified && PERMISSIONS.updateUser[row.original.type].includes(user.type) && ( -
verifyAccount(row.original)}> - -
- )} - {PERMISSIONS.updateUser[row.original.type].includes(user.type) && ( -
toggleDisableAccount(row.original)}> - {row.original.status === "disabled" ? ( - - ) : ( - - )} -
- )} - {PERMISSIONS.deleteUser[row.original.type].includes(user.type) && ( -
deleteAccount(row.original)}> - -
- )} -
- ); - }; + const actionColumn = ({ row }: { row: { original: User } }) => { + return ( +
+ {PERMISSIONS.updateUser[row.original.type].includes(user.type) && ( + + +
+ +
+
+ + +
+ + + + +
+
+
+
+ )} + {!row.original.isVerified && + PERMISSIONS.updateUser[row.original.type].includes(user.type) && ( +
verifyAccount(row.original)} + > + +
+ )} + {PERMISSIONS.updateUser[row.original.type].includes(user.type) && ( +
toggleDisableAccount(row.original)} + > + {row.original.status === "disabled" ? ( + + ) : ( + + )} +
+ )} + {PERMISSIONS.deleteUser[row.original.type].includes(user.type) && ( +
deleteAccount(row.original)} + > + +
+ )} +
+ ); + }; - const demographicColumns = [ - columnHelper.accessor("name", { - header: ( - - ) as any, - cell: ({row, getValue}) => ( -
(PERMISSIONS.updateExpiryDate[row.original.type].includes(user.type) ? setSelectedUser(row.original) : null)}> - {getValue()} -
- ), - }), - columnHelper.accessor("demographicInformation.country", { - header: ( - - ) as any, - cell: (info) => - info.getValue() - ? `${countryCodes.findOne("countryCode" as any, info.getValue()).flag} ${ - countries[info.getValue() as unknown as keyof TCountries].name - } (+${countryCodes.findOne("countryCode" as any, info.getValue()).countryCallingCode})` - : "Not available", - }), - columnHelper.accessor("demographicInformation.phone", { - header: ( - - ) as any, - cell: (info) => info.getValue() || "Not available", - enableSorting: true, - }), - columnHelper.accessor((x) => (x.type === "corporate" ? x.demographicInformation?.position : x.demographicInformation?.employment), { - id: "employment", - header: ( - - ) as any, - cell: (info) => (info.row.original.type === "corporate" ? info.getValue() : capitalize(info.getValue())) || "Not available", - enableSorting: true, - }), - columnHelper.accessor("demographicInformation.gender", { - header: ( - - ) as any, - cell: (info) => capitalize(info.getValue()) || "Not available", - enableSorting: true, - }), - { - header: ( - setShowDemographicInformation((prev) => !prev)}> - Switch - - ), - id: "actions", - cell: actionColumn, - }, - ]; + const demographicColumns = [ + columnHelper.accessor("name", { + header: ( + + ) as any, + cell: ({ row, getValue }) => ( +
+ PERMISSIONS.updateExpiryDate[row.original.type].includes(user.type) + ? setSelectedUser(row.original) + : null + } + > + {getValue()} +
+ ), + }), + columnHelper.accessor("demographicInformation.country", { + header: ( + + ) as any, + cell: (info) => + info.getValue() + ? `${ + countryCodes.findOne("countryCode" as any, info.getValue()).flag + } ${ + countries[info.getValue() as unknown as keyof TCountries].name + } (+${ + countryCodes.findOne("countryCode" as any, info.getValue()) + .countryCallingCode + })` + : "Not available", + }), + columnHelper.accessor("demographicInformation.phone", { + header: ( + + ) as any, + cell: (info) => info.getValue() || "Not available", + enableSorting: true, + }), + columnHelper.accessor( + (x) => + x.type === "corporate" + ? x.demographicInformation?.position + : x.demographicInformation?.employment, + { + id: "employment", + header: ( + + ) as any, + cell: (info) => + (info.row.original.type === "corporate" + ? info.getValue() + : capitalize(info.getValue())) || "Not available", + enableSorting: true, + } + ), + columnHelper.accessor("demographicInformation.gender", { + header: ( + + ) as any, + cell: (info) => capitalize(info.getValue()) || "Not available", + enableSorting: true, + }), + { + header: ( + setShowDemographicInformation((prev) => !prev)} + > + Switch + + ), + id: "actions", + cell: actionColumn, + }, + ]; - const defaultColumns = [ - columnHelper.accessor("name", { - header: ( - - ) as any, - cell: ({row, getValue}) => ( -
(PERMISSIONS.updateExpiryDate[row.original.type].includes(user.type) ? setSelectedUser(row.original) : null)}> - {row.original.type === "corporate" ? row.original.corporateInformation?.companyInformation?.name || getValue() : getValue()} -
- ), - }), - columnHelper.accessor("email", { - header: ( - - ) as any, - cell: ({row, getValue}) => ( -
(PERMISSIONS.updateExpiryDate[row.original.type].includes(user.type) ? setSelectedUser(row.original) : null)}> - {getValue()} -
- ), - }), - columnHelper.accessor("type", { - header: ( - - ) as any, - cell: (info) => USER_TYPE_LABELS[info.getValue()], - }), - columnHelper.accessor("corporateInformation.companyInformation.name", { - header: ( - - ) as any, - cell: (info) => , - }), - columnHelper.accessor("subscriptionExpirationDate", { - header: ( - - ) as any, - cell: (info) => ( - - {!info.getValue() ? "No expiry date" : moment(info.getValue()).format("DD/MM/YYYY")} - - ), - }), - columnHelper.accessor("isVerified", { - header: ( - - ) as any, - cell: (info) => ( -
-
- -
-
- ), - }), - { - header: ( - setShowDemographicInformation((prev) => !prev)}> - Switch - - ), - id: "actions", - cell: actionColumn, - }, - ]; + const defaultColumns = [ + columnHelper.accessor("name", { + header: ( + + ) as any, + cell: ({ row, getValue }) => ( +
+ PERMISSIONS.updateExpiryDate[row.original.type].includes(user.type) + ? setSelectedUser(row.original) + : null + } + > + {row.original.type === "corporate" + ? row.original.corporateInformation?.companyInformation?.name || + getValue() + : getValue()} +
+ ), + }), + columnHelper.accessor("email", { + header: ( + + ) as any, + cell: ({ row, getValue }) => ( +
+ PERMISSIONS.updateExpiryDate[row.original.type].includes(user.type) + ? setSelectedUser(row.original) + : null + } + > + {getValue()} +
+ ), + }), + columnHelper.accessor("type", { + header: ( + + ) as any, + cell: (info) => USER_TYPE_LABELS[info.getValue()], + }), + columnHelper.accessor("corporateInformation.companyInformation.name", { + header: ( + + ) as any, + cell: (info) => ( + + ), + }), + columnHelper.accessor("subscriptionExpirationDate", { + header: ( + + ) as any, + cell: (info) => ( + + {!info.getValue() + ? "No expiry date" + : moment(info.getValue()).format("DD/MM/YYYY")} + + ), + }), + columnHelper.accessor("isVerified", { + header: ( + + ) as any, + cell: (info) => ( +
+
+ +
+
+ ), + }), + { + header: ( + setShowDemographicInformation((prev) => !prev)} + > + Switch + + ), + id: "actions", + cell: actionColumn, + }, + ]; - const reverseString = (str: string) => reverse(str.split("")).join(""); + const reverseString = (str: string) => reverse(str.split("")).join(""); - const selectSorter = (previous: string | undefined, name: string) => { - if (!previous) return name; - if (previous === name) return reverseString(name); + const selectSorter = (previous: string | undefined, name: string) => { + if (!previous) return name; + if (previous === name) return reverseString(name); - return undefined; - }; + return undefined; + }; - const sortFunction = async (a: User, b: User) => { - if (sorter === "name" || sorter === reverseString("name")) - return sorter === "name" ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name); + const sortFunction = async (a: User, b: User) => { + if (sorter === "name" || sorter === reverseString("name")) + return sorter === "name" + ? a.name.localeCompare(b.name) + : b.name.localeCompare(a.name); - if (sorter === "email" || sorter === reverseString("email")) - return sorter === "email" ? a.email.localeCompare(b.email) : b.email.localeCompare(a.email); + if (sorter === "email" || sorter === reverseString("email")) + return sorter === "email" + ? a.email.localeCompare(b.email) + : b.email.localeCompare(a.email); - if (sorter === "type" || sorter === reverseString("type")) - return sorter === "type" - ? userTypes.findIndex((t) => a.type === t) - userTypes.findIndex((t) => b.type === t) - : userTypes.findIndex((t) => b.type === t) - userTypes.findIndex((t) => a.type === t); + if (sorter === "type" || sorter === reverseString("type")) + return sorter === "type" + ? userTypes.findIndex((t) => a.type === t) - + userTypes.findIndex((t) => b.type === t) + : userTypes.findIndex((t) => b.type === t) - + userTypes.findIndex((t) => a.type === t); - if (sorter === "verification" || sorter === reverseString("verification")) - return sorter === "verification" - ? a.isVerified.toString().localeCompare(b.isVerified.toString()) - : b.isVerified.toString().localeCompare(a.isVerified.toString()); + if (sorter === "verification" || sorter === reverseString("verification")) + return sorter === "verification" + ? a.isVerified.toString().localeCompare(b.isVerified.toString()) + : b.isVerified.toString().localeCompare(a.isVerified.toString()); - if (sorter === "expiryDate" || sorter === reverseString("expiryDate")) { - if (!a.subscriptionExpirationDate && b.subscriptionExpirationDate) return sorter === "expiryDate" ? -1 : 1; - if (a.subscriptionExpirationDate && !b.subscriptionExpirationDate) return sorter === "expiryDate" ? 1 : -1; - if (!a.subscriptionExpirationDate && !b.subscriptionExpirationDate) return 0; - if (moment(a.subscriptionExpirationDate).isAfter(b.subscriptionExpirationDate)) return sorter === "expiryDate" ? -1 : 1; - if (moment(b.subscriptionExpirationDate).isAfter(a.subscriptionExpirationDate)) return sorter === "expiryDate" ? 1 : -1; - return 0; - } + if (sorter === "expiryDate" || sorter === reverseString("expiryDate")) { + if (!a.subscriptionExpirationDate && b.subscriptionExpirationDate) + return sorter === "expiryDate" ? -1 : 1; + if (a.subscriptionExpirationDate && !b.subscriptionExpirationDate) + return sorter === "expiryDate" ? 1 : -1; + if (!a.subscriptionExpirationDate && !b.subscriptionExpirationDate) + return 0; + if ( + moment(a.subscriptionExpirationDate).isAfter( + b.subscriptionExpirationDate + ) + ) + return sorter === "expiryDate" ? -1 : 1; + if ( + moment(b.subscriptionExpirationDate).isAfter( + a.subscriptionExpirationDate + ) + ) + return sorter === "expiryDate" ? 1 : -1; + return 0; + } - if (sorter === "country" || sorter === reverseString("country")) { - if (!a.demographicInformation?.country && b.demographicInformation?.country) return sorter === "country" ? -1 : 1; - if (a.demographicInformation?.country && !b.demographicInformation?.country) return sorter === "country" ? 1 : -1; - if (!a.demographicInformation?.country && !b.demographicInformation?.country) return 0; + if (sorter === "country" || sorter === reverseString("country")) { + if ( + !a.demographicInformation?.country && + b.demographicInformation?.country + ) + return sorter === "country" ? -1 : 1; + if ( + a.demographicInformation?.country && + !b.demographicInformation?.country + ) + return sorter === "country" ? 1 : -1; + if ( + !a.demographicInformation?.country && + !b.demographicInformation?.country + ) + return 0; - return sorter === "country" - ? a.demographicInformation!.country.localeCompare(b.demographicInformation!.country) - : b.demographicInformation!.country.localeCompare(a.demographicInformation!.country); - } + return sorter === "country" + ? a.demographicInformation!.country.localeCompare( + b.demographicInformation!.country + ) + : b.demographicInformation!.country.localeCompare( + a.demographicInformation!.country + ); + } - if (sorter === "phone" || sorter === reverseString("phone")) { - if (!a.demographicInformation?.phone && b.demographicInformation?.phone) return sorter === "phone" ? -1 : 1; - if (a.demographicInformation?.phone && !b.demographicInformation?.phone) return sorter === "phone" ? 1 : -1; - if (!a.demographicInformation?.phone && !b.demographicInformation?.phone) return 0; + if (sorter === "phone" || sorter === reverseString("phone")) { + if (!a.demographicInformation?.phone && b.demographicInformation?.phone) + return sorter === "phone" ? -1 : 1; + if (a.demographicInformation?.phone && !b.demographicInformation?.phone) + return sorter === "phone" ? 1 : -1; + if (!a.demographicInformation?.phone && !b.demographicInformation?.phone) + return 0; - return sorter === "phone" - ? a.demographicInformation!.phone.localeCompare(b.demographicInformation!.phone) - : b.demographicInformation!.phone.localeCompare(a.demographicInformation!.phone); - } + return sorter === "phone" + ? a.demographicInformation!.phone.localeCompare( + b.demographicInformation!.phone + ) + : b.demographicInformation!.phone.localeCompare( + a.demographicInformation!.phone + ); + } - if (sorter === "employment" || sorter === reverseString("employment")) { - const aSortingItem = a.type === "corporate" ? a.demographicInformation?.position : a.demographicInformation?.employment; - const bSortingItem = b.type === "corporate" ? b.demographicInformation?.position : b.demographicInformation?.employment; + if (sorter === "employment" || sorter === reverseString("employment")) { + const aSortingItem = + a.type === "corporate" + ? a.demographicInformation?.position + : a.demographicInformation?.employment; + const bSortingItem = + b.type === "corporate" + ? b.demographicInformation?.position + : b.demographicInformation?.employment; - if (!aSortingItem && bSortingItem) return sorter === "employment" ? -1 : 1; - if (aSortingItem && !bSortingItem) return sorter === "employment" ? 1 : -1; - if (!aSortingItem && !bSortingItem) return 0; + if (!aSortingItem && bSortingItem) + return sorter === "employment" ? -1 : 1; + if (aSortingItem && !bSortingItem) + return sorter === "employment" ? 1 : -1; + if (!aSortingItem && !bSortingItem) return 0; - return sorter === "employment" ? aSortingItem!.localeCompare(bSortingItem!) : bSortingItem!.localeCompare(aSortingItem!); - } + return sorter === "employment" + ? aSortingItem!.localeCompare(bSortingItem!) + : bSortingItem!.localeCompare(aSortingItem!); + } - if (sorter === "gender" || sorter === reverseString("gender")) { - if (!a.demographicInformation?.gender && b.demographicInformation?.gender) return sorter === "employment" ? -1 : 1; - if (a.demographicInformation?.gender && !b.demographicInformation?.gender) return sorter === "employment" ? 1 : -1; - if (!a.demographicInformation?.gender && !b.demographicInformation?.gender) return 0; + if (sorter === "gender" || sorter === reverseString("gender")) { + if (!a.demographicInformation?.gender && b.demographicInformation?.gender) + return sorter === "employment" ? -1 : 1; + if (a.demographicInformation?.gender && !b.demographicInformation?.gender) + return sorter === "employment" ? 1 : -1; + if ( + !a.demographicInformation?.gender && + !b.demographicInformation?.gender + ) + return 0; - return sorter === "gender" - ? a.demographicInformation!.gender.localeCompare(b.demographicInformation!.gender) - : b.demographicInformation!.gender.localeCompare(a.demographicInformation!.gender); - } + return sorter === "gender" + ? a.demographicInformation!.gender.localeCompare( + b.demographicInformation!.gender + ) + : b.demographicInformation!.gender.localeCompare( + a.demographicInformation!.gender + ); + } - if (sorter === "companyName" || sorter === reverseString("companyName")) { - const aCorporateName = getUserCompanyName(a, users, groups); - const bCorporateName = getUserCompanyName(b, users, groups); - if (!aCorporateName && bCorporateName) return sorter === "companyName" ? -1 : 1; - if (aCorporateName && !bCorporateName) return sorter === "companyName" ? 1 : -1; - if (!aCorporateName && !bCorporateName) return 0; + if (sorter === "companyName" || sorter === reverseString("companyName")) { + const aCorporateName = getUserCompanyName(a, users, groups); + const bCorporateName = getUserCompanyName(b, users, groups); + if (!aCorporateName && bCorporateName) + return sorter === "companyName" ? -1 : 1; + if (aCorporateName && !bCorporateName) + return sorter === "companyName" ? 1 : -1; + if (!aCorporateName && !bCorporateName) return 0; - return sorter === "companyName" ? aCorporateName.localeCompare(bCorporateName) : bCorporateName.localeCompare(aCorporateName); - } + return sorter === "companyName" + ? aCorporateName.localeCompare(bCorporateName) + : bCorporateName.localeCompare(aCorporateName); + } - return a.id.localeCompare(b.id); - }; + return a.id.localeCompare(b.id); + }; - const {rows: filteredRows, renderSearch} = useListSearch(searchFields, displayUsers); + const { rows: filteredRows, renderSearch } = useListSearch( + searchFields, + displayUsers + ); - const table = useReactTable({ - data: filteredRows, - columns: (!showDemographicInformation ? defaultColumns : demographicColumns) as any, - getCoreRowModel: getCoreRowModel(), - }); + const table = useReactTable({ + data: filteredRows, + columns: (!showDemographicInformation + ? defaultColumns + : demographicColumns) as any, + getCoreRowModel: getCoreRowModel(), + }); - const downloadExcel = () => { - const csv = exportListToExcel(filteredRows, users, groups); + const downloadExcel = () => { + const csv = exportListToExcel(filteredRows, users, groups); - const element = document.createElement("a"); - const file = new Blob([csv], {type: "text/csv"}); - element.href = URL.createObjectURL(file); - element.download = "users.csv"; - document.body.appendChild(element); - element.click(); - document.body.removeChild(element); - }; + const element = document.createElement("a"); + const file = new Blob([csv], { type: "text/csv" }); + element.href = URL.createObjectURL(file); + element.download = "users.csv"; + document.body.appendChild(element); + element.click(); + document.body.removeChild(element); + }; - return ( -
- setSelectedUser(undefined)}> - <> - {selectedUser && ( -
- { - 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), - }); + return ( + <> + {renderHeader && renderHeader(displayUsers.length)} +
+ setSelectedUser(undefined)}> + <> + {selectedUser && ( +
+ { + 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 + } + 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 - } - onViewCorporate={ - selectedUser.type === "teacher" || selectedUser.type === "student" - ? () => { - appendUserFilters({ - id: "view-corporate", - filter: (x: User) => x.type === "corporate", - }); - appendUserFilters({ - id: "belongs-to-admin", - filter: (x: User) => - groups - .filter((g) => g.participants.includes(selectedUser.id)) - .flatMap((g) => [g.admin, ...g.participants]) - .includes(x.id), - }); + router.push("/list/users"); + } + : undefined + } + onViewCorporate={ + selectedUser.type === "teacher" || + selectedUser.type === "student" + ? () => { + appendUserFilters({ + id: "view-corporate", + filter: (x: User) => x.type === "corporate", + }); + appendUserFilters({ + id: "belongs-to-admin", + filter: (x: User) => + groups + .filter((g) => + g.participants.includes(selectedUser.id) + ) + .flatMap((g) => [g.admin, ...g.participants]) + .includes(x.id), + }); - router.push("/list/users"); - } - : undefined - } - onClose={(shouldReload) => { - setSelectedUser(undefined); - if (shouldReload) reload(); - }} - user={selectedUser} - /> -
- )} - -
-
-
- {renderSearch()} - -
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - ))} - - ))} - - - {table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - ))} - - ))} - -
- {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())} -
- {flexRender(cell.column.columnDef.cell, cell.getContext())} -
-
-
- ); + router.push("/list/users"); + } + : undefined + } + onClose={(shouldReload) => { + setSelectedUser(undefined); + if (shouldReload) reload(); + }} + user={selectedUser} + /> +
+ )} + +
+
+
+ {renderSearch()} + +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + ))} + + ))} + + + {table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + ))} + + ))} + +
+ {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} +
+ {flexRender(cell.column.columnDef.cell, cell.getContext())} +
+
+
+ + ); } diff --git a/src/pages/list/users.tsx b/src/pages/list/users.tsx index 3ec4c585..a04193b8 100644 --- a/src/pages/list/users.tsx +++ b/src/pages/list/users.tsx @@ -1,77 +1,85 @@ import Layout from "@/components/High/Layout"; import useUser from "@/hooks/useUser"; import useUsers from "@/hooks/useUsers"; -import {sessionOptions} from "@/lib/session"; +import { sessionOptions } from "@/lib/session"; import useFilterStore from "@/stores/listFilterStore"; -import {withIronSessionSsr} from "iron-session/next"; +import { withIronSessionSsr } from "iron-session/next"; import Head from "next/head"; -import {useRouter} from "next/router"; -import {useEffect} from "react"; -import {BsArrowLeft} from "react-icons/bs"; -import {ToastContainer} from "react-toastify"; +import { useRouter } from "next/router"; +import { useEffect } from "react"; +import { BsArrowLeft } from "react-icons/bs"; +import { ToastContainer } from "react-toastify"; import UserList from "../(admin)/Lists/UserList"; -export const getServerSideProps = withIronSessionSsr(({req, res}) => { - const user = req.session.user; +export const getServerSideProps = withIronSessionSsr(({ req, res }) => { + const user = req.session.user; - const envVariables: {[key: string]: string} = {}; - Object.keys(process.env) - .filter((x) => x.startsWith("NEXT_PUBLIC")) - .forEach((x: string) => { - envVariables[x] = process.env[x]!; - }); + const envVariables: { [key: string]: string } = {}; + Object.keys(process.env) + .filter((x) => x.startsWith("NEXT_PUBLIC")) + .forEach((x: string) => { + envVariables[x] = process.env[x]!; + }); - if (!user || !user.isVerified) { - return { - redirect: { - destination: "/login", - permanent: false, - } - }; - } + if (!user || !user.isVerified) { + return { + redirect: { + destination: "/login", + permanent: false, + }, + }; + } - return { - props: {user: req.session.user, envVariables}, - }; + return { + props: { user: req.session.user, envVariables }, + }; }, sessionOptions); export default function UsersListPage() { - const {user} = useUser(); - const {users} = useUsers(); - const [filters, clearFilters] = useFilterStore((state) => [state.userFilters, state.clearUserFilters]); - const router = useRouter(); + const { user } = useUser(); + const { users } = useUsers(); + const [filters, clearFilters] = useFilterStore((state) => [ + state.userFilters, + state.clearUserFilters, + ]); + const router = useRouter(); - return ( - <> - - EnCoach - - - - - + return ( + <> + + EnCoach + + + + + - {user && ( - -
-
{ - clearFilters(); - router.back(); - }} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> - - Back -
-

Users ({filters.map((f) => f.filter).reduce((d, f) => d.filter(f), users).length})

-
- - f.filter)} /> -
- )} - - ); + {user && ( + + f.filter)} + renderHeader={(total) => ( +
+
{ + clearFilters(); + router.back(); + }} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" + > + + Back +
+

Users ({total})

+
+ )} + /> +
+ )} + + ); }