diff --git a/src/components/DemographicInformationInput.tsx b/src/components/DemographicInformationInput.tsx index a042cf19..3f32eb49 100644 --- a/src/components/DemographicInformationInput.tsx +++ b/src/components/DemographicInformationInput.tsx @@ -17,7 +17,7 @@ import moment from "moment"; interface Props { user: User; - mutateUser: KeyedMutator; + mutateUser: (user: User) => void; } export default function DemographicInformationInput({user, mutateUser}: Props) { @@ -42,7 +42,7 @@ export default function DemographicInformationInput({user, mutateUser}: Props) { setIsLoading(true); axios - .patch("/api/users/update", { + .patch<{user: User}>("/api/users/update", { demographicInformation: { country, phone: `+${countryCodes.findOne("countryCode" as any, country!).countryCallingCode}${phone}`, @@ -54,7 +54,7 @@ export default function DemographicInformationInput({user, mutateUser}: Props) { }, agentInformation: user.type === "agent" ? {companyName, commercialRegistration} : undefined, }) - .then((response) => mutateUser((response.data as {user: User}).user)) + .then((response) => mutateUser(response.data.user)) .catch(() => { toast.error("Something went wrong, please try again later!", {toastId: "user-update-error"}); }) @@ -89,7 +89,15 @@ export default function DemographicInformationInput({user, mutateUser}: Props) { - setPhone(e)} value={phone} placeholder="Enter phone number" required /> + setPhone(e)} + value={phone} + placeholder="Enter phone number" + required + /> {user.type === "student" && ( , - achieved: user.levels.reading >= user.desiredLevels.reading, + achieved: user.levels?.reading || 0 >= user.desiredLevels?.reading || 9, }, { module: "listening", icon: () => , - achieved: user.levels.listening >= user.desiredLevels.listening, + achieved: user.levels?.listening || 0 >= user.desiredLevels?.listening || 9, }, { module: "writing", icon: () => , - achieved: user.levels.writing >= user.desiredLevels.writing, + achieved: user.levels?.writing || 0 >= user.desiredLevels?.writing || 9, }, { module: "speaking", icon: () => , - achieved: user.levels.speaking >= user.desiredLevels.speaking, + achieved: user.levels?.speaking || 0 >= user.desiredLevels?.speaking || 9, }, { module: "level", icon: () => , - achieved: user.levels.level >= user.desiredLevels.level, + achieved: user.levels?.level || 0 >= user.desiredLevels?.level || 9, }, ]; diff --git a/src/dashboards/Admin.tsx b/src/dashboards/Admin.tsx index e3bc48ce..f2a7af67 100644 --- a/src/dashboards/Admin.tsx +++ b/src/dashboards/Admin.tsx @@ -31,12 +31,40 @@ interface Props { user: User; } +const studentHash = { + type: "student", + size: 25, + orderBy: "registrationDate", +}; + +const teacherHash = { + type: "teacher", + size: 25, + orderBy: "registrationDate", +}; + +const corporateHash = { + type: "corporate", + size: 25, + orderBy: "registrationDate", +}; + +const agentsHash = { + type: "agent", + size: 25, + orderBy: "registrationDate", +}; + export default function AdminDashboard({user}: Props) { const [page, setPage] = useState(""); const [selectedUser, setSelectedUser] = useState(); const [showModal, setShowModal] = useState(false); - const {users, reload, isLoading} = useUsers(); + const {users: students, total: totalStudents, reload: reloadStudents, isLoading: isStudentsLoading} = useUsers(studentHash); + const {users: teachers, total: totalTeachers, reload: reloadTeachers, isLoading: isTeachersLoading} = useUsers(teacherHash); + const {users: corporates, total: totalCorporate, reload: reloadCorporates, isLoading: isCorporatesLoading} = useUsers(corporateHash); + const {users: agents, total: totalAgents, reload: reloadAgents, isLoading: isAgentsLoading} = useUsers(corporateHash); + const {groups} = useGroups({}); const {pending, done} = usePaymentStatusUsers(); @@ -47,9 +75,6 @@ export default function AdminDashboard({user}: Props) { setShowModal(!!selectedUser && router.asPath === "/#"); }, [selectedUser, router.asPath]); - // eslint-disable-next-line react-hooks/exhaustive-deps - useEffect(reload, [page]); - const inactiveCountryManagerFilter = (x: User) => x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate); const UserDisplay = (displayUser: User) => ( @@ -279,50 +304,50 @@ export default function AdminDashboard({user}: Props) {
x.type === "student").length} + value={totalStudents} onClick={() => router.push("/#students")} color="purple" /> x.type === "teacher").length} + value={totalTeachers} onClick={() => router.push("/#teachers")} color="purple" /> x.type === "corporate").length} + value={totalCorporate} onClick={() => router.push("/#corporate")} color="purple" /> x.type === "agent").length} + value={totalAgents} onClick={() => router.push("/#agents")} color="purple" /> x.demographicInformation).map((x) => x.demographicInformation?.country))].length} + value={[...new Set(agents.filter((x) => x.demographicInformation).map((x) => x.demographicInformation?.country))].length} color="purple" /> router.push("/#inactiveStudents")} Icon={BsPersonFill} - isLoading={isLoading} + isLoading={isStudentsLoading} label="Inactive Students" value={ - users.filter((x) => x.type === "student" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate))) + students.filter((x) => x.type === "student" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate))) .length } color="rose" @@ -330,26 +355,26 @@ export default function AdminDashboard({user}: Props) { router.push("/#inactiveCountryManagers")} Icon={BsBriefcaseFill} - isLoading={isLoading} + isLoading={isAgentsLoading} label="Inactive Country Managers" - value={users.filter(inactiveCountryManagerFilter).length} + value={agents.filter(inactiveCountryManagerFilter).length} color="rose" /> router.push("/#inactiveCorporate")} Icon={BsBank} - isLoading={isLoading} + isLoading={isCorporatesLoading} label="Inactive Corporate" value={ - users.filter((x) => x.type === "corporate" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate))) - .length + corporates.filter( + (x) => x.type === "corporate" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)), + ).length } color="rose" /> router.push("/#paymentdone")} Icon={BsCurrencyDollar} - isLoading={isLoading} label="Payment Done" value={done.length} color="purple" @@ -357,7 +382,6 @@ export default function AdminDashboard({user}: Props) { router.push("/#paymentpending")} Icon={BsCurrencyDollar} - isLoading={isLoading} label="Pending Payment" value={pending.length} color="rose" @@ -365,14 +389,13 @@ export default function AdminDashboard({user}: Props) { router.push("https://cms.encoach.com/admin")} Icon={BsLayoutSidebar} - isLoading={isLoading} label="Content Management System (CMS)" color="green" /> router.push("/#corporatestudentslevels")} Icon={BsPersonFill} - isLoading={isLoading} + isLoading={isStudentsLoading} label="Corporate Students Levels" color="purple" /> @@ -382,8 +405,7 @@ export default function AdminDashboard({user}: Props) {
Latest students
- {users - .filter((x) => x.type === "student") + {students .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) .map((x) => ( @@ -393,8 +415,7 @@ export default function AdminDashboard({user}: Props) {
Latest teachers
- {users - .filter((x) => x.type === "teacher") + {teachers .sort((a, b) => { return dateSorter(a, b, "desc", "registrationDate"); }) @@ -406,8 +427,7 @@ export default function AdminDashboard({user}: Props) {
Latest corporate
- {users - .filter((x) => x.type === "corporate") + {corporates .sort((a, b) => { return dateSorter(a, b, "desc", "registrationDate"); }) @@ -419,8 +439,8 @@ export default function AdminDashboard({user}: Props) {
Unpaid Corporate
- {users - .filter((x) => x.type === "corporate" && x.status === "paymentDue") + {corporates + .filter((x) => x.status === "paymentDue") .map((x) => ( ))} @@ -429,10 +449,9 @@ export default function AdminDashboard({user}: Props) {
Students expiring in 1 month
- {users + {students .filter( (x) => - x.type === "student" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) && moment().isBefore(moment(x.subscriptionExpirationDate)), @@ -445,10 +464,9 @@ export default function AdminDashboard({user}: Props) {
Teachers expiring in 1 month
- {users + {teachers .filter( (x) => - x.type === "teacher" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) && moment().isBefore(moment(x.subscriptionExpirationDate)), @@ -461,10 +479,9 @@ export default function AdminDashboard({user}: Props) {
Country Manager expiring in 1 month
- {users + {agents .filter( (x) => - x.type === "agent" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) && moment().isBefore(moment(x.subscriptionExpirationDate)), @@ -477,10 +494,9 @@ export default function AdminDashboard({user}: Props) {
Corporate expiring in 1 month
- {users + {corporates .filter( (x) => - x.type === "corporate" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) && moment().isBefore(moment(x.subscriptionExpirationDate)), @@ -493,10 +509,8 @@ export default function AdminDashboard({user}: Props) {
Expired Students
- {users - .filter( - (x) => x.type === "student" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)), - ) + {students + .filter((x) => x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate))) .map((x) => ( ))} @@ -505,10 +519,8 @@ export default function AdminDashboard({user}: Props) {
Expired Teachers
- {users - .filter( - (x) => x.type === "teacher" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)), - ) + {teachers + .filter((x) => x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate))) .map((x) => ( ))} @@ -517,10 +529,8 @@ export default function AdminDashboard({user}: Props) {
Expired Country Manager
- {users - .filter( - (x) => x.type === "agent" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)), - ) + {agents + .filter((x) => x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate))) .map((x) => ( ))} @@ -529,11 +539,8 @@ export default function AdminDashboard({user}: Props) {
Expired Corporate
- {users - .filter( - (x) => - x.type === "corporate" && x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate)), - ) + {corporates + .filter((x) => x.subscriptionExpirationDate && moment().isAfter(moment(x.subscriptionExpirationDate))) .map((x) => ( ))} @@ -553,7 +560,10 @@ export default function AdminDashboard({user}: Props) { loggedInUser={user} onClose={(shouldReload) => { setSelectedUser(undefined); - if (shouldReload) reload(); + if (shouldReload && selectedUser!.type === "student") reloadStudents(); + if (shouldReload && selectedUser!.type === "teacher") reloadTeachers(); + if (shouldReload && selectedUser!.type === "corporate") reloadCorporates(); + if (shouldReload && selectedUser!.type === "agent") reloadAgents(); }} onViewStudents={ selectedUser.type === "corporate" || selectedUser.type === "teacher" diff --git a/src/dashboards/Corporate/index.tsx b/src/dashboards/Corporate/index.tsx index 9fa3187c..f353d055 100644 --- a/src/dashboards/Corporate/index.tsx +++ b/src/dashboards/Corporate/index.tsx @@ -1,400 +1,546 @@ /* eslint-disable @next/next/no-img-element */ import Modal from "@/components/Modal"; import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser"; -import useUsers, {userHashStudent, userHashTeacher, userHashCorporate} from "@/hooks/useUsers"; -import {CorporateUser, Group, MasterCorporateUser, Stat, User} from "@/interfaces/user"; -import UserList from "@/pages/(admin)/Lists/UserList"; -import {dateSorter} from "@/utils"; -import moment from "moment"; -import {useEffect, useMemo, useState} from "react"; +import useUsers, { + userHashStudent, + userHashTeacher, + userHashCorporate, +} from "@/hooks/useUsers"; import { - BsArrowLeft, - BsClipboard2Data, - BsClipboard2DataFill, - BsClock, - BsGlobeCentralSouthAsia, - BsPaperclip, - BsPerson, - BsPersonAdd, - BsPersonFill, - BsPersonFillGear, - BsPersonGear, - BsPencilSquare, - BsPersonBadge, - BsPersonCheck, - BsPeople, - BsArrowRepeat, - BsPlus, - BsEnvelopePaper, + CorporateUser, + Group, + MasterCorporateUser, + Stat, + User, +} from "@/interfaces/user"; +import UserList from "@/pages/(admin)/Lists/UserList"; +import { dateSorter } from "@/utils"; +import moment from "moment"; +import { useEffect, useMemo, useState } from "react"; +import { + BsArrowLeft, + BsClipboard2Data, + BsClipboard2DataFill, + BsClock, + BsGlobeCentralSouthAsia, + BsPaperclip, + BsPerson, + BsPersonAdd, + BsPersonFill, + BsPersonFillGear, + BsPersonGear, + BsPencilSquare, + BsPersonBadge, + BsPersonCheck, + BsPeople, + BsArrowRepeat, + BsPlus, + BsEnvelopePaper, + BsDatabase, } from "react-icons/bs"; import UserCard from "@/components/UserCard"; import useGroups from "@/hooks/useGroups"; -import {averageLevelCalculator, calculateAverageLevel, calculateBandScore} from "@/utils/score"; -import {MODULE_ARRAY} from "@/utils/moduleUtils"; -import {Module} from "@/interfaces"; -import {groupByExam} from "@/utils/stats"; +import { + averageLevelCalculator, + calculateAverageLevel, + calculateBandScore, +} from "@/utils/score"; +import { MODULE_ARRAY } from "@/utils/moduleUtils"; +import { Module } from "@/interfaces"; +import { groupByExam } from "@/utils/stats"; import IconCard from "../IconCard"; import GroupList from "@/pages/(admin)/Lists/GroupList"; import useFilterStore from "@/stores/listFilterStore"; -import {useRouter} from "next/router"; +import { useRouter } from "next/router"; import useCodes from "@/hooks/useCodes"; -import {getUserCorporate} from "@/utils/groups"; +import { getUserCorporate } from "@/utils/groups"; import useAssignments from "@/hooks/useAssignments"; -import {Assignment} from "@/interfaces/results"; +import { Assignment } from "@/interfaces/results"; import AssignmentView from "../AssignmentView"; import AssignmentCreator from "../AssignmentCreator"; import clsx from "clsx"; import AssignmentCard from "../AssignmentCard"; -import {createColumnHelper} from "@tanstack/react-table"; +import { createColumnHelper } from "@tanstack/react-table"; import Checkbox from "@/components/Low/Checkbox"; import List from "@/components/List"; -import {getUserCompanyName} from "@/resources/user"; -import {futureAssignmentFilter, pastAssignmentFilter, archivedAssignmentFilter, activeAssignmentFilter} from "@/utils/assignments"; +import { getUserCompanyName } from "@/resources/user"; +import { + futureAssignmentFilter, + pastAssignmentFilter, + archivedAssignmentFilter, + activeAssignmentFilter, +} from "@/utils/assignments"; import useUserBalance from "@/hooks/useUserBalance"; import AssignmentsPage from "../views/AssignmentsPage"; import StudentPerformancePage from "./StudentPerformancePage"; import MasterStatistical from "../MasterCorporate/MasterStatistical"; interface Props { - user: CorporateUser; - linkedCorporate?: CorporateUser | MasterCorporateUser; + user: CorporateUser; + linkedCorporate?: CorporateUser | MasterCorporateUser; } const studentHash = { - type: "student", - orderBy: "registrationDate", - size: 25, + type: "student", + orderBy: "registrationDate", + size: 25, }; const teacherHash = { - type: "teacher", - orderBy: "registrationDate", - size: 25, + type: "teacher", + orderBy: "registrationDate", + size: 25, }; -export default function CorporateDashboard({user, linkedCorporate}: Props) { - const [selectedUser, setSelectedUser] = useState(); - const [showModal, setShowModal] = useState(false); +export default function CorporateDashboard({ user, linkedCorporate }: Props) { + const [selectedUser, setSelectedUser] = useState(); + const [showModal, setShowModal] = useState(false); - const {data: stats} = useFilterRecordsByUser(); - const {groups} = useGroups({admin: user.id}); - const {assignments, isLoading: isAssignmentsLoading, reload: reloadAssignments} = useAssignments({corporate: user.id}); - const {balance} = useUserBalance(); + const { data: stats } = useFilterRecordsByUser(); + const { groups } = useGroups({ admin: user.id }); + const { + assignments, + isLoading: isAssignmentsLoading, + reload: reloadAssignments, + } = useAssignments({ corporate: user.id }); + const { balance } = useUserBalance(); - const {users: students, total: totalStudents, reload: reloadStudents, isLoading: isStudentsLoading} = useUsers(studentHash); - const {users: teachers, total: totalTeachers, reload: reloadTeachers, isLoading: isTeachersLoading} = useUsers(teacherHash); + const { + users: students, + total: totalStudents, + reload: reloadStudents, + isLoading: isStudentsLoading, + } = useUsers(studentHash); + const { + users: teachers, + total: totalTeachers, + reload: reloadTeachers, + isLoading: isTeachersLoading, + } = useUsers(teacherHash); - const appendUserFilters = useFilterStore((state) => state.appendUserFilter); - const router = useRouter(); + const appendUserFilters = useFilterStore((state) => state.appendUserFilter); + const router = useRouter(); - const assignmentsGroups = useMemo(() => groups.filter((x) => x.admin === user.id || x.participants.includes(user.id)), [groups, user.id]); + const assignmentsGroups = useMemo( + () => + groups.filter( + (x) => x.admin === user.id || x.participants.includes(user.id) + ), + [groups, user.id] + ); - const assignmentsUsers = useMemo( - () => - [...teachers, ...students].filter((x) => - !!selectedUser - ? groups - .filter((g) => g.admin === selectedUser.id) - .flatMap((g) => g.participants) - .includes(x.id) || false - : groups.flatMap((g) => g.participants).includes(x.id), - ), - [groups, teachers, students, selectedUser], - ); + const assignmentsUsers = useMemo( + () => + [...teachers, ...students].filter((x) => + !!selectedUser + ? groups + .filter((g) => g.admin === selectedUser.id) + .flatMap((g) => g.participants) + .includes(x.id) || false + : groups.flatMap((g) => g.participants).includes(x.id) + ), + [groups, teachers, students, selectedUser] + ); - useEffect(() => { - setShowModal(!!selectedUser && router.asPath === "/#"); - }, [selectedUser, router.asPath]); + useEffect(() => { + setShowModal(!!selectedUser && router.asPath === "/#"); + }, [selectedUser, router.asPath]); - 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 GroupsList = () => { - const filter = (x: Group) => x.admin === user.id || x.participants.includes(user.id); + // this workaround will allow us toreuse the master statistical due to master corporate restraints + // while still being able to use the corporate user + const groupedByNameCorporateIds = useMemo( + () => ({ + [user.corporateInformation?.companyInformation?.name || user.name]: [ + user.id, + ], + }), + [user] + ); + const teachersAndStudents = useMemo( + () => [...students, ...teachers], + [students, teachers] + ); + const MasterStatisticalPage = () => { + return ( + <> +
+
router.push("/")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300" + > + + Back +
+

Master Statistical

+
+ + + ); + }; - return ( - <> -
-
router.push("/")} - 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 ( + <> +
+
router.push("/")} + 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: students.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: students.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)); - if (router.asPath === "/#students") - return ( - ( -
-
router.push("/")} - className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> - - Back -
-

Students ({total})

-
- )} - /> - ); + return calculateAverageLevel(levels); + }; - if (router.asPath === "/#teachers") - return ( - ( -
-
router.push("/")} - 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})

-
- )} - /> - ); + if (router.asPath === "/#students") + return ( + ( +
+
router.push("/")} + 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})

+
+ )} + /> + ); - if (router.asPath === "/#groups") return ; - if (router.asPath === "/#studentsPerformance") return ; + if (router.asPath === "/#teachers") + return ( + ( +
+
router.push("/")} + 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})

+
+ )} + /> + ); - if (router.asPath === "/#assignments") - return ( - router.push("/")} - /> - ); + if (router.asPath === "/#groups") return ; + if (router.asPath === "/#studentsPerformance") + return ; - return ( - <> - setSelectedUser(undefined)}> - <> - {selectedUser && ( -
- { - setSelectedUser(undefined); - if (shouldReload && selectedUser!.type === "student") reloadStudents(); - if (shouldReload && selectedUser!.type === "teacher") reloadTeachers(); - }} - 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), - }); + if (router.asPath === "/#assignments") + return ( + router.push("/")} + /> + ); - 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), - }); + if (router.asPath === "/#statistical") return ; - router.push("/list/users"); - } - : undefined - } - user={selectedUser} - /> -
- )} - -
+ return ( + <> + setSelectedUser(undefined)}> + <> + {selectedUser && ( +
+ { + setSelectedUser(undefined); + if (shouldReload && selectedUser!.type === "student") + reloadStudents(); + if (shouldReload && selectedUser!.type === "teacher") + reloadTeachers(); + }} + 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), + }); - <> - {!!linkedCorporate && ( -
- Linked to: {linkedCorporate?.corporateInformation?.companyInformation.name || linkedCorporate.name} -
- )} -
- router.push("/#students")} - isLoading={isStudentsLoading} - Icon={BsPersonFill} - label="Students" - value={totalStudents} - color="purple" - /> - router.push("/#teachers")} - isLoading={isTeachersLoading} - Icon={BsPencilSquare} - label="Teachers" - value={totalTeachers} - 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" - /> - router.push("/#groups")} Icon={BsPeople} label="Groups" value={groups.length} color="purple" /> - - - router.push("/#studentsPerformance")} - /> - -
+ router.push("/list/users"); + } + : undefined + } + onViewTeachers={ + selectedUser.type === "corporate" || + selectedUser.type === "student" + ? () => { + appendUserFilters({ + id: "view-teachers", + filter: (x: User) => x.type === "teacher", + }); + appendUserFilters({ + id: "belongs-to-admin", + filter: (x: User) => + groups + .filter( + (g) => + g.admin === selectedUser.id || + g.participants.includes(selectedUser.id) + ) + .flatMap((g) => g.participants) + .includes(x.id), + }); -
-
- Latest students -
- {students - .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) - .map((x) => ( - - ))} -
-
-
- Latest teachers -
- {teachers - .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) - .map((x) => ( - - ))} -
-
-
- Highest level students -
- {students - .sort((a, b) => calculateAverageLevel(b.levels) - calculateAverageLevel(a.levels)) - .map((x) => ( - - ))} -
-
-
- Highest exam count students -
- {students - .sort( - (a, b) => - Object.keys(groupByExam(getStatsByStudent(b))).length - Object.keys(groupByExam(getStatsByStudent(a))).length, - ) - .map((x) => ( - - ))} -
-
-
- - - ); + router.push("/list/users"); + } + : undefined + } + user={selectedUser} + /> +
+ )} + +
+ + <> + {!!linkedCorporate && ( +
+ Linked to:{" "} + + {linkedCorporate?.corporateInformation?.companyInformation.name || + linkedCorporate.name} + +
+ )} +
+ router.push("/#students")} + isLoading={isStudentsLoading} + Icon={BsPersonFill} + label="Students" + value={totalStudents} + color="purple" + /> + router.push("/#teachers")} + isLoading={isTeachersLoading} + Icon={BsPencilSquare} + label="Teachers" + value={totalTeachers} + 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" + /> + router.push("/#groups")} + Icon={BsPeople} + label="Groups" + value={groups.length} + color="purple" + /> + + + router.push("/#studentsPerformance")} + /> + router.push("/#statistical")} + /> + +
+ +
+
+ Latest students +
+ {students + .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) + .map((x) => ( + + ))} +
+
+
+ Latest teachers +
+ {teachers + .sort((a, b) => dateSorter(a, b, "desc", "registrationDate")) + .map((x) => ( + + ))} +
+
+
+ Highest level students +
+ {students + .sort( + (a, b) => + calculateAverageLevel(b.levels) - + calculateAverageLevel(a.levels) + ) + .map((x) => ( + + ))} +
+
+
+ Highest exam count students +
+ {students + .sort( + (a, b) => + Object.keys(groupByExam(getStatsByStudent(b))).length - + Object.keys(groupByExam(getStatsByStudent(a))).length + ) + .map((x) => ( + + ))} +
+
+
+ + + ); } diff --git a/src/dashboards/MasterCorporate/MasterStatisticalPage.tsx b/src/dashboards/MasterCorporate/MasterStatisticalPage.tsx index 4dcb173b..cded8415 100644 --- a/src/dashboards/MasterCorporate/MasterStatisticalPage.tsx +++ b/src/dashboards/MasterCorporate/MasterStatisticalPage.tsx @@ -7,23 +7,14 @@ import {BsArrowLeft} from "react-icons/bs"; import MasterStatistical from "./MasterStatistical"; interface Props { - user: User; + groupedByNameCorporates: Record; } -const MasterStatisticalPage = () => { +const MasterStatisticalPage = ({ groupedByNameCorporates }: Props) => { const {users} = useUsers(); const router = useRouter(); - const groupedByNameCorporates = useMemo( - () => - groupBy( - users.filter((x) => x.type === "corporate"), - (x: CorporateUser) => x.corporateInformation?.companyInformation?.name || "N/A", - ), - [users], - ); - const groupedByNameCorporateIds = useMemo( () => Object.keys(groupedByNameCorporates).reduce((accm, x) => { diff --git a/src/dashboards/MasterCorporate/index.tsx b/src/dashboards/MasterCorporate/index.tsx index 41951c21..584eaf28 100644 --- a/src/dashboards/MasterCorporate/index.tsx +++ b/src/dashboards/MasterCorporate/index.tsx @@ -129,6 +129,20 @@ export default function MasterCorporateDashboard({user}: Props) {
); + const {users} = useUsers(); + + + const groupedByNameCorporates = useMemo( + () => + groupBy( + users.filter((x) => x.type === "corporate"), + (x: CorporateUser) => x.corporateInformation?.companyInformation?.name || "N/A", + ) as Record, + [users], + ); + + const groupedByNameCorporatesKeys = Object.keys(groupedByNameCorporates); + const GroupsList = () => { return ( <> @@ -148,7 +162,7 @@ export default function MasterCorporateDashboard({user}: Props) { }; if (router.asPath === "/#studentsPerformance") return ; - if (router.asPath === "/#statistical") return ; + if (router.asPath === "/#statistical") return ; if (router.asPath === "/#groups") return ; if (router.asPath === "/#students") @@ -360,7 +374,7 @@ export default function MasterCorporateDashboard({user}: Props) { color="purple" onClick={() => router.push("/#corporate")} /> - + ({...user, type, expiryDate})) }); + await axios.post("/api/batch_users", {users: newUsers.map((user) => ({...user, type, expiryDate}))}); toast.success(`Successfully added ${newUsers.length} user(s)!`); onFinish(); } catch { diff --git a/src/pages/(admin)/Lists/UserList.tsx b/src/pages/(admin)/Lists/UserList.tsx index 38f48b47..336a08cb 100644 --- a/src/pages/(admin)/Lists/UserList.tsx +++ b/src/pages/(admin)/Lists/UserList.tsx @@ -31,6 +31,10 @@ import useUserBalance from "@/hooks/useUserBalance"; const columnHelper = createColumnHelper(); const searchFields = [["name"], ["email"], ["corporateInformation", "companyInformation", "name"]]; +const corporatesHash = { + type: "corporate", +}; + const CompanyNameCell = ({users, user, groups}: {user: User; users: User[]; groups: Group[]}) => { const [companyName, setCompanyName] = useState(""); const [isLoading, setIsLoading] = useState(false); @@ -70,6 +74,10 @@ export default function UserList({ ); const {users, total, isLoading, reload} = useUsers(userHash); + const {users: corporates} = useUsers(corporatesHash); + + const totalUsers = useMemo(() => [...users, ...corporates], [users, corporates]); + const {permissions} = usePermissions(user?.id || ""); const {balance} = useUserBalance(); const {groups} = useGroups({ @@ -354,7 +362,7 @@ export default function UserList({ ) as any, - cell: (info) => , + cell: (info) => , }), columnHelper.accessor("subscriptionExpirationDate", { header: ( diff --git a/src/pages/(admin)/UserCreator.tsx b/src/pages/(admin)/UserCreator.tsx index 12415726..03fc35e6 100644 --- a/src/pages/(admin)/UserCreator.tsx +++ b/src/pages/(admin)/UserCreator.tsx @@ -141,7 +141,11 @@ export default function UserCreator({user, users, permissions, onFinish}: Props) setType("student"); setPosition(undefined); }) - .catch(() => toast.error("Something went wrong! Please try again later!")) + .catch((error) => { + const data = error?.response?.data; + if (!!data?.message) return toast.error(data.message); + toast.error("Something went wrong! Please try again later!"); + }) .finally(() => setIsLoading(false)); }; diff --git a/src/pages/api/make_user.ts b/src/pages/api/make_user.ts index 31b0e69d..b8128015 100644 --- a/src/pages/api/make_user.ts +++ b/src/pages/api/make_user.ts @@ -218,6 +218,8 @@ async function post(req: NextApiRequest, res: NextApiResponse) { return res.status(200).json({ok: true}); }) .catch((error) => { + if (error.code.includes("email-already-in-use")) return res.status(403).json({error, message: "E-mail is already in the platform."}); + console.log(`Failing - ${email}`); console.log(error); return res.status(401).json({error}); diff --git a/src/pages/api/sessions/index.ts b/src/pages/api/sessions/index.ts index 1e7c83f1..267ae57b 100644 --- a/src/pages/api/sessions/index.ts +++ b/src/pages/api/sessions/index.ts @@ -24,7 +24,7 @@ async function get(req: NextApiRequest, res: NextApiResponse) { const {user} = req.query as {user?: string}; const q = user ? {user: user} : {}; - const sessions = await db.collection("sessions").find(q).toArray(); + const sessions = await db.collection("sessions").find(q).limit(10).toArray(); res.status(200).json( sessions.filter((x) => { @@ -41,12 +41,8 @@ async function post(req: NextApiRequest, res: NextApiResponse) { return; } const session = req.body; - - await db.collection("sessions").updateOne( - { id: session.id}, - { $set: session }, - { upsert: true } - ); + + await db.collection("sessions").updateOne({id: session.id}, {$set: session}, {upsert: true}); res.status(200).json({ok: true}); } diff --git a/src/pages/api/users/update.ts b/src/pages/api/users/update.ts index 121a01b3..aab28fa9 100644 --- a/src/pages/api/users/update.ts +++ b/src/pages/api/users/update.ts @@ -1,17 +1,17 @@ // Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from "next"; -import { app, storage } from "@/firebase"; -import { withIronSessionApiRoute } from "iron-session/next"; -import { sessionOptions } from "@/lib/session"; -import { Group, User } from "@/interfaces/user"; -import { getDownloadURL, getStorage, ref, uploadBytes } from "firebase/storage"; -import { getAuth, signInWithEmailAndPassword, updateEmail, updatePassword } from "firebase/auth"; -import { errorMessages } from "@/constants/errors"; +import type {NextApiRequest, NextApiResponse} from "next"; +import {app, storage} from "@/firebase"; +import {withIronSessionApiRoute} from "iron-session/next"; +import {sessionOptions} from "@/lib/session"; +import {Group, User} from "@/interfaces/user"; +import {getDownloadURL, getStorage, ref, uploadBytes} from "firebase/storage"; +import {getAuth, signInWithEmailAndPassword, updateEmail, updatePassword} from "firebase/auth"; +import {errorMessages} from "@/constants/errors"; import moment from "moment"; import ShortUniqueId from "short-unique-id"; -import { Payment } from "@/interfaces/paypal"; -import { toFixedNumber } from "@/utils/number"; -import { propagateExpiryDateChanges, propagateStatusChange } from "@/utils/propagate.user.changes"; +import {Payment} from "@/interfaces/paypal"; +import {toFixedNumber} from "@/utils/number"; +import {propagateExpiryDateChanges, propagateStatusChange} from "@/utils/propagate.user.changes"; import client from "@/lib/mongodb"; const db = client.db(process.env.MONGODB_DB); @@ -41,7 +41,7 @@ const managePaymentRecords = async (user: User, userId: string | undefined): Pro date: new Date().toISOString(), }; - const corporatePayments = await db.collection("payments").find({ corporate: userId }).toArray(); + const corporatePayments = await db.collection("payments").find({corporate: userId}).toArray(); if (corporatePayments.length === 0) { await addPaymentRecord(data); return true; @@ -71,21 +71,17 @@ const managePaymentRecords = async (user: User, userId: string | undefined): Pro async function handler(req: NextApiRequest, res: NextApiResponse) { if (!req.session.user) { - res.status(401).json({ ok: false }); + res.status(401).json({ok: false}); return; } const queryId = req.query.id as string; - const userId = queryId ? (queryId as string) : req.session.user.id - let user = await db.collection("users").findOne({ id: userId }); - const updatedUser = req.body as User & { password?: string; newPassword?: string }; + let user = await db.collection("users").findOne({id: queryId ? (queryId as string) : req.session.user.id}); + const updatedUser = req.body as User & {password?: string; newPassword?: string}; if (!!queryId) { - await db.collection("users").updateOne( - { id: queryId }, - { $set: updatedUser } - ); + await db.collection("users").updateOne({id: queryId}, {$set: updatedUser}); await managePaymentRecords(updatedUser, updatedUser.id); if (updatedUser.status || updatedUser.type === "corporate") { @@ -94,7 +90,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { propagateExpiryDateChanges(queryId, user?.subscriptionExpirationDate, updatedUser.subscriptionExpirationDate || null); } - res.status(200).json({ ok: true }); + res.status(200).json({ok: true}); return; } @@ -114,17 +110,17 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { const credential = await signInWithEmailAndPassword(auth, req.session.user.email, updatedUser.password); await updatePassword(credential.user, updatedUser.newPassword); } catch { - res.status(400).json({ error: "E001", message: errorMessages.E001 }); + res.status(400).json({error: "E001", message: errorMessages.E001}); return; } } if (updatedUser.email !== req.session.user.email && updatedUser.password) { try { - const usersWithSameEmail = await db.collection("users").find({ email: updatedUser.email.toLowerCase() }).toArray(); + const usersWithSameEmail = await db.collection("users").find({email: updatedUser.email.toLowerCase()}).toArray(); if (usersWithSameEmail.length > 0) { - res.status(400).json({ error: "E003", message: errorMessages.E003 }); + res.status(400).json({error: "E003", message: errorMessages.E003}); return; } @@ -132,22 +128,24 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { await updateEmail(credential.user, updatedUser.email); if (req.session.user.type === "student") { - const corporateAdmins = (await db.collection("users").find({ type: "corporate" }).toArray()).map((x) => x.id); + const corporateAdmins = (await db.collection("users").find({type: "corporate"}).toArray()).map((x) => x.id); - const groups = await db.collection("groups").find({ - participants: req.session.user!.id, - admin: { $in: corporateAdmins } - }).toArray(); + const groups = await db + .collection("groups") + .find({ + participants: req.session.user!.id, + admin: {$in: corporateAdmins}, + }) + .toArray(); groups.forEach(async (group) => { - await db.collection("groups").updateOne( - { id: group.id }, - { $set: { participants: group.participants.filter((x) => x !== req.session.user!.id) } } - ); + await db + .collection("groups") + .updateOne({id: group.id}, {$set: {participants: group.participants.filter((x) => x !== req.session.user!.id)}}); }); } } catch { - res.status(400).json({ error: "E002", message: errorMessages.E002 }); + res.status(400).json({error: "E002", message: errorMessages.E002}); return; } } @@ -160,22 +158,18 @@ async function handler(req: NextApiRequest, res: NextApiResponse) { delete updatedUser.password; delete updatedUser.newPassword; - await db.collection("users").updateOne( - { id: userId }, - { $set: updatedUser } - ); - - user = await db.collection("users").findOne({ id: req.session.user.id }); + await db.collection("users").updateOne({id: queryId}, {$set: updatedUser}); if (!queryId) { - req.session.user = user ? user : null; + req.session.user = updatedUser ? {...updatedUser, id: req.session.user.id} : null; await req.session.save(); } - if (user) { - await managePaymentRecords(user, queryId); + if ({...updatedUser, id: req.session.user!.id}) { + await managePaymentRecords({...updatedUser, id: req.session.user!.id}, queryId); } - res.status(200).json({ user }); + + res.status(200).json({user: {...updatedUser, id: req.session.user!.id}}); } export const config = { diff --git a/src/pages/exam.tsx b/src/pages/exam.tsx index 779ababd..84cc0317 100644 --- a/src/pages/exam.tsx +++ b/src/pages/exam.tsx @@ -10,7 +10,7 @@ import {User} from "@/interfaces/user"; export const getServerSideProps = withIronSessionSsr(({req, res}) => { const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/exercises.tsx b/src/pages/exercises.tsx index 9a24775c..983fdfeb 100644 --- a/src/pages/exercises.tsx +++ b/src/pages/exercises.tsx @@ -10,7 +10,7 @@ import {User} from "@/interfaces/user"; export const getServerSideProps = withIronSessionSsr(({req, res}) => { const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/generation.tsx b/src/pages/generation.tsx index 8505434d..4d23a995 100644 --- a/src/pages/generation.tsx +++ b/src/pages/generation.tsx @@ -27,7 +27,7 @@ import {User} from "@/interfaces/user"; export const getServerSideProps = withIronSessionSsr(({req, res}) => { const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/groups.tsx b/src/pages/groups.tsx index 70b38f4b..12886c91 100644 --- a/src/pages/groups.tsx +++ b/src/pages/groups.tsx @@ -43,7 +43,7 @@ import {getUsers} from "@/utils/users.be"; export const getServerSideProps = withIronSessionSsr(async ({req, res}) => { const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 773e829f..6a4f9ca4 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -46,7 +46,7 @@ export const getServerSideProps = withIronSessionSsr(async ({req, res}) => { envVariables[x] = process.env[x]!; }); - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", @@ -68,22 +68,18 @@ interface Props { linkedCorporate?: CorporateUser | MasterCorporateUser; } -export default function Home({linkedCorporate}: Props) { +export default function Home({user: propsUser, linkedCorporate}: Props) { + const [user, setUser] = useState(propsUser); const [showDiagnostics, setShowDiagnostics] = useState(false); const [showDemographicInput, setShowDemographicInput] = useState(false); const [selectedScreen, setSelectedScreen] = useState("admin"); - const {user, mutateUser} = useUser({redirectTo: "/login"}); + const {mutateUser} = useUser({redirectTo: "/login"}); const router = useRouter(); useEffect(() => { if (user) { - setShowDemographicInput( - !user.demographicInformation || - !user.demographicInformation.country || - !user.demographicInformation.gender || - !user.demographicInformation.phone, - ); + // setShowDemographicInput(!user.demographicInformation || !user.demographicInformation.country || !user.demographicInformation.phone); setShowDiagnostics(user.isFirstLogin && user.type === "student"); } }, [user]); @@ -135,7 +131,13 @@ export default function Home({linkedCorporate}: Props) { - + { + setUser(user); + mutateUser(user); + }} + user={user} + /> ); diff --git a/src/pages/list/users.tsx b/src/pages/list/users.tsx index 3a07e363..26069756 100644 --- a/src/pages/list/users.tsx +++ b/src/pages/list/users.tsx @@ -21,7 +21,7 @@ export const getServerSideProps = withIronSessionSsr(({req, res}) => { envVariables[x] = process.env[x]!; }); - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 4d4b6292..fe7d37ad 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -28,7 +28,7 @@ export const getServerSideProps = withIronSessionSsr(({req, res}) => { envVariables[x] = process.env[x]!; }); - if (user && user.isVerified) { + if (user) { return { redirect: { destination: "/", @@ -56,7 +56,7 @@ export default function Login() { }); useEffect(() => { - if (user && user.isVerified) router.push("/"); + if (user) router.push("/"); }, [router, user]); const forgotPassword = () => { @@ -173,7 +173,7 @@ export default function Login() { )} - {user && !user.isVerified && } + {/* {user && !user.isVerified && } */}
diff --git a/src/pages/payment-record.tsx b/src/pages/payment-record.tsx index 3eae246a..8d99512c 100644 --- a/src/pages/payment-record.tsx +++ b/src/pages/payment-record.tsx @@ -1,28 +1,20 @@ /* eslint-disable @next/next/no-img-element */ import Head from "next/head"; -import { withIronSessionSsr } from "iron-session/next"; -import { sessionOptions } from "@/lib/session"; +import {withIronSessionSsr} from "iron-session/next"; +import {sessionOptions} from "@/lib/session"; import useUser from "@/hooks/useUser"; -import { toast, ToastContainer } from "react-toastify"; +import {toast, ToastContainer} from "react-toastify"; import Layout from "@/components/High/Layout"; -import { shouldRedirectHome } from "@/utils/navigation.disabled"; +import {shouldRedirectHome} from "@/utils/navigation.disabled"; import usePayments from "@/hooks/usePayments"; import usePaypalPayments from "@/hooks/usePaypalPayments"; -import { Payment, PaypalPayment } from "@/interfaces/paypal"; -import { - CellContext, - createColumnHelper, - flexRender, - getCoreRowModel, - HeaderGroup, - Table, - useReactTable, -} from "@tanstack/react-table"; -import { CURRENCIES } from "@/resources/paypal"; -import { BsTrash } from "react-icons/bs"; +import {Payment, PaypalPayment} from "@/interfaces/paypal"; +import {CellContext, createColumnHelper, flexRender, getCoreRowModel, HeaderGroup, Table, useReactTable} from "@tanstack/react-table"; +import {CURRENCIES} from "@/resources/paypal"; +import {BsTrash} from "react-icons/bs"; import axios from "axios"; -import { useEffect, useState, useMemo } from "react"; -import { AgentUser, CorporateUser, User } from "@/interfaces/user"; +import {useEffect, useState, useMemo} from "react"; +import {AgentUser, CorporateUser, User} from "@/interfaces/user"; import UserCard from "@/components/UserCard"; import Modal from "@/components/Modal"; import clsx from "clsx"; @@ -34,1499 +26,1228 @@ import Input from "@/components/Low/Input"; import ReactDatePicker from "react-datepicker"; import moment from "moment"; import PaymentAssetManager from "@/components/PaymentAssetManager"; -import { toFixedNumber } from "@/utils/number"; -import { CSVLink } from "react-csv"; -import { Tab } from "@headlessui/react"; -import { useListSearch } from "@/hooks/useListSearch"; -import { checkAccess, getTypesOfUser } from "@/utils/permissions"; +import {toFixedNumber} from "@/utils/number"; +import {CSVLink} from "react-csv"; +import {Tab} from "@headlessui/react"; +import {useListSearch} from "@/hooks/useListSearch"; +import {checkAccess, getTypesOfUser} from "@/utils/permissions"; -export const getServerSideProps = withIronSessionSsr(({ req, res }) => { - const user = req.session.user; +export const getServerSideProps = withIronSessionSsr(({req, res}) => { + const user = req.session.user; - if (!user || !user.isVerified) { - return { - redirect: { - destination: "/login", - permanent: false, - }, - }; - } + if (!user) { + return { + redirect: { + destination: "/login", + permanent: false, + }, + }; + } - if ( - shouldRedirectHome(user) || - checkAccess( - user, - getTypesOfUser([ - "admin", - "developer", - "agent", - "corporate", - "mastercorporate", - ]) - ) - ) { - return { - redirect: { - destination: "/", - permanent: false, - }, - }; - } + if (shouldRedirectHome(user) || checkAccess(user, getTypesOfUser(["admin", "developer", "agent", "corporate", "mastercorporate"]))) { + return { + redirect: { + destination: "/", + permanent: false, + }, + }; + } - return { - props: { user: req.session.user }, - }; + return { + props: {user: req.session.user}, + }; }, sessionOptions); const columnHelper = createColumnHelper(); const paypalColumnHelper = createColumnHelper(); -const PaymentCreator = ({ - onClose, - reload, - showComission = false, -}: { - onClose: () => void; - reload: () => void; - showComission: boolean; -}) => { - const [corporate, setCorporate] = useState(); - const [date, setDate] = useState(new Date()); +const PaymentCreator = ({onClose, reload, showComission = false}: {onClose: () => void; reload: () => void; showComission: boolean}) => { + const [corporate, setCorporate] = useState(); + const [date, setDate] = useState(new Date()); - const { users } = useUsers(); + const {users} = useUsers(); - const price = corporate?.corporateInformation?.payment?.value || 0; - const commission = corporate?.corporateInformation?.payment?.commission || 0; - const currency = corporate?.corporateInformation?.payment?.currency || "EUR"; + const price = corporate?.corporateInformation?.payment?.value || 0; + const commission = corporate?.corporateInformation?.payment?.commission || 0; + const currency = corporate?.corporateInformation?.payment?.currency || "EUR"; - const referralAgent = useMemo(() => { - if (corporate?.corporateInformation?.referralAgent) { - return users.find( - (u) => u.id === corporate.corporateInformation.referralAgent - ); - } + const referralAgent = useMemo(() => { + if (corporate?.corporateInformation?.referralAgent) { + return users.find((u) => u.id === corporate.corporateInformation.referralAgent); + } - return undefined; - }, [corporate?.corporateInformation?.referralAgent, users]); + return undefined; + }, [corporate?.corporateInformation?.referralAgent, users]); - const submit = () => { - axios - .post(`/api/payments`, { - corporate: corporate?.id, - agent: referralAgent?.id, - agentCommission: commission, - agentValue: toFixedNumber((commission! / 100) * price!, 2), - currency, - value: price, - isPaid: false, - date: date.toISOString(), - }) - .then(() => { - toast.success("New payment has been created successfully!"); - reload(); - onClose(); - }) - .catch(() => { - toast.error("Something went wrong, please try again later!"); - }); - }; + const submit = () => { + axios + .post(`/api/payments`, { + corporate: corporate?.id, + agent: referralAgent?.id, + agentCommission: commission, + agentValue: toFixedNumber((commission! / 100) * price!, 2), + currency, + value: price, + isPaid: false, + date: date.toISOString(), + }) + .then(() => { + toast.success("New payment has been created successfully!"); + reload(); + onClose(); + }) + .catch(() => { + toast.error("Something went wrong, please try again later!"); + }); + }; - return ( -
-

New Payment

-
-
- - u.type === "corporate") as CorporateUser[]).map((user) => ({ + value: user.id, + meta: user, + label: `${user.corporateInformation?.companyInformation?.name || user.name} - ${user.email}`, + }))} + defaultValue={{value: "undefined", label: "Select an account"}} + onChange={(value) => setCorporate((value as any)?.meta ?? undefined)} + menuPortalTarget={document?.body} + styles={{ + menuPortal: (base) => ({...base, zIndex: 9999}), + control: (styles) => ({ + ...styles, + paddingLeft: "4px", + border: "none", + outline: "none", + ":focus": { + outline: "none", + }, + }), + option: (styles, state) => ({ + ...styles, + backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white", + color: state.isFocused ? "black" : styles.color, + }), + }} + /> +
-
- -
- {}} - type="number" - value={price} - defaultValue={0} - className="col-span-3" - disabled - /> - {}} - type="number" - defaultValue={0} - value={commission} - disabled - /> -
-
- - c.currency === currency)?.label - }`} - onChange={() => null} - type="text" - defaultValue={0} - disabled - /> -
-
- )} +
+ +
+ {}} type="number" value={price} defaultValue={0} className="col-span-3" disabled /> + {}} type="number" defaultValue={0} value={commission} disabled /> +
+
+ + c.currency === currency)?.label}`} + onChange={() => null} + type="text" + defaultValue={0} + disabled + /> +
+
+ )} -
-
- - setDate(date ?? new Date())} - /> -
+
+
+ + setDate(date ?? new Date())} + /> +
-
- - null} - type="text" - defaultValue={"No country manager"} - disabled - /> -
-
-
- - -
-
-
- ); +
+ + null} + type="text" + defaultValue={"No country manager"} + disabled + /> +
+
+
+ + +
+ + + ); }; const IS_PAID_OPTIONS = [ - { - value: null, - label: "All", - }, - { - value: false, - label: "Unpaid", - }, - { - value: true, - label: "Paid", - }, + { + value: null, + label: "All", + }, + { + value: false, + label: "Unpaid", + }, + { + value: true, + label: "Paid", + }, ]; const IS_FILE_SUBMITTED_OPTIONS = [ - { - value: null, - label: "All", - }, - { - value: false, - label: "Submitted", - }, - { - value: true, - label: "Not Submitted", - }, + { + value: null, + label: "All", + }, + { + value: false, + label: "Submitted", + }, + { + value: true, + label: "Not Submitted", + }, ]; -const CSV_PAYMENTS_WHITELISTED_KEYS = [ - "corporateId", - "corporate", - "date", - "amount", - "agent", - "agentCommission", - "agentValue", - "isPaid", -]; +const CSV_PAYMENTS_WHITELISTED_KEYS = ["corporateId", "corporate", "date", "amount", "agent", "agentCommission", "agentValue", "isPaid"]; -const CSV_PAYPAL_WHITELISTED_KEYS = [ - "orderId", - "status", - "name", - "email", - "value", - "createdAt", - "subscriptionExpirationDate", -]; +const CSV_PAYPAL_WHITELISTED_KEYS = ["orderId", "status", "name", "email", "value", "createdAt", "subscriptionExpirationDate"]; interface SimpleCSVColumn { - key: string; - label: string; - index: number; + key: string; + label: string; + index: number; } interface PaypalPaymentWithUserData extends PaypalPayment { - name: string; - email: string; + name: string; + email: string; } const paypalFilterRows = [["email"], ["name"], ["orderId"], ["value"]]; export default function PaymentRecord() { - const [selectedCorporateUser, setSelectedCorporateUser] = useState(); - const [selectedAgentUser, setSelectedAgentUser] = useState(); - const [isCreatingPayment, setIsCreatingPayment] = useState(false); - const [filters, setFilters] = useState< - { filter: (p: Payment) => boolean; id: string }[] - >([]); - const [displayPayments, setDisplayPayments] = useState([]); + const [selectedCorporateUser, setSelectedCorporateUser] = useState(); + const [selectedAgentUser, setSelectedAgentUser] = useState(); + const [isCreatingPayment, setIsCreatingPayment] = useState(false); + const [filters, setFilters] = useState<{filter: (p: Payment) => boolean; id: string}[]>([]); + const [displayPayments, setDisplayPayments] = useState([]); - const [corporate, setCorporate] = useState(); - const [agent, setAgent] = useState(); + const [corporate, setCorporate] = useState(); + const [agent, setAgent] = useState(); - const { user } = useUser({ redirectTo: "/login" }); - const { users, reload: reloadUsers } = useUsers(); - const { payments: originalPayments, reload: reloadPayment } = usePayments(); - const { payments: paypalPayments, reload: reloadPaypalPayment } = - usePaypalPayments(); - const [startDate, setStartDate] = useState( - moment("01/01/2023").toDate() - ); - const [endDate, setEndDate] = useState( - moment().endOf("day").toDate() - ); + const {user} = useUser({redirectTo: "/login"}); + const {users, reload: reloadUsers} = useUsers(); + const {payments: originalPayments, reload: reloadPayment} = usePayments(); + const {payments: paypalPayments, reload: reloadPaypalPayment} = usePaypalPayments(); + const [startDate, setStartDate] = useState(moment("01/01/2023").toDate()); + const [endDate, setEndDate] = useState(moment().endOf("day").toDate()); - const [startDatePaymob, setStartDatePaymob] = useState( - moment("01/01/2023").toDate() - ); - const [endDatePaymob, setEndDatePaymob] = useState( - moment().endOf("day").toDate() - ); + const [startDatePaymob, setStartDatePaymob] = useState(moment("01/01/2023").toDate()); + const [endDatePaymob, setEndDatePaymob] = useState(moment().endOf("day").toDate()); - const [paid, setPaid] = useState(IS_PAID_OPTIONS[0].value); - const [commissionTransfer, setCommissionTransfer] = useState( - IS_FILE_SUBMITTED_OPTIONS[0].value - ); - const [corporateTransfer, setCorporateTransfer] = useState( - IS_FILE_SUBMITTED_OPTIONS[0].value - ); - const reload = () => { - reloadUsers(); - reloadPayment(); - }; + const [paid, setPaid] = useState(IS_PAID_OPTIONS[0].value); + const [commissionTransfer, setCommissionTransfer] = useState(IS_FILE_SUBMITTED_OPTIONS[0].value); + const [corporateTransfer, setCorporateTransfer] = useState(IS_FILE_SUBMITTED_OPTIONS[0].value); + const reload = () => { + reloadUsers(); + reloadPayment(); + }; - const payments = useMemo(() => { - return originalPayments.filter((p: Payment) => { - const date = moment(p.date); - return date.isAfter(startDate) && date.isBefore(endDate); - }); - }, [originalPayments, startDate, endDate]); + const payments = useMemo(() => { + return originalPayments.filter((p: Payment) => { + const date = moment(p.date); + return date.isAfter(startDate) && date.isBefore(endDate); + }); + }, [originalPayments, startDate, endDate]); - const [selectedIndex, setSelectedIndex] = useState(0); + const [selectedIndex, setSelectedIndex] = useState(0); - useEffect(() => { - setDisplayPayments( - filters - .map((f) => f.filter) - .reduce((d, f) => d.filter(f), payments) - .sort((a, b) => moment(b.date).diff(moment(a.date))) - ); - }, [payments, filters]); + useEffect(() => { + setDisplayPayments( + filters + .map((f) => f.filter) + .reduce((d, f) => d.filter(f), payments) + .sort((a, b) => moment(b.date).diff(moment(a.date))), + ); + }, [payments, filters]); - useEffect(() => { - if (user && user.type === "agent") { - setAgent(user); - } - }, [user]); + useEffect(() => { + if (user && user.type === "agent") { + setAgent(user); + } + }, [user]); - useEffect(() => { - setFilters((prev) => [ - ...prev.filter((x) => x.id !== "agent-filter"), - ...(!agent - ? [] - : [ - { - id: "agent-filter", - filter: (p: Payment) => p.agent === agent.id, - }, - ]), - ]); - }, [agent]); + useEffect(() => { + setFilters((prev) => [ + ...prev.filter((x) => x.id !== "agent-filter"), + ...(!agent + ? [] + : [ + { + id: "agent-filter", + filter: (p: Payment) => p.agent === agent.id, + }, + ]), + ]); + }, [agent]); - useEffect(() => { - setFilters((prev) => [ - ...prev.filter((x) => x.id !== "corporate-filter"), - ...(!corporate - ? [] - : [ - { - id: "corporate-filter", - filter: (p: Payment) => p.corporate === corporate.id, - }, - ]), - ]); - }, [corporate]); + useEffect(() => { + setFilters((prev) => [ + ...prev.filter((x) => x.id !== "corporate-filter"), + ...(!corporate + ? [] + : [ + { + id: "corporate-filter", + filter: (p: Payment) => p.corporate === corporate.id, + }, + ]), + ]); + }, [corporate]); - useEffect(() => { - setFilters((prev) => [ - ...prev.filter((x) => x.id !== "paid"), - ...(typeof paid !== "boolean" - ? [] - : [{ id: "paid", filter: (p: Payment) => p.isPaid === paid }]), - ]); - }, [paid]); + useEffect(() => { + setFilters((prev) => [ + ...prev.filter((x) => x.id !== "paid"), + ...(typeof paid !== "boolean" ? [] : [{id: "paid", filter: (p: Payment) => p.isPaid === paid}]), + ]); + }, [paid]); - useEffect(() => { - setFilters((prev) => [ - ...prev.filter((x) => x.id !== "commissionTransfer"), - ...(typeof commissionTransfer !== "boolean" - ? [] - : [ - { - id: "commissionTransfer", - filter: (p: Payment) => - !p.commissionTransfer === commissionTransfer, - }, - ]), - ]); - }, [commissionTransfer]); + useEffect(() => { + setFilters((prev) => [ + ...prev.filter((x) => x.id !== "commissionTransfer"), + ...(typeof commissionTransfer !== "boolean" + ? [] + : [ + { + id: "commissionTransfer", + filter: (p: Payment) => !p.commissionTransfer === commissionTransfer, + }, + ]), + ]); + }, [commissionTransfer]); - useEffect(() => { - setFilters((prev) => [ - ...prev.filter((x) => x.id !== "corporateTransfer"), - ...(typeof corporateTransfer !== "boolean" - ? [] - : [ - { - id: "corporateTransfer", - filter: (p: Payment) => - !p.corporateTransfer === corporateTransfer, - }, - ]), - ]); - }, [corporateTransfer]); + useEffect(() => { + setFilters((prev) => [ + ...prev.filter((x) => x.id !== "corporateTransfer"), + ...(typeof corporateTransfer !== "boolean" + ? [] + : [ + { + id: "corporateTransfer", + filter: (p: Payment) => !p.corporateTransfer === corporateTransfer, + }, + ]), + ]); + }, [corporateTransfer]); - useEffect(() => { - if (user && user.type === "corporate") return setCorporate(user); - if (user && user.type === "agent") return setAgent(user); - }, [user]); + useEffect(() => { + if (user && user.type === "corporate") return setCorporate(user); + if (user && user.type === "agent") return setAgent(user); + }, [user]); - const updatePayment = (payment: Payment, key: string, value: any) => { - axios - .patch(`api/payments/${payment.id}`, { ...payment, [key]: value }) - .then(() => toast.success("Updated the payment")) - .finally(reload); - }; + const updatePayment = (payment: Payment, key: string, value: any) => { + axios + .patch(`api/payments/${payment.id}`, {...payment, [key]: value}) + .then(() => toast.success("Updated the payment")) + .finally(reload); + }; - const deletePayment = (id: string) => { - if (!confirm(`Are you sure you want to delete this payment?`)) return; + const deletePayment = (id: string) => { + if (!confirm(`Are you sure you want to delete this payment?`)) return; - axios - .delete(`/api/payments/${id}`) - .then(() => toast.success(`Deleted the "${id}" payment`)) - .catch((reason) => { - if (reason.response.status === 404) { - toast.error("Exam not found!"); - return; - } + axios + .delete(`/api/payments/${id}`) + .then(() => toast.success(`Deleted the "${id}" payment`)) + .catch((reason) => { + if (reason.response.status === 404) { + toast.error("Exam not found!"); + return; + } - if (reason.response.status === 403) { - toast.error( - "You do not have permission to delete an approved payment record!" - ); - return; - } + if (reason.response.status === 403) { + toast.error("You do not have permission to delete an approved payment record!"); + return; + } - toast.error("Something went wrong, please try again later."); - }) - .finally(reload); - }; + toast.error("Something went wrong, please try again later."); + }) + .finally(reload); + }; - const getFileAssetsColumns = () => { - if (user) { - const containerClassName = - "flex gap-2 text-mti-purple-light hover:text-mti-purple-dark ease-in-out duration-300 cursor-pointer"; - switch (user.type) { - case "corporate": - return [ - columnHelper.accessor("corporateTransfer", { - header: "Corporate transfer", - id: "corporateTransfer", - cell: (info) => ( -
- -
- ), - }), - ]; - case "agent": - return [ - columnHelper.accessor("commissionTransfer", { - header: "Commission transfer", - id: "commissionTransfer", - cell: (info) => ( -
- -
- ), - }), - ]; - case "admin": - return [ - columnHelper.accessor("corporateTransfer", { - header: "Corporate transfer", - id: "corporateTransfer", - cell: (info) => ( -
- -
- ), - }), - columnHelper.accessor("commissionTransfer", { - header: "Commission transfer", - id: "commissionTransfer", - cell: (info) => ( -
- -
- ), - }), - ]; - case "developer": - return [ - columnHelper.accessor("corporateTransfer", { - header: "Corporate transfer", - id: "corporateTransfer", - cell: (info) => ( -
- -
- ), - }), - columnHelper.accessor("commissionTransfer", { - header: "Commission transfer", - id: "commissionTransfer", - cell: (info) => ( -
- -
- ), - }), - ]; - default: - return []; - } - } + const getFileAssetsColumns = () => { + if (user) { + const containerClassName = "flex gap-2 text-mti-purple-light hover:text-mti-purple-dark ease-in-out duration-300 cursor-pointer"; + switch (user.type) { + case "corporate": + return [ + columnHelper.accessor("corporateTransfer", { + header: "Corporate transfer", + id: "corporateTransfer", + cell: (info) => ( +
+ +
+ ), + }), + ]; + case "agent": + return [ + columnHelper.accessor("commissionTransfer", { + header: "Commission transfer", + id: "commissionTransfer", + cell: (info) => ( +
+ +
+ ), + }), + ]; + case "admin": + return [ + columnHelper.accessor("corporateTransfer", { + header: "Corporate transfer", + id: "corporateTransfer", + cell: (info) => ( +
+ +
+ ), + }), + columnHelper.accessor("commissionTransfer", { + header: "Commission transfer", + id: "commissionTransfer", + cell: (info) => ( +
+ +
+ ), + }), + ]; + case "developer": + return [ + columnHelper.accessor("corporateTransfer", { + header: "Corporate transfer", + id: "corporateTransfer", + cell: (info) => ( +
+ +
+ ), + }), + columnHelper.accessor("commissionTransfer", { + header: "Commission transfer", + id: "commissionTransfer", + cell: (info) => ( +
+ +
+ ), + }), + ]; + default: + return []; + } + } - return []; - }; + return []; + }; - const columHelperValue = (key: string, info: any) => { - switch (key) { - case "agentCommission": { - const value = info.getValue(); - return { value: `${value}%` }; - } - case "agent": { - const user = users.find( - (x) => x.id === info.row.original.agent - ) as AgentUser; - return { - value: user?.name, - user, - }; - } - case "agentValue": - case "amount": { - const value = info.getValue(); - const numberValue = toFixedNumber(value, 2); - return { value: numberValue }; - } - case "date": { - const value = info.getValue(); - return { value: moment(value).format("DD/MM/YYYY") }; - } - case "corporate": { - const specificValue = info.row.original.corporate; - const user = users.find((x) => x.id === specificValue) as CorporateUser; - return { - user, - value: - user?.corporateInformation.companyInformation.name || user?.name, - }; - } - case "currency": { - return { - value: info.row.original.currency, - }; - } - case "isPaid": - case "corporateId": - default: { - const value = info.getValue(); - return { value }; - } - } - }; + const columHelperValue = (key: string, info: any) => { + switch (key) { + case "agentCommission": { + const value = info.getValue(); + return {value: `${value}%`}; + } + case "agent": { + const user = users.find((x) => x.id === info.row.original.agent) as AgentUser; + return { + value: user?.name, + user, + }; + } + case "agentValue": + case "amount": { + const value = info.getValue(); + const numberValue = toFixedNumber(value, 2); + return {value: numberValue}; + } + case "date": { + const value = info.getValue(); + return {value: moment(value).format("DD/MM/YYYY")}; + } + case "corporate": { + const specificValue = info.row.original.corporate; + const user = users.find((x) => x.id === specificValue) as CorporateUser; + return { + user, + value: user?.corporateInformation.companyInformation.name || user?.name, + }; + } + case "currency": { + return { + value: info.row.original.currency, + }; + } + case "isPaid": + case "corporateId": + default: { + const value = info.getValue(); + return {value}; + } + } + }; - const hiddenToCorporateColumns = () => { - if (user && user.type !== "corporate") - return [ - columnHelper.accessor("agent", { - header: "Country Manager", - id: "agent", - cell: (info) => { - const { user, value } = columHelperValue(info.column.id, info); - return ( -
setSelectedAgentUser(user)} - > - {value} -
- ); - }, - }), - columnHelper.accessor("agentCommission", { - header: "Commission", - id: "agentCommission", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); - return <>{value}; - }, - }), - columnHelper.accessor("agentValue", { - header: "Commission Value", - id: "agentValue", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); - const finalValue = `${value} ${info.row.original.currency}`; - return {finalValue}; - }, - }), - ]; - return []; - }; + const hiddenToCorporateColumns = () => { + if (user && user.type !== "corporate") + return [ + columnHelper.accessor("agent", { + header: "Country Manager", + id: "agent", + cell: (info) => { + const {user, value} = columHelperValue(info.column.id, info); + return ( +
setSelectedAgentUser(user)}> + {value} +
+ ); + }, + }), + columnHelper.accessor("agentCommission", { + header: "Commission", + id: "agentCommission", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); + return <>{value}; + }, + }), + columnHelper.accessor("agentValue", { + header: "Commission Value", + id: "agentValue", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); + const finalValue = `${value} ${info.row.original.currency}`; + return {finalValue}; + }, + }), + ]; + return []; + }; - const defaultColumns = [ - columnHelper.accessor("corporate", { - header: "Corporate ID", - id: "corporateId", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); - return value; - }, - }), - columnHelper.accessor("corporate", { - header: "Corporate", - id: "corporate", - cell: (info) => { - const { user, value } = columHelperValue(info.column.id, info); - return ( -
setSelectedCorporateUser(user)} - > - {value} -
- ); - }, - }), - columnHelper.accessor("date", { - header: "Date", - id: "date", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); - return {value}; - }, - }), - columnHelper.accessor("value", { - header: "Amount", - id: "amount", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); - const currency = CURRENCIES.find( - (x) => x.currency === info.row.original.currency - )?.label; - const finalValue = `${value} ${currency}`; - return {finalValue}; - }, - }), - ...hiddenToCorporateColumns(), - columnHelper.accessor("isPaid", { - header: "Paid", - id: "isPaid", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); + const defaultColumns = [ + columnHelper.accessor("corporate", { + header: "Corporate ID", + id: "corporateId", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); + return value; + }, + }), + columnHelper.accessor("corporate", { + header: "Corporate", + id: "corporate", + cell: (info) => { + const {user, value} = columHelperValue(info.column.id, info); + return ( +
setSelectedCorporateUser(user)}> + {value} +
+ ); + }, + }), + columnHelper.accessor("date", { + header: "Date", + id: "date", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); + return {value}; + }, + }), + columnHelper.accessor("value", { + header: "Amount", + id: "amount", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); + const currency = CURRENCIES.find((x) => x.currency === info.row.original.currency)?.label; + const finalValue = `${value} ${currency}`; + return {finalValue}; + }, + }), + ...hiddenToCorporateColumns(), + columnHelper.accessor("isPaid", { + header: "Paid", + id: "isPaid", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); - return ( - { - if (user?.type === agent || user?.type === "corporate" || value) - return null; - if ( - !info.row.original.commissionTransfer || - !info.row.original.corporateTransfer - ) - return alert( - "All files need to be uploaded to consider it paid!" - ); - if ( - !confirm(`Are you sure you want to consider this payment paid?`) - ) - return null; + return ( + { + if (user?.type === agent || user?.type === "corporate" || value) return null; + if (!info.row.original.commissionTransfer || !info.row.original.corporateTransfer) + return alert("All files need to be uploaded to consider it paid!"); + if (!confirm(`Are you sure you want to consider this payment paid?`)) return null; - return updatePayment(info.row.original, "isPaid", e); - }} - > - - - ); - }, - }), - ...getFileAssetsColumns(), - { - header: "", - id: "actions", - cell: ({ row }: { row: { original: Payment } }) => { - return ( -
- {user?.type !== "agent" && ( -
deletePayment(row.original.id)} - > - -
- )} -
- ); - }, - }, - ]; + return updatePayment(info.row.original, "isPaid", e); + }}> + +
+ ); + }, + }), + ...getFileAssetsColumns(), + { + header: "", + id: "actions", + cell: ({row}: {row: {original: Payment}}) => { + return ( +
+ {user?.type !== "agent" && ( +
deletePayment(row.original.id)}> + +
+ )} +
+ ); + }, + }, + ]; - const table = useReactTable({ - data: displayPayments, - columns: defaultColumns, - getCoreRowModel: getCoreRowModel(), - }); + const table = useReactTable({ + data: displayPayments, + columns: defaultColumns, + getCoreRowModel: getCoreRowModel(), + }); - const updatedPaypalPayments = useMemo( - () => - paypalPayments - .filter((p) => { - const date = moment(p.createdAt); - return date.isAfter(startDatePaymob) && date.isBefore(endDatePaymob); - }) - .map((p) => { - const user = users.find((x) => x.id === p.userId) as User; - return { ...p, name: user?.name, email: user?.email }; - }), - [paypalPayments, users, startDatePaymob, endDatePaymob] - ); + const updatedPaypalPayments = useMemo( + () => + paypalPayments + .filter((p) => { + const date = moment(p.createdAt); + return date.isAfter(startDatePaymob) && date.isBefore(endDatePaymob); + }) + .map((p) => { + const user = users.find((x) => x.id === p.userId) as User; + return {...p, name: user?.name, email: user?.email}; + }), + [paypalPayments, users, startDatePaymob, endDatePaymob], + ); - const paypalColumns = [ - paypalColumnHelper.accessor("orderId", { - header: "Order ID", - id: "orderId", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); - return {value}; - }, - }), - paypalColumnHelper.accessor("status", { - header: "Status", - id: "status", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); - return {value}; - }, - }), - paypalColumnHelper.accessor("name", { - header: "User Name", - id: "name", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); - return {value}; - }, - }), - paypalColumnHelper.accessor("email", { - header: "Email", - id: "email", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); - return {value}; - }, - }), - paypalColumnHelper.accessor("value", { - header: "Amount", - id: "value", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); - const finalValue = `${value} ${info.row.original.currency}`; - return {finalValue}; - }, - }), - paypalColumnHelper.accessor("createdAt", { - header: "Date", - id: "createdAt", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); - return {moment(value).format("DD/MM/YYYY")}; - }, - }), - paypalColumnHelper.accessor("subscriptionExpirationDate", { - header: "Expiration Date", - id: "subscriptionExpirationDate", - cell: (info) => { - const { value } = columHelperValue(info.column.id, info); - return {moment(value).format("DD/MM/YYYY")}; - }, - }), - ]; + const paypalColumns = [ + paypalColumnHelper.accessor("orderId", { + header: "Order ID", + id: "orderId", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); + return {value}; + }, + }), + paypalColumnHelper.accessor("status", { + header: "Status", + id: "status", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); + return {value}; + }, + }), + paypalColumnHelper.accessor("name", { + header: "User Name", + id: "name", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); + return {value}; + }, + }), + paypalColumnHelper.accessor("email", { + header: "Email", + id: "email", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); + return {value}; + }, + }), + paypalColumnHelper.accessor("value", { + header: "Amount", + id: "value", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); + const finalValue = `${value} ${info.row.original.currency}`; + return {finalValue}; + }, + }), + paypalColumnHelper.accessor("createdAt", { + header: "Date", + id: "createdAt", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); + return {moment(value).format("DD/MM/YYYY")}; + }, + }), + paypalColumnHelper.accessor("subscriptionExpirationDate", { + header: "Expiration Date", + id: "subscriptionExpirationDate", + cell: (info) => { + const {value} = columHelperValue(info.column.id, info); + return {moment(value).format("DD/MM/YYYY")}; + }, + }), + ]; - const { rows: filteredRows, renderSearch } = useListSearch( - paypalFilterRows, - updatedPaypalPayments - ); + const {rows: filteredRows, renderSearch} = useListSearch(paypalFilterRows, updatedPaypalPayments); - const paypalTable = useReactTable({ - data: filteredRows.sort((a, b) => - moment(b.createdAt).diff(moment(a.createdAt), "second") - ), - columns: paypalColumns, - getCoreRowModel: getCoreRowModel(), - }); + const paypalTable = useReactTable({ + data: filteredRows.sort((a, b) => moment(b.createdAt).diff(moment(a.createdAt), "second")), + columns: paypalColumns, + getCoreRowModel: getCoreRowModel(), + }); - const getUserModal = () => { - if (user) { - if (selectedCorporateUser) { - return ( - setSelectedCorporateUser(undefined)} - > - <> - {selectedCorporateUser && ( -
- { - setSelectedCorporateUser(undefined); - if (shouldReload) reload(); - }} - user={selectedCorporateUser} - disabled - disabledFields={{ countryManager: true }} - /> -
- )} - -
- ); - } + const getUserModal = () => { + if (user) { + if (selectedCorporateUser) { + return ( + setSelectedCorporateUser(undefined)}> + <> + {selectedCorporateUser && ( +
+ { + setSelectedCorporateUser(undefined); + if (shouldReload) reload(); + }} + user={selectedCorporateUser} + disabled + disabledFields={{countryManager: true}} + /> +
+ )} + +
+ ); + } - if (selectedAgentUser) { - return ( - setSelectedAgentUser(undefined)} - > - <> - {selectedAgentUser && ( -
- { - setSelectedAgentUser(undefined); - if (shouldReload) reload(); - }} - user={selectedAgentUser} - /> -
- )} - -
- ); - } - } + if (selectedAgentUser) { + return ( + setSelectedAgentUser(undefined)}> + <> + {selectedAgentUser && ( +
+ { + setSelectedAgentUser(undefined); + if (shouldReload) reload(); + }} + user={selectedAgentUser} + /> +
+ )} + +
+ ); + } + } - return null; - }; + return null; + }; - const getCSVData = () => { - const tables = [table, paypalTable]; - const whitelists = [ - CSV_PAYMENTS_WHITELISTED_KEYS, - CSV_PAYPAL_WHITELISTED_KEYS, - ]; - const currentTable = tables[selectedIndex]; - const whitelist = whitelists[selectedIndex]; - const columns = (currentTable.getHeaderGroups() as any[]).reduce( - (accm: any[], group: any) => { - const whitelistedColumns = group.headers.filter((header: any) => - whitelist.includes(header.id) - ); + const getCSVData = () => { + const tables = [table, paypalTable]; + const whitelists = [CSV_PAYMENTS_WHITELISTED_KEYS, CSV_PAYPAL_WHITELISTED_KEYS]; + const currentTable = tables[selectedIndex]; + const whitelist = whitelists[selectedIndex]; + const columns = (currentTable.getHeaderGroups() as any[]).reduce((accm: any[], group: any) => { + const whitelistedColumns = group.headers.filter((header: any) => whitelist.includes(header.id)); - const data = whitelistedColumns.map((data: any) => ({ - key: data.column.columnDef.id, - label: data.column.columnDef.header, - })) as SimpleCSVColumn[]; + const data = whitelistedColumns.map((data: any) => ({ + key: data.column.columnDef.id, + label: data.column.columnDef.header, + })) as SimpleCSVColumn[]; - return [...accm, ...data]; - }, - [] - ); + return [...accm, ...data]; + }, []); - const { rows } = currentTable.getRowModel(); + const {rows} = currentTable.getRowModel(); - const finalColumns = [ - ...columns, - { - key: "currency", - label: "Currency", - }, - ]; + const finalColumns = [ + ...columns, + { + key: "currency", + label: "Currency", + }, + ]; - return { - columns: finalColumns, - rows: rows.map((row) => { - return finalColumns.reduce((accm, { key }) => { - const { value } = columHelperValue(key, { - row, - getValue: () => row.getValue(key), - }); - return { - ...accm, - [key]: value, - }; - }, {}); - }), - }; - }; + return { + columns: finalColumns, + rows: rows.map((row) => { + return finalColumns.reduce((accm, {key}) => { + const {value} = columHelperValue(key, { + row, + getValue: () => row.getValue(key), + }); + return { + ...accm, + [key]: value, + }; + }, {}); + }), + }; + }; - const { rows: csvRows, columns: csvColumns } = getCSVData(); + const {rows: csvRows, columns: csvColumns} = getCSVData(); - const renderTable = (table: Table) => ( - - - {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())} -
- ); + const renderTable = (table: Table) => ( + + + {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())} +
+ ); - return ( - <> - - Payment Record | EnCoach - - - - - - {user && ( - - {getUserModal()} - setIsCreatingPayment(false)} - > - setIsCreatingPayment(false)} - reload={reload} - showComission={checkAccess(user, ["developer", "admin"])} - /> - + return ( + <> + + Payment Record | EnCoach + + + + + + {user && ( + + {getUserModal()} + setIsCreatingPayment(false)}> + setIsCreatingPayment(false)} + reload={reload} + showComission={checkAccess(user, ["developer", "admin"])} + /> + -
-

Payment Record

-
- {checkAccess(user, [ - "developer", - "admin", - "agent", - "corporate", - "mastercorporate", - ]) && ( - - )} - {checkAccess(user, ["developer", "admin"]) && ( - - )} -
-
- - - - clsx( - "w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-mti-purple-light", - "ring-white ring-opacity-60 ring-offset-2 ring-offset-mti-purple-light focus:outline-none focus:ring-2", - "transition duration-300 ease-in-out", - selected - ? "bg-white shadow" - : "text-blue-100 hover:bg-white/[0.12] hover:text-mti-purple-dark" - ) - } - > - Payments - - {checkAccess(user, ["developer", "admin"]) && ( - - clsx( - "w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-mti-purple-light", - "ring-white ring-opacity-60 ring-offset-2 ring-offset-mti-purple-light focus:outline-none focus:ring-2", - "transition duration-300 ease-in-out", - selected - ? "bg-white shadow" - : "text-blue-100 hover:bg-white/[0.12] hover:text-mti-purple-dark" - ) - } - > - Paymob - - )} - - - -
-
- - u.type === "agent") as AgentUser[] - ).map((user) => ({ - value: user.id, - meta: user, - label: `${user.name} - ${user.email}`, - }))} - value={ - agent - ? { - value: agent?.id, - label: `${agent.name} - ${agent.email}`, - } - : undefined - } - onChange={(value) => - setAgent( - value !== null ? (value as any).meta : undefined - ) - } - menuPortalTarget={document?.body} - styles={{ - menuPortal: (base) => ({ ...base, zIndex: 9999 }), - control: (styles) => ({ - ...styles, - paddingLeft: "4px", - border: "none", - outline: "none", - ":focus": { - outline: "none", - }, - }), - option: (styles, state) => ({ - ...styles, - backgroundColor: state.isFocused - ? "#D5D9F0" - : state.isSelected - ? "#7872BF" - : "white", - color: state.isFocused ? "black" : styles.color, - }), - }} - /> -
- )} -
- - e.value === commissionTransfer - )} - onChange={(value) => { - if (value) return setCommissionTransfer(value.value); - setCommissionTransfer(null); - }} - menuPortalTarget={document?.body} - styles={{ - menuPortal: (base) => ({ ...base, zIndex: 9999 }), - control: (styles) => ({ - ...styles, - paddingLeft: "4px", - border: "none", - outline: "none", - ":focus": { - outline: "none", - }, - }), - option: (styles, state) => ({ - ...styles, - backgroundColor: state.isFocused - ? "#D5D9F0" - : state.isSelected - ? "#7872BF" - : "white", - color: state.isFocused ? "black" : styles.color, - }), - }} - /> -
- )} -
- - u.type === "corporate") as CorporateUser[]).map((user) => ({ + value: user.id, + meta: user, + label: `${user.corporateInformation?.companyInformation?.name || user.name} - ${user.email}`, + }))} + defaultValue={ + user.type === "corporate" + ? { + value: user.id, + meta: user, + label: `${user.corporateInformation?.companyInformation?.name || user.name} - ${ + user.email + }`, + } + : undefined + } + isDisabled={user.type === "corporate"} + onChange={(value) => setCorporate((value as any)?.meta ?? undefined)} + menuPortalTarget={document?.body} + styles={{ + menuPortal: (base) => ({...base, zIndex: 9999}), + control: (styles) => ({ + ...styles, + paddingLeft: "4px", + border: "none", + outline: "none", + ":focus": { + outline: "none", + }, + }), + option: (styles, state) => ({ + ...styles, + backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white", + color: state.isFocused ? "black" : styles.color, + }), + }} + /> +
+ {user.type !== "corporate" && ( +
+ + e.value === paid)} + onChange={(value) => { + if (value) return setPaid(value.value); + setPaid(null); + }} + menuPortalTarget={document?.body} + styles={{ + menuPortal: (base) => ({...base, zIndex: 9999}), + control: (styles) => ({ + ...styles, + paddingLeft: "4px", + border: "none", + outline: "none", + ":focus": { + outline: "none", + }, + }), + option: (styles, state) => ({ + ...styles, + backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white", + color: state.isFocused ? "black" : styles.color, + }), + }} + /> +
+
+ + moment(date).isSameOrBefore(moment(new Date()))} + onChange={([initialDate, finalDate]: [Date, Date]) => { + setStartDate(initialDate ?? moment("01/01/2023").toDate()); + if (finalDate) { + // basicly selecting a final day works as if I'm selecting the first + // minute of that day. this way it covers the whole day + setEndDate(moment(finalDate).endOf("day").toDate()); + return; + } + setEndDate(null); + }} + /> +
+ {user.type !== "corporate" && ( +
+ + e.value === corporateTransfer)} + onChange={(value) => { + if (value) return setCorporateTransfer(value.value); + setCorporateTransfer(null); + }} + menuPortalTarget={document?.body} + styles={{ + menuPortal: (base) => ({...base, zIndex: 9999}), + control: (styles) => ({ + ...styles, + paddingLeft: "4px", + border: "none", + outline: "none", + ":focus": { + outline: "none", + }, + }), + option: (styles, state) => ({ + ...styles, + backgroundColor: state.isFocused ? "#D5D9F0" : state.isSelected ? "#7872BF" : "white", + color: state.isFocused ? "black" : styles.color, + }), + }} + /> +
+
+ {renderTable(table as Table)} +
+ +
+
+ + moment(date).isSameOrBefore(moment(new Date()))} + onChange={([initialDate, finalDate]: [Date, Date]) => { + setStartDatePaymob(initialDate ?? moment("01/01/2023").toDate()); + if (finalDate) { + // basicly selecting a final day works as if I'm selecting the first + // minute of that day. this way it covers the whole day + setEndDatePaymob(moment(finalDate).endOf("day").toDate()); + return; + } + setEndDatePaymob(null); + }} + /> +
+
+ {renderSearch()} + {renderTable(paypalTable as Table)} +
+
+
+
+ )} + + ); } diff --git a/src/pages/payment.tsx b/src/pages/payment.tsx index bc2984f3..78f3b573 100644 --- a/src/pages/payment.tsx +++ b/src/pages/payment.tsx @@ -16,7 +16,7 @@ export const getServerSideProps = withIronSessionSsr(({req, res}) => { envVariables[x] = process.env[x]!; }); - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/permissions/[id].tsx b/src/pages/permissions/[id].tsx index 022ba933..6e66f109 100644 --- a/src/pages/permissions/[id].tsx +++ b/src/pages/permissions/[id].tsx @@ -32,7 +32,7 @@ export const getServerSideProps = withIronSessionSsr(async (context) => { const {req, params} = context; const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/permissions/index.tsx b/src/pages/permissions/index.tsx index 373707e7..6e116600 100644 --- a/src/pages/permissions/index.tsx +++ b/src/pages/permissions/index.tsx @@ -12,7 +12,7 @@ import PermissionList from "@/components/PermissionList"; export const getServerSideProps = withIronSessionSsr(async ({req}) => { const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/profile.tsx b/src/pages/profile.tsx index 93d0efad..d864670b 100644 --- a/src/pages/profile.tsx +++ b/src/pages/profile.tsx @@ -50,7 +50,7 @@ import {getUsers} from "@/utils/users.be"; export const getServerSideProps = withIronSessionSsr(async ({req, res}) => { const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/record.tsx b/src/pages/record.tsx index 3500fe70..c4d520d0 100644 --- a/src/pages/record.tsx +++ b/src/pages/record.tsx @@ -29,7 +29,7 @@ import useGradingSystem from "@/hooks/useGrading"; export const getServerSideProps = withIronSessionSsr(async ({req, res}) => { const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/register.tsx b/src/pages/register.tsx index 3cfda76d..b8961ae9 100644 --- a/src/pages/register.tsx +++ b/src/pages/register.tsx @@ -121,7 +121,7 @@ export default function Register({code: queryCode}: {code: string}) { )} - {user && !user.isVerified && } + {/* {user && !user.isVerified && } */} diff --git a/src/pages/settings.tsx b/src/pages/settings.tsx index b26a6a5e..e3dce976 100644 --- a/src/pages/settings.tsx +++ b/src/pages/settings.tsx @@ -31,7 +31,7 @@ import useUsers from "@/hooks/useUsers"; export const getServerSideProps = withIronSessionSsr(async ({req, res}) => { const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/stats.tsx b/src/pages/stats.tsx index b9c78c8c..4c45090f 100644 --- a/src/pages/stats.tsx +++ b/src/pages/stats.tsx @@ -34,7 +34,7 @@ const COLORS = ["#1EB3FF", "#FF790A", "#3D9F11", "#EF5DA8", "#414288"]; export const getServerSideProps = withIronSessionSsr(({req, res}) => { const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/tickets.tsx b/src/pages/tickets.tsx index d2957f79..fb6e2b47 100644 --- a/src/pages/tickets.tsx +++ b/src/pages/tickets.tsx @@ -22,7 +22,7 @@ const columnHelper = createColumnHelper(); export const getServerSideProps = withIronSessionSsr(({req, res}) => { const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/training/[id]/index.tsx b/src/pages/training/[id]/index.tsx index 2dab7719..69aab218 100644 --- a/src/pages/training/[id]/index.tsx +++ b/src/pages/training/[id]/index.tsx @@ -35,7 +35,7 @@ import {sortByModule} from "@/utils/moduleUtils"; export const getServerSideProps = withIronSessionSsr(({req, res}) => { const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", diff --git a/src/pages/training/index.tsx b/src/pages/training/index.tsx index 3c074561..461ca135 100644 --- a/src/pages/training/index.tsx +++ b/src/pages/training/index.tsx @@ -1,30 +1,30 @@ /* eslint-disable @next/next/no-img-element */ import Head from "next/head"; -import { withIronSessionSsr } from "iron-session/next"; -import { sessionOptions } from "@/lib/session"; -import { User } from "@/interfaces/user"; -import { ToastContainer } from "react-toastify"; +import {withIronSessionSsr} from "iron-session/next"; +import {sessionOptions} from "@/lib/session"; +import {User} from "@/interfaces/user"; +import {ToastContainer} from "react-toastify"; import Layout from "@/components/High/Layout"; -import { shouldRedirectHome } from "@/utils/navigation.disabled"; -import { useEffect, useState } from "react"; +import {shouldRedirectHome} from "@/utils/navigation.disabled"; +import {useEffect, useState} from "react"; import clsx from "clsx"; -import { FaPlus } from "react-icons/fa"; +import {FaPlus} from "react-icons/fa"; import useRecordStore from "@/stores/recordStore"; import router from "next/router"; import useTrainingContentStore from "@/stores/trainingContentStore"; import axios from "axios"; -import { ITrainingContent } from "@/training/TrainingInterfaces"; +import {ITrainingContent} from "@/training/TrainingInterfaces"; import moment from "moment"; -import { uuidv4 } from "@firebase/util"; +import {uuidv4} from "@firebase/util"; import TrainingScore from "@/training/TrainingScore"; import ModuleBadge from "@/components/ModuleBadge"; import RecordFilter from "@/components/Medium/RecordFilter"; import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser"; -export const getServerSideProps = withIronSessionSsr(({ req, res }) => { +export const getServerSideProps = withIronSessionSsr(({req, res}) => { const user = req.session.user; - if (!user || !user.isVerified) { + if (!user) { return { redirect: { destination: "/login", @@ -43,22 +43,23 @@ export const getServerSideProps = withIronSessionSsr(({ req, res }) => { } return { - props: { user: req.session.user }, + props: {user: req.session.user}, }; }, sessionOptions); -const Training: React.FC<{ user: User }> = ({ user }) => { - const [recordUserId, setRecordTraining] = useRecordStore((state) => [ - state.selectedUser, - state.setTraining, - ]); +const Training: React.FC<{user: User}> = ({user}) => { + const [recordUserId, setRecordTraining] = useRecordStore((state) => [state.selectedUser, state.setTraining]); const [filter, setFilter] = useState<"months" | "weeks" | "days" | "assignments">(); const [stats, setTrainingStats] = useTrainingContentStore((state) => [state.stats, state.setStats]); const [isNewContentLoading, setIsNewContentLoading] = useState(stats.length != 0); - const [groupedByTrainingContent, setGroupedByTrainingContent] = useState<{ [key: string]: ITrainingContent }>(); + const [groupedByTrainingContent, setGroupedByTrainingContent] = useState<{[key: string]: ITrainingContent}>(); - const { data: trainingContent, isLoading: areRecordsLoading } = useFilterRecordsByUser(recordUserId || user?.id, undefined, "training"); + const {data: trainingContent, isLoading: areRecordsLoading} = useFilterRecordsByUser( + recordUserId || user?.id, + undefined, + "training", + ); useEffect(() => { const handleRouteChange = (url: string) => { @@ -74,7 +75,7 @@ const Training: React.FC<{ user: User }> = ({ user }) => { useEffect(() => { const postStats = async () => { try { - const response = await axios.post<{ id: string }>(`/api/training`, { userID: user.id, stats: stats }); + const response = await axios.post<{id: string}>(`/api/training`, {userID: user.id, stats: stats}); return response.data.id; } catch (error) { setIsNewContentLoading(false); @@ -97,12 +98,12 @@ const Training: React.FC<{ user: User }> = ({ user }) => { router.push("/record"); }; - const filterTrainingContentByDate = (trainingContent: { [key: string]: ITrainingContent }) => { + const filterTrainingContentByDate = (trainingContent: {[key: string]: ITrainingContent}) => { if (filter) { const filterDate = moment() - .subtract({ [filter as string]: 1 }) + .subtract({[filter as string]: 1}) .format("x"); - const filteredTrainingContent: { [key: string]: ITrainingContent } = {}; + const filteredTrainingContent: {[key: string]: ITrainingContent} = {}; Object.keys(trainingContent).forEach((timestamp) => { if (timestamp >= filterDate) filteredTrainingContent[timestamp] = trainingContent[timestamp]; @@ -117,10 +118,10 @@ const Training: React.FC<{ user: User }> = ({ user }) => { const grouped = trainingContent.reduce((acc, content) => { acc[content.created_at] = content; return acc; - }, {} as { [key: number]: ITrainingContent }); + }, {} as {[key: number]: ITrainingContent}); setGroupedByTrainingContent(grouped); - }else { + } else { setGroupedByTrainingContent(undefined); } }, [trainingContent]); @@ -138,7 +139,7 @@ const Training: React.FC<{ user: User }> = ({ user }) => { const trainingContentContainer = (timestamp: string) => { if (!groupedByTrainingContent) return <>; - + const trainingContent: ITrainingContent = groupedByTrainingContent[timestamp]; const uniqueModules = [...new Set(trainingContent.exams.map((exam) => exam.module))]; @@ -192,7 +193,7 @@ const Training: React.FC<{ user: User }> = ({ user }) => { ) : ( <> - + {user.type === "student" && ( <>
diff --git a/src/utils/exams.be.ts b/src/utils/exams.be.ts index 18621bc6..8b7b83df 100644 --- a/src/utils/exams.be.ts +++ b/src/utils/exams.be.ts @@ -5,7 +5,7 @@ import {DeveloperUser, Stat, StudentUser, User} from "@/interfaces/user"; import {Module} from "@/interfaces"; import {getCorporateUser} from "@/resources/user"; import {getUserCorporate} from "./groups.be"; -import { Db, ObjectId } from "mongodb"; +import {Db, ObjectId} from "mongodb"; export const getExams = async ( db: Db, @@ -18,18 +18,18 @@ export const getExams = async ( variant?: Variant, instructorGender?: InstructorGender, ): Promise => { + const allExams = await db + .collection(module) + .find({ + isDiagnostic: false, + }) + .toArray(); - const allExams = await db.collection(module).find({ - isDiagnostic: false - }).toArray(); - - const shuffledPublicExams = ( - shuffle( - allExams.map((doc) => ({ - ...doc, - module, - })) as Exam[], - ) + const shuffledPublicExams = shuffle( + allExams.map((doc) => ({ + ...doc, + module, + })) as Exam[], ).filter((x) => !x.private); let exams: Exam[] = await filterByOwners(shuffledPublicExams, userId); @@ -39,9 +39,12 @@ export const getExams = async ( exams = await filterByPreference(db, exams, module, userId); if (avoidRepeated === "true") { - const stats = await db.collection("stats").find({ - user: userId - }).toArray(); + const stats = await db + .collection("stats") + .find({ + user: userId, + }) + .toArray(); const filteredExams = exams.filter((x) => !stats.map((s) => s.exam).includes(x.id)); @@ -78,7 +81,7 @@ const filterByOwners = async (exams: Exam[], userID?: string) => { const filterByDifficulty = async (db: Db, exams: Exam[], module: Module, userID?: string) => { if (!userID) return exams; - const user = await db.collection("users").findOne({ _id: new ObjectId(userID) }); + const user = await db.collection("users").findOne({id: userID}); if (!user) return exams; const difficulty = user.levels[module] <= 3 ? "easy" : user.levels[module] <= 6 ? "medium" : "hard"; @@ -92,7 +95,7 @@ const filterByPreference = async (db: Db, exams: Exam[], module: Module, userID? if (!userID) return exams; - const user = await db.collection("users").findOne({ _id: new ObjectId(userID) }); + const user = await db.collection("users").findOne({id: userID}); if (!user) return exams; if (!["developer", "student"].includes(user.type)) return exams; diff --git a/src/utils/users.be.ts b/src/utils/users.be.ts index a04bfd20..cd5c1c1a 100644 --- a/src/utils/users.be.ts +++ b/src/utils/users.be.ts @@ -56,7 +56,7 @@ export async function getLinkedUsers( const participants = uniq([ ...adminGroups.flatMap((x) => x.participants), - ...groups.flat().flatMap((x) => x.participants), + ...(userType === "mastercorporate" ? groups.flat().flatMap((x) => x.participants) : []), ...(userType === "teacher" ? belongingGroups.flatMap((x) => x.participants) : []), ]); diff --git a/yarn.lock b/yarn.lock index f3580bcb..55dfc342 100644 --- a/yarn.lock +++ b/yarn.lock @@ -191,7 +191,7 @@ "@emotion/utils" "0.11.3" "@emotion/weak-memoize" "0.2.5" -"@emotion/cache@^11.13.0": +"@emotion/cache@^11.13.0", "@emotion/cache@^11.4.0": version "11.13.1" resolved "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz" integrity sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw== @@ -202,27 +202,16 @@ "@emotion/weak-memoize" "^0.4.0" stylis "4.2.0" -"@emotion/cache@^11.4.0": - version "11.13.1" - resolved "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz" - integrity sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw== - dependencies: - "@emotion/memoize" "^0.9.0" - "@emotion/sheet" "^1.4.0" - "@emotion/utils" "^1.4.0" - "@emotion/weak-memoize" "^0.4.0" - stylis "4.2.0" - -"@emotion/hash@^0.9.2": - version "0.9.2" - resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz" - integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g== - "@emotion/hash@0.8.0": version "0.8.0" resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz" integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== +"@emotion/hash@^0.9.2": + version "0.9.2" + resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz" + integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g== + "@emotion/is-prop-valid@^0.8.2": version "0.8.8" resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz" @@ -230,16 +219,16 @@ dependencies: "@emotion/memoize" "0.7.4" -"@emotion/memoize@^0.9.0": - version "0.9.0" - resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz" - integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== - "@emotion/memoize@0.7.4": version "0.7.4" resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz" integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== +"@emotion/memoize@^0.9.0": + version "0.9.0" + resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz" + integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== + "@emotion/react@^11.8.1": version "11.13.0" resolved "https://registry.npmjs.org/@emotion/react/-/react-11.13.0.tgz" @@ -265,7 +254,7 @@ "@emotion/utils" "0.11.3" csstype "^2.5.7" -"@emotion/serialize@^1.2.0": +"@emotion/serialize@^1.2.0", "@emotion/serialize@^1.3.0": version "1.3.0" resolved "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz" integrity sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA== @@ -276,67 +265,56 @@ "@emotion/utils" "^1.4.0" csstype "^3.0.2" -"@emotion/serialize@^1.3.0": - version "1.3.0" - resolved "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz" - integrity sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA== - dependencies: - "@emotion/hash" "^0.9.2" - "@emotion/memoize" "^0.9.0" - "@emotion/unitless" "^0.9.0" - "@emotion/utils" "^1.4.0" - csstype "^3.0.2" - -"@emotion/sheet@^1.4.0": - version "1.4.0" - resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz" - integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== - "@emotion/sheet@0.9.4": version "0.9.4" resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz" integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== +"@emotion/sheet@^1.4.0": + version "1.4.0" + resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz" + integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== + "@emotion/stylis@0.8.5": version "0.8.5" resolved "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz" integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== -"@emotion/unitless@^0.9.0": - version "0.9.0" - resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz" - integrity sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ== - "@emotion/unitless@0.7.5": version "0.7.5" resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== +"@emotion/unitless@^0.9.0": + version "0.9.0" + resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz" + integrity sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ== + "@emotion/use-insertion-effect-with-fallbacks@^1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz" integrity sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw== -"@emotion/utils@^1.4.0": - version "1.4.0" - resolved "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz" - integrity sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ== - "@emotion/utils@0.11.3": version "0.11.3" resolved "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz" integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw== -"@emotion/weak-memoize@^0.4.0": - version "0.4.0" - resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz" - integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== +"@emotion/utils@^1.4.0": + version "1.4.0" + resolved "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz" + integrity sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ== "@emotion/weak-memoize@0.2.5": version "0.2.5" resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== +"@emotion/weak-memoize@^0.4.0": + version "0.4.0" + resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz" + integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg== + "@eslint/eslintrc@^1.4.1": version "1.4.1" resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz" @@ -511,7 +489,7 @@ "@firebase/util" "1.9.3" tslib "^2.1.0" -"@firebase/database-compat@^0.3.4", "@firebase/database-compat@0.3.4": +"@firebase/database-compat@0.3.4", "@firebase/database-compat@^0.3.4": version "0.3.4" resolved "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-0.3.4.tgz" integrity sha512-kuAW+l+sLMUKBThnvxvUZ+Q1ZrF/vFJ58iUY9kAcbX48U03nVzIF6Tmkf0p3WVQwMqiXguSgtOPIB6ZCeF+5Gg== @@ -523,7 +501,7 @@ "@firebase/util" "1.9.3" tslib "^2.1.0" -"@firebase/database-types@^0.10.4", "@firebase/database-types@0.10.4": +"@firebase/database-types@0.10.4", "@firebase/database-types@^0.10.4": version "0.10.4" resolved "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.10.4.tgz" integrity sha512-dPySn0vJ/89ZeBac70T+2tWWPiJXWbmRygYv0smT5TfE3hDrQ09eKMF3Y+vMlTdrMWq7mUdYW5REWPSGH4kAZQ== @@ -744,13 +722,6 @@ node-fetch "2.6.7" tslib "^2.1.0" -"@firebase/util@^1.9.7": - version "1.9.7" - resolved "https://registry.npmjs.org/@firebase/util/-/util-1.9.7.tgz" - integrity sha512-fBVNH/8bRbYjqlbIhZ+lBtdAAS4WqZumx03K06/u7fJSpz1TGjEMm1ImvKD47w+xaFKIP2ori6z8BrbakRfjJA== - dependencies: - tslib "^2.1.0" - "@firebase/util@1.9.3": version "1.9.3" resolved "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz" @@ -758,6 +729,13 @@ dependencies: tslib "^2.1.0" +"@firebase/util@^1.9.7": + version "1.9.7" + resolved "https://registry.npmjs.org/@firebase/util/-/util-1.9.7.tgz" + integrity sha512-fBVNH/8bRbYjqlbIhZ+lBtdAAS4WqZumx03K06/u7fJSpz1TGjEMm1ImvKD47w+xaFKIP2ori6z8BrbakRfjJA== + dependencies: + tslib "^2.1.0" + "@firebase/webchannel-wrapper@0.9.0": version "0.9.0" resolved "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.9.0.tgz" @@ -1020,6 +998,46 @@ dependencies: glob "7.1.7" +"@next/swc-darwin-arm64@14.2.5": + version "14.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz#d0a160cf78c18731c51cc0bff131c706b3e9bb05" + integrity sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ== + +"@next/swc-darwin-x64@14.2.5": + version "14.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz#eb832a992407f6e6352eed05a073379f1ce0589c" + integrity sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA== + +"@next/swc-linux-arm64-gnu@14.2.5": + version "14.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz#098fdab57a4664969bc905f5801ef5a89582c689" + integrity sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA== + +"@next/swc-linux-arm64-musl@14.2.5": + version "14.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz#243a1cc1087fb75481726dd289c7b219fa01f2b5" + integrity sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA== + +"@next/swc-linux-x64-gnu@14.2.5": + version "14.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz#b8a2e436387ee4a52aa9719b718992e0330c4953" + integrity sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ== + +"@next/swc-linux-x64-musl@14.2.5": + version "14.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz#cb8a9adad5fb8df86112cfbd363aab5c6d32757b" + integrity sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ== + +"@next/swc-win32-arm64-msvc@14.2.5": + version "14.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz#81f996c1c38ea0900d4e7719cc8814be8a835da0" + integrity sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw== + +"@next/swc-win32-ia32-msvc@14.2.5": + version "14.2.5" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz#f61c74ce823e10b2bc150e648fc192a7056422e0" + integrity sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg== + "@next/swc-win32-x64-msvc@14.2.5": version "14.2.5" resolved "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz" @@ -1033,7 +1051,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -1591,6 +1609,14 @@ resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz" integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== +"@swc/helpers@0.5.5": + version "0.5.5" + resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz" + integrity sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A== + dependencies: + "@swc/counter" "^0.1.3" + tslib "^2.4.0" + "@swc/helpers@^0.4.2": version "0.4.14" resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz" @@ -1605,14 +1631,6 @@ dependencies: tslib "^2.4.0" -"@swc/helpers@0.5.5": - version "0.5.5" - resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz" - integrity sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A== - dependencies: - "@swc/counter" "^0.1.3" - tslib "^2.4.0" - "@tanstack/react-table@^8.10.1": version "8.19.3" resolved "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.19.3.tgz" @@ -1826,7 +1844,7 @@ resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz" integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== -"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@>=8.1.0", "@types/node@18.13.0": +"@types/node@*", "@types/node@18.13.0", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@>=8.1.0": version "18.13.0" resolved "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz" integrity sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg== @@ -2652,7 +2670,7 @@ classnames@^2.2.6, classnames@^2.3.0, classnames@^2.5.1: resolved "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== -client-only@^0.0.1, client-only@0.0.1: +client-only@0.0.1, client-only@^0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz" integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== @@ -2675,20 +2693,16 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" - clone@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz" integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== +clsx@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz" + integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q== + clsx@^1.1.1: version "1.2.1" resolved "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz" @@ -2699,11 +2713,6 @@ clsx@^2.0.0, clsx@^2.1.1: resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== -clsx@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz" - integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q== - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" @@ -2718,16 +2727,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@^1.0.0, color-name@^1.1.4, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + color-string@^1.9.1: version "1.9.1" resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" @@ -2953,6 +2962,13 @@ dayjs@^1.8.34: resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== +debug@4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debug@^3.2.7: version "3.2.7" resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" @@ -2960,13 +2976,6 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@4: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" @@ -3141,7 +3150,7 @@ eastasianwidth@^0.2.0: resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== -ecdsa-sig-formatter@^1.0.11, ecdsa-sig-formatter@1.0.11: +ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: version "1.0.11" resolved "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz" integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== @@ -3894,6 +3903,11 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + fstream@^1.0.12: version "1.0.12" resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz" @@ -3996,7 +4010,7 @@ get-tsconfig@^4.2.0: resolved "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.4.0.tgz" integrity sha512-0Gdjo/9+FzsYhXCEFueo2aY1z1tpXrxWZzP7k8ul9qt1U5o8rYJwTJYmaeHdrVosYIVYkOy2iwCJ9FdpocJhPQ== -glob-parent@^5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -4010,12 +4024,29 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== +glob@7.1.6: + version "7.1.6" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: - is-glob "^4.0.1" + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@7.1.7, glob@^7.1.3, glob@^7.1.4: + version "7.1.7" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" glob@^10.4.2: version "10.4.5" @@ -4029,18 +4060,6 @@ glob@^10.4.2: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@^7.1.3, glob@^7.1.4, glob@7.1.7: - version "7.1.7" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@^7.2.3: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" @@ -4064,18 +4083,6 @@ glob@^8.0.0: minimatch "^5.0.1" once "^1.3.0" -glob@7.1.6: - version "7.1.6" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - globals@^11.1.0: version "11.12.0" resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" @@ -4374,7 +4381,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3, inherits@2: +inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -5062,18 +5069,18 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -lru-cache@^10.2.0: - version "10.4.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz" - integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== - -lru-cache@^6.0.0, lru-cache@6.0.0: +lru-cache@6.0.0, lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== dependencies: yallist "^4.0.0" +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-memoizer@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.3.0.tgz" @@ -5149,7 +5156,7 @@ micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" -"mime-db@>= 1.43.0 < 2", mime-db@1.52.0: +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -5173,14 +5180,7 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^5.0.1: - version "5.1.6" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" - integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== - dependencies: - brace-expansion "^2.0.1" - -minimatch@^5.1.0: +minimatch@^5.0.1, minimatch@^5.1.0: version "5.1.6" resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== @@ -5224,11 +5224,6 @@ minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" -mkdirp@^1.0.3, mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - "mkdirp@>=0.5 0": version "0.5.6" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" @@ -5236,6 +5231,11 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: dependencies: minimist "^1.2.6" +mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + moment-timezone@^0.5.44: version "0.5.45" resolved "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.45.tgz" @@ -5265,7 +5265,7 @@ mongodb@^6.8.1: bson "^6.7.0" mongodb-connection-string-url "^3.0.0" -ms@^2.1.1, ms@2.1.2: +ms@2.1.2, ms@^2.1.1: version "2.1.2" resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== @@ -5327,21 +5327,14 @@ node-addon-api@^5.0.0: resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz" integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== -node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@2.6.7: +node-fetch@2.6.7, node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" -node-fetch@^2.6.12: - version "2.7.0" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - -node-fetch@^2.6.9: +node-fetch@^2.6.12, node-fetch@^2.6.9: version "2.7.0" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -5702,7 +5695,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^ resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8, postcss@^8.0.9, postcss@^8.4.21, postcss@8.4.31: +postcss@8.4.31, postcss@^8, postcss@^8.0.9, postcss@^8.4.21: version "8.4.31" resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz" integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== @@ -5744,15 +5737,6 @@ promise-polyfill@^8.3.0: resolved "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.3.0.tgz" integrity sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg== -prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - prop-types@15.7.2: version "15.7.2" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz" @@ -5762,6 +5746,15 @@ prop-types@15.7.2: object-assign "^4.1.1" react-is "^16.8.1" +prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + proto3-json-serializer@^1.0.0: version "1.1.1" resolved "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-1.1.1.tgz" @@ -5785,6 +5778,24 @@ protobufjs-cli@1.1.1: tmp "^0.2.1" uglify-js "^3.7.7" +protobufjs@7.2.4: + version "7.2.4" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz" + integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + protobufjs@^6.11.3: version "6.11.3" resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz" @@ -5840,24 +5851,6 @@ protobufjs@^7.2.5: "@types/node" ">=13.7.0" long "^5.0.0" -protobufjs@7.2.4: - version "7.2.4" - resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz" - integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/node" ">=13.7.0" - long "^5.0.0" - proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" @@ -6159,33 +6152,7 @@ read-excel-file@^5.7.1: fflate "^0.7.3" unzipper "^0.12.2" -readable-stream@^2.0.0: - version "2.3.8" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^2.0.2: - version "2.3.8" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^2.0.5: +readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -6207,19 +6174,6 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@~2.3.6: - version "2.3.8" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - readdir-glob@^1.1.2: version "1.1.3" resolved "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz" @@ -6326,13 +6280,6 @@ reusify@^1.0.4: resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - rimraf@2: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" @@ -6340,6 +6287,13 @@ rimraf@2: dependencies: glob "^7.1.3" +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" @@ -6347,7 +6301,7 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@^5.0.1, safe-buffer@>=5.1.0, safe-buffer@~5.2.0: +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -6554,20 +6508,6 @@ streamsearch@^1.1.0: resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" @@ -6627,6 +6567,20 @@ string.prototype.trimstart@^1.0.6: define-properties "^1.1.4" es-abstract "^1.20.4" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + "strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" @@ -7081,7 +7035,7 @@ use-sidecar@^1.1.2: detect-node-es "^1.1.0" tslib "^2.0.0" -use-sync-external-store@^1.2.0, use-sync-external-store@1.2.0: +use-sync-external-store@1.2.0, use-sync-external-store@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== @@ -7091,12 +7045,7 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -uuid@^8.0.0: - version "8.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -uuid@^8.3.0: +uuid@^8.0.0, uuid@^8.3.0: version "8.3.2" resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -7331,11 +7280,6 @@ yargs-parser@^20.2.2: resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== - yargs@^15.3.1: version "15.4.1" resolved "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz" @@ -7366,19 +7310,6 @@ yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.7.2: - version "17.7.2" - resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== - dependencies: - cliui "^8.0.1" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" - y18n "^5.0.5" - yargs-parser "^21.1.1" - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"