From 9c8d7988c5743c8af4d86df7e43348eaba65f7d0 Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Wed, 6 Dec 2023 15:16:48 +0000 Subject: [PATCH 01/16] Changed Comercial labels to Corporate --- src/components/DemographicInformationInput.tsx | 8 ++++---- src/components/UserCard.tsx | 10 +++++----- src/pages/profile.tsx | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/DemographicInformationInput.tsx b/src/components/DemographicInformationInput.tsx index 222dc546..1f90ff21 100644 --- a/src/components/DemographicInformationInput.tsx +++ b/src/components/DemographicInformationInput.tsx @@ -24,7 +24,7 @@ export default function DemographicInformationInput({user, mutateUser}: Props) { const [position, setPosition] = useState(); const [isLoading, setIsLoading] = useState(false); - const [companyName, setCompanyName] = useState(); + const [corporateName, setCorporateName] = useState(); const [commercialRegistration, setCommercialRegistration] = useState(); const save = (e?: FormEvent) => { @@ -40,7 +40,7 @@ export default function DemographicInformationInput({user, mutateUser}: Props) { employment: user.type === "corporate" ? undefined : employment, position: user.type === "corporate" ? position : undefined, }, - agentInformation: user.type === "agent" ? {companyName, commercialRegistration} : undefined, + agentInformation: user.type === "agent" ? {corporateName, commercialRegistration} : undefined, }) .then((response) => mutateUser((response.data as {user: User}).user)) .catch(() => { @@ -62,7 +62,7 @@ export default function DemographicInformationInput({user, mutateUser}: Props) {
{user.type === "agent" && (
- + {!isLoading && "Save information"} {isLoading && ( diff --git a/src/components/UserCard.tsx b/src/components/UserCard.tsx index 682b32d8..f81302ac 100644 --- a/src/components/UserCard.tsx +++ b/src/components/UserCard.tsx @@ -146,11 +146,11 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers, <>
@@ -159,7 +159,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers, type="text" name="commercialRegistration" onChange={setCommercialRegistration} - placeholder="Enter company name" + placeholder="Enter commercial registration" defaultValue={commercialRegistration} required /> @@ -171,11 +171,11 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers, <>
null} - placeholder="Enter company name" + placeholder="Enter corporate name" defaultValue={user.agentInformation.companyName} disabled /> @@ -227,7 +227,7 @@ export default function Home() { type="text" name="commercialRegistration" onChange={() => null} - placeholder="Enter company name" + placeholder="Enter commercial registration" defaultValue={user.agentInformation.commercialRegistration} disabled /> From f36384fdb447ecf2381336c1c26aae21dbd8e8dd Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Wed, 6 Dec 2023 15:43:44 +0000 Subject: [PATCH 02/16] Replaced Corporate Icon on Admin dashboard --- src/dashboards/Admin.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/dashboards/Admin.tsx b/src/dashboards/Admin.tsx index 097bb968..f50ff99d 100644 --- a/src/dashboards/Admin.tsx +++ b/src/dashboards/Admin.tsx @@ -13,9 +13,8 @@ import { BsGlobeCentralSouthAsia, BsPerson, BsPersonFill, - BsPersonFillGear, - BsPersonGear, BsPersonLinesFill, + BsBank, } from "react-icons/bs"; import UserCard from "@/components/UserCard"; import useGroups from "@/hooks/useGroups"; @@ -207,7 +206,7 @@ export default function AdminDashboard({user}: Props) { color="purple" /> x.type === "corporate").length} onClick={() => setPage("corporate")} From 62b2f477f427bb7d0d1207e4d27bfedb8462e2ee Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Wed, 6 Dec 2023 15:54:49 +0000 Subject: [PATCH 03/16] Replaced Corporate Icon on Agent Dashboard --- src/dashboards/Agent.tsx | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/dashboards/Agent.tsx b/src/dashboards/Agent.tsx index f951f04e..4c4cd21e 100644 --- a/src/dashboards/Agent.tsx +++ b/src/dashboards/Agent.tsx @@ -9,17 +9,8 @@ import moment from "moment"; import {useEffect, useState} from "react"; import { BsArrowLeft, - BsClipboard2Data, - BsClipboard2DataFill, - BsClock, - BsGlobeCentralSouthAsia, - BsPaperclip, - BsPerson, - BsPersonAdd, BsPersonFill, - BsPersonFillGear, - BsPersonGear, - BsPersonLinesFill, + BsBank } from "react-icons/bs"; import UserCard from "@/components/UserCard"; import useGroups from "@/hooks/useGroups"; @@ -119,7 +110,7 @@ export default function AgentDashboard({user}: Props) { /> setPage("corporate")} - Icon={BsPersonFill} + Icon={BsBank} label="Corporate" value={users.filter(corporateFilter).length} color="purple" From 9d4071d4cd90444d60c0b3fc2a1e6f5626dc75fa Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Thu, 7 Dec 2023 18:19:01 +0000 Subject: [PATCH 04/16] Added debug settings for vscoe --- .vscode/launch.json | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..e3305190 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Next.js: debug server-side", + "type": "node-terminal", + "request": "launch", + "command": "npm run dev" + }, + { + "name": "Next.js: debug client-side", + "type": "chrome", + "request": "launch", + "url": "http://localhost:3000" + }, + { + "name": "Next.js: debug full stack", + "type": "node-terminal", + "request": "launch", + "command": "npm run dev", + "serverReadyAction": { + "pattern": "- Local:.+(https?://.+)", + "uriFormat": "%s", + "action": "debugWithChrome" + } + } + ] + } \ No newline at end of file From f7af21878e6efdf930cbb4c3e90f26c1b36ad07e Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Thu, 7 Dec 2023 18:20:11 +0000 Subject: [PATCH 05/16] Separate get exam bussiness logic into a backend asset --- src/pages/api/exam/[module]/index.ts | 36 ++++--------------- src/utils/exams.be.ts | 52 ++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 29 deletions(-) create mode 100644 src/utils/exams.be.ts diff --git a/src/pages/api/exam/[module]/index.ts b/src/pages/api/exam/[module]/index.ts index 87fd150b..c48a3d78 100644 --- a/src/pages/api/exam/[module]/index.ts +++ b/src/pages/api/exam/[module]/index.ts @@ -1,14 +1,11 @@ // Next.js API route support: https://nextjs.org/docs/api-routes/introduction import type {NextApiRequest, NextApiResponse} from "next"; import {app} from "@/firebase"; -import {getFirestore, collection, getDocs, query, where, setDoc, doc} from "firebase/firestore"; +import {getFirestore, setDoc, doc} from "firebase/firestore"; import {withIronSessionApiRoute} from "iron-session/next"; import {sessionOptions} from "@/lib/session"; -import {shuffle} from "lodash"; import {Exam} from "@/interfaces/exam"; -import {Stat} from "@/interfaces/user"; -import {v4} from "uuid"; - +import { getExams } from "@/utils/exams.be"; const db = getFirestore(app); export default withIronSessionApiRoute(handler, sessionOptions); @@ -26,31 +23,12 @@ async function GET(req: NextApiRequest, res: NextApiResponse) { return; } - const {module, avoidRepeated} = req.query as {module: string; avoidRepeated: string}; - const moduleRef = collection(db, module); - - const q = query(moduleRef, where("isDiagnostic", "==", false)); - const snapshot = await getDocs(q); - - const exams: Exam[] = shuffle( - snapshot.docs.map((doc) => ({ - id: doc.id, - ...doc.data(), - module, - })), - ) as Exam[]; - - if (avoidRepeated === "true") { - const statsQ = query(collection(db, "stats"), where("user", "==", req.session.user.id)); - const statsSnapshot = await getDocs(statsQ); - - const stats: Stat[] = statsSnapshot.docs.map((doc) => ({id: doc.id, ...doc.data()})) as unknown as Stat[]; - const filteredExams = exams.filter((x) => !stats.map((s) => s.exam).includes(x.id)); - - res.status(200).json(filteredExams.length > 0 ? filteredExams : exams); - return; - } + const { + module, + avoidRepeated, + } = req.query as {module: string; avoidRepeated: string}; + const exams: Exam[] = await getExams(db, module, avoidRepeated, req.session.user.id); res.status(200).json(exams); } diff --git a/src/utils/exams.be.ts b/src/utils/exams.be.ts new file mode 100644 index 00000000..ee9832f3 --- /dev/null +++ b/src/utils/exams.be.ts @@ -0,0 +1,52 @@ +import { + collection, + getDocs, + query, + where, + setDoc, + doc, + Firestore, +} from "firebase/firestore"; +import { shuffle } from "lodash"; +import { Exam } from "@/interfaces/exam"; +import { Stat } from "@/interfaces/user"; + +export const getExams = async ( + db: Firestore, + module: string, + avoidRepeated: string, + // added userId as due to assignments being set from the teacher to the student + // we need to make sure we are serving exams not executed by the user and not + // by the teacher that performed the request + userId: string +): Promise => { + const moduleRef = collection(db, module); + + const q = query(moduleRef, where("isDiagnostic", "==", false)); + const snapshot = await getDocs(q); + + const exams: Exam[] = shuffle( + snapshot.docs.map((doc) => ({ + id: doc.id, + ...doc.data(), + module, + })) + ) as Exam[]; + + if (avoidRepeated === "true") { + const statsQ = query(collection(db, "stats"), where("user", "==", userId)); + const statsSnapshot = await getDocs(statsQ); + + const stats: Stat[] = statsSnapshot.docs.map((doc) => ({ + id: doc.id, + ...doc.data(), + })) as unknown as Stat[]; + const filteredExams = exams.filter( + (x) => !stats.map((s) => s.exam).includes(x.id) + ); + + return filteredExams.length > 0 ? filteredExams : exams; + } + + return exams; +}; From 5eaa0ac26949618be8ccd911b42a421d4b9aabba Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Thu, 7 Dec 2023 18:23:00 +0000 Subject: [PATCH 06/16] Assignments now generate unique list of exams for each user --- src/dashboards/AssignmentCreator.tsx | 54 ++++++++++------------ src/interfaces/results.ts | 2 +- src/pages/api/assignments/index.ts | 69 ++++++++++++++++++++++++++-- 3 files changed, 91 insertions(+), 34 deletions(-) diff --git a/src/dashboards/AssignmentCreator.tsx b/src/dashboards/AssignmentCreator.tsx index 08b29b90..e55faa60 100644 --- a/src/dashboards/AssignmentCreator.tsx +++ b/src/dashboards/AssignmentCreator.tsx @@ -46,36 +46,32 @@ export default function AssignmentCreator({isCreating, assignment, assigner, gro }; const createAssignment = () => { - setIsLoading(true); + setIsLoading(true); - const examPromises = selectedModules.map(async (module) => getExam(module, false)); - Promise.all(examPromises) - .then((exams) => { - (assignment ? axios.patch : axios.post)(`/api/assignments${assignment ? `/${assignment.id}` : ""}`, { - assigner, - assignees, - name, - startDate, - endDate, - results: [], - exams: exams.map((e) => ({module: e?.module, id: e?.id})), - }) - .then(() => { - toast.success(`The assignment "${name}" has been ${assignment ? "updated" : "created"} successfully!`); - cancelCreation(); - }) - .catch((e) => { - console.log(e); - toast.error("Something went wrong, please try again later!"); - }) - .finally(() => setIsLoading(false)); - }) - .catch((e) => { - console.log(e); - toast.error("Something went wrong, please try again later!"); - setIsLoading(false); - }); - }; + (assignment ? axios.patch : axios.post)( + `/api/assignments${assignment ? `/${assignment.id}` : ""}`, + { + assignees, + name, + startDate, + endDate, + selectedModules + } + ) + .then(() => { + toast.success( + `The assignment "${name}" has been ${ + assignment ? "updated" : "created" + } successfully!` + ); + cancelCreation(); + }) + .catch((e) => { + console.log(e); + toast.error("Something went wrong, please try again later!"); + }) + .finally(() => setIsLoading(false)); + }; const deleteAssignment = () => { if (assignment) { diff --git a/src/interfaces/results.ts b/src/interfaces/results.ts index 1acadec3..b3e6d9e3 100644 --- a/src/interfaces/results.ts +++ b/src/interfaces/results.ts @@ -19,7 +19,7 @@ export interface Assignment { type: "academic" | "general"; stats: Stat[]; }[]; - exams: {id: string; module: Module}[]; + exams: {id: string; module: Module, assignee: string}[]; startDate: Date; endDate: Date; } diff --git a/src/pages/api/assignments/index.ts b/src/pages/api/assignments/index.ts index eb59649e..37ee47a1 100644 --- a/src/pages/api/assignments/index.ts +++ b/src/pages/api/assignments/index.ts @@ -5,6 +5,10 @@ import {getFirestore, collection, getDocs, query, where, setDoc, doc} from "fire import {withIronSessionApiRoute} from "iron-session/next"; import {sessionOptions} from "@/lib/session"; import {uuidv4} from "@firebase/util"; +import { Module } from "@/interfaces"; +import { getExams } from "@/utils/exams.be"; +import { Exam } from "@/interfaces/exam"; +import { flatten } from "lodash"; const db = getFirestore(app); @@ -34,8 +38,65 @@ async function GET(req: NextApiRequest, res: NextApiResponse) { res.status(200).json(docs); } -async function POST(req: NextApiRequest, res: NextApiResponse) { - await setDoc(doc(db, "assignments", uuidv4()), {assigner: req.session.user?.id, ...req.body}); - - res.status(200).json({ok: true}); +interface ExamWithUser { + module: Module; + id: string; + assignee: string; +} + +function getRandomIndex(arr: any[]): number { + const randomIndex = Math.floor(Math.random() * arr.length); + return randomIndex; +} + +async function POST(req: NextApiRequest, res: NextApiResponse) { + const { selectedModules, assignees, ...body } = req.body as { + selectedModules: Module[]; + assignees: string[]; + }; + + // for optimization purposes, it would be better to create a new endpoint that returned the answers for all users at once + const allExams = await assignees.map(async (assignee) => { + const selectedModulePromises = await selectedModules.map( + async (module: Module) => { + try { + const exams: Exam[] = await getExams(db, module, "true", assignee); + + const exam = exams[getRandomIndex(exams)]; + if (exam) { + return { module: exam.module, id: exam.id, assignee }; + } + return null; + } catch (e) { + console.error(e); + return null; + } + }, + [] + ); + const newModules = await Promise.all(selectedModulePromises); + + return newModules; + }, []); + + const exams = flatten(await Promise.all(allExams)).filter( + (x) => x !== null + ) as ExamWithUser[]; + + if (exams.length === 0) { + res + .status(400) + .json({ ok: false, error: "No exams found for the selected modules" }); + return; + } + + await setDoc(doc(db, "assignments", uuidv4()), { + assigner: req.session.user?.id, + assignees, + results: [], + exams, + ...body, + }); + + res.status(200).json({ ok: true }); } From f48885bba66eeffe6060e974a691cc484948098b Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Thu, 7 Dec 2023 18:23:44 +0000 Subject: [PATCH 07/16] Updatd UI to display the unique tests for each user in an assignment --- src/dashboards/Student.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dashboards/Student.tsx b/src/dashboards/Student.tsx index d93a0780..ec67cff7 100644 --- a/src/dashboards/Student.tsx +++ b/src/dashboards/Student.tsx @@ -38,7 +38,7 @@ export default function StudentDashboard({user}: Props) { const setAssignment = useExamStore((state) => state.setAssignment); const startAssignment = (assignment: Assignment) => { - const examPromises = assignment.exams.map((e) => getExamById(e.module, e.id)); + const examPromises = assignment.exams.filter((e) => e.assignee === user.id).map((e) => getExamById(e.module, e.id)); Promise.all(examPromises).then((exams) => { if (exams.every((x) => !!x)) { @@ -121,6 +121,7 @@ export default function StudentDashboard({user}: Props) {
{assignment.exams + .filter((e) => e.assignee === user.id) .map((e) => e.module) .sort(sortByModuleName) .map((module) => ( From 0049ab272b7f30e7ac43a5fb3112181d4fefa762 Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Thu, 7 Dec 2023 23:07:35 +0000 Subject: [PATCH 08/16] Added dynamic generation of exams as an option --- src/dashboards/AssignmentCreator.tsx | 11 ++- src/pages/api/assignments/index.ts | 100 +++++++++++++++++++-------- src/utils/exams.be.ts | 2 +- 3 files changed, 82 insertions(+), 31 deletions(-) diff --git a/src/dashboards/AssignmentCreator.tsx b/src/dashboards/AssignmentCreator.tsx index e55faa60..fe1b9c68 100644 --- a/src/dashboards/AssignmentCreator.tsx +++ b/src/dashboards/AssignmentCreator.tsx @@ -18,6 +18,7 @@ import {getExam} from "@/utils/exams"; import {toast} from "react-toastify"; import {uuidv4} from "@firebase/util"; import {Assignment} from "@/interfaces/results"; +import Checkbox from "@/components/Low/Checkbox"; interface Props { isCreating: boolean; @@ -35,6 +36,8 @@ export default function AssignmentCreator({isCreating, assignment, assigner, gro const [isLoading, setIsLoading] = useState(false); const [startDate, setStartDate] = useState(assignment ? moment(assignment.startDate).toDate() : moment().add(1, "day").toDate()); const [endDate, setEndDate] = useState(assignment ? moment(assignment.endDate).toDate() : moment().add(8, "day").toDate()); + // creates a new exam for each assignee or just one exam for all assignees + const [generateMultiple, setGenerateMultiple] = useState(false); const toggleModule = (module: Module) => { const modules = selectedModules.filter((x) => x !== module); @@ -55,7 +58,8 @@ export default function AssignmentCreator({isCreating, assignment, assigner, gro name, startDate, endDate, - selectedModules + selectedModules, + generateMultiple, } ) .then(() => { @@ -280,6 +284,11 @@ export default function AssignmentCreator({isCreating, assignment, assigner, gro ))}
+
+ setGenerateMultiple(d => !d)}> + Generate an unique exam for each student + +
- Teachers expiring in 1 month + Country Manager expiring in 1 month
{users .filter( @@ -341,7 +341,7 @@ export default function AdminDashboard({user}: Props) {
- Expired Teachers + Expired Country Manager
{users .filter( From fe32584ff952f5f39926e921a18df40d2400bbfd Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Thu, 7 Dec 2023 23:23:39 +0000 Subject: [PATCH 12/16] Add Inactive Country manager --- src/dashboards/Admin.tsx | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/dashboards/Admin.tsx b/src/dashboards/Admin.tsx index 6e1529cc..33410fd6 100644 --- a/src/dashboards/Admin.tsx +++ b/src/dashboards/Admin.tsx @@ -148,6 +148,26 @@ export default function AdminDashboard({user}: Props) { ); + const InactiveCountryManagerList = () => { + const filter = (x: User) => x.type === "agent" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); + + return ( + <> +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> + + Back +
+

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

+
+ + + + ); + } + const InactiveStudentsList = () => { const filter = (x: User) => x.type === "student" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); @@ -235,6 +255,16 @@ export default function AdminDashboard({user}: Props) { } color="rose" /> + setPage("inactiveCountryManagers")} + Icon={BsPerson} + label="Inactive Country Managers" + value={ + users.filter((x) => x.type === "agent" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate))) + .length + } + color="rose" + /> setPage("inactiveCorporate")} Icon={BsPerson} @@ -453,7 +483,9 @@ export default function AdminDashboard({user}: Props) { {page === "agents" && } {page === "inactiveStudents" && } {page === "inactiveCorporate" && } + {page === "inactiveCountryManagers" && } {page === "" && } + ); } From ec56a5426b38524961673aec9f30f0e4c789c778 Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Thu, 7 Dec 2023 23:31:16 +0000 Subject: [PATCH 13/16] Added Inactive Referred corporate --- src/dashboards/Agent.tsx | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/dashboards/Agent.tsx b/src/dashboards/Agent.tsx index 4c4cd21e..38183407 100644 --- a/src/dashboards/Agent.tsx +++ b/src/dashboards/Agent.tsx @@ -41,6 +41,7 @@ export default function AgentDashboard({user}: Props) { const corporateFilter = (user: User) => user.type === "corporate"; const referredCorporateFilter = (x: User) => x.type === "corporate" && !!x.corporateInformation && x.corporateInformation.referralAgent === user.id; + const inactiveReferredCorporateFilter = (x: User) => referredCorporateFilter(x) && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); const UserDisplay = (displayUser: User) => (
{ - const filter = (x: User) => x.type === "corporate" && !!x.corporateInformation && x.corporateInformation.referralAgent === user.id; - return ( <>
@@ -70,10 +69,28 @@ export default function AgentDashboard({user}: Props) { Back
-

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

+

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

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

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

+
+ + ); }; @@ -108,6 +125,13 @@ export default function AgentDashboard({user}: Props) { value={users.filter(referredCorporateFilter).length} color="purple" /> + setPage("inactiveReferredCorporate")} + Icon={BsPersonFill} + label="Inactive Referred Corporate" + value={users.filter(inactiveReferredCorporateFilter).length} + color="rose" + /> setPage("corporate")} Icon={BsBank} @@ -168,6 +192,7 @@ export default function AgentDashboard({user}: Props) { {page === "referredCorporate" && } {page === "corporate" && } + {page === "inactiveReferredCorporate" && } {page === "" && } ); From 26c4368f31d99fd46b640464a656eb7bfaeabc5e Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Thu, 7 Dec 2023 23:34:31 +0000 Subject: [PATCH 14/16] Minor improvement on reusability of filter function --- src/dashboards/Admin.tsx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/dashboards/Admin.tsx b/src/dashboards/Admin.tsx index 33410fd6..49b9c654 100644 --- a/src/dashboards/Admin.tsx +++ b/src/dashboards/Admin.tsx @@ -42,6 +42,8 @@ export default function AdminDashboard({user}: Props) { setShowModal(!!selectedUser && page === ""); }, [selectedUser, page]); + const inactiveCountryManagerFilter = (x: User) => x.type === "agent" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); + const UserDisplay = (displayUser: User) => (
setSelectedUser(displayUser)} @@ -149,8 +151,6 @@ export default function AdminDashboard({user}: Props) { ); const InactiveCountryManagerList = () => { - const filter = (x: User) => x.type === "agent" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); - return ( <>
@@ -160,10 +160,10 @@ export default function AdminDashboard({user}: Props) { Back
-

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

+

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

- + ); } @@ -259,10 +259,7 @@ export default function AdminDashboard({user}: Props) { onClick={() => setPage("inactiveCountryManagers")} Icon={BsPerson} label="Inactive Country Managers" - value={ - users.filter((x) => x.type === "agent" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate))) - .length - } + value={users.filter(inactiveCountryManagerFilter).length} color="rose" /> Date: Thu, 7 Dec 2023 23:42:04 +0000 Subject: [PATCH 15/16] Added Referenced corporate expiring in 1 month --- src/dashboards/Agent.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/dashboards/Agent.tsx b/src/dashboards/Agent.tsx index 38183407..0ed93eea 100644 --- a/src/dashboards/Agent.tsx +++ b/src/dashboards/Agent.tsx @@ -164,6 +164,21 @@ export default function AgentDashboard({user}: Props) { ))}
+
+ Referenced corporate expiring in 1 month +
+ {users + .filter( + (x) => + referredCorporateFilter(x) && + moment().isAfter(moment(x.subscriptionExpirationDate).subtract(30, "days")) && + moment().isBefore(moment(x.subscriptionExpirationDate)), + ) + .map((x) => ( + + ))} +
+
); From dfbbf0456da9e3be45b6276d2cba078b71067986 Mon Sep 17 00:00:00 2001 From: Joao Ramos Date: Fri, 8 Dec 2023 14:55:16 +0000 Subject: [PATCH 16/16] Revert "Changed Comercial labels to Corporate" This reverts commit 9c8d7988c5743c8af4d86df7e43348eaba65f7d0. --- src/components/DemographicInformationInput.tsx | 8 ++++---- src/components/UserCard.tsx | 10 +++++----- src/pages/profile.tsx | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/DemographicInformationInput.tsx b/src/components/DemographicInformationInput.tsx index 1f90ff21..222dc546 100644 --- a/src/components/DemographicInformationInput.tsx +++ b/src/components/DemographicInformationInput.tsx @@ -24,7 +24,7 @@ export default function DemographicInformationInput({user, mutateUser}: Props) { const [position, setPosition] = useState(); const [isLoading, setIsLoading] = useState(false); - const [corporateName, setCorporateName] = useState(); + const [companyName, setCompanyName] = useState(); const [commercialRegistration, setCommercialRegistration] = useState(); const save = (e?: FormEvent) => { @@ -40,7 +40,7 @@ export default function DemographicInformationInput({user, mutateUser}: Props) { employment: user.type === "corporate" ? undefined : employment, position: user.type === "corporate" ? position : undefined, }, - agentInformation: user.type === "agent" ? {corporateName, commercialRegistration} : undefined, + agentInformation: user.type === "agent" ? {companyName, commercialRegistration} : undefined, }) .then((response) => mutateUser((response.data as {user: User}).user)) .catch(() => { @@ -62,7 +62,7 @@ export default function DemographicInformationInput({user, mutateUser}: Props) { {user.type === "agent" && (
- + {!isLoading && "Save information"} {isLoading && ( diff --git a/src/components/UserCard.tsx b/src/components/UserCard.tsx index f81302ac..682b32d8 100644 --- a/src/components/UserCard.tsx +++ b/src/components/UserCard.tsx @@ -146,11 +146,11 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers, <>
@@ -159,7 +159,7 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers, type="text" name="commercialRegistration" onChange={setCommercialRegistration} - placeholder="Enter commercial registration" + placeholder="Enter company name" defaultValue={commercialRegistration} required /> @@ -171,11 +171,11 @@ const UserCard = ({user, loggedInUser, onClose, onViewStudents, onViewTeachers, <>
null} - placeholder="Enter corporate name" + placeholder="Enter company name" defaultValue={user.agentInformation.companyName} disabled /> @@ -227,7 +227,7 @@ export default function Home() { type="text" name="commercialRegistration" onChange={() => null} - placeholder="Enter commercial registration" + placeholder="Enter company name" defaultValue={user.agentInformation.commercialRegistration} disabled />