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 diff --git a/src/components/DemographicInformationInput.tsx b/src/components/DemographicInformationInput.tsx index 222dc546..2468178e 100644 --- a/src/components/DemographicInformationInput.tsx +++ b/src/components/DemographicInformationInput.tsx @@ -62,7 +62,7 @@ export default function DemographicInformationInput({user, mutateUser}: Props) {
{user.type === "agent" && (
- +
@@ -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, <>
x.type === "agent" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); + const UserDisplay = (displayUser: User) => (
setSelectedUser(displayUser)} @@ -149,6 +150,24 @@ export default function AdminDashboard({user}: Props) { ); + const InactiveCountryManagerList = () => { + return ( + <> +
+
setPage("")} + className="flex gap-2 items-center text-mti-purple-light cursor-pointer hover:text-mti-purple-dark transition ease-in-out duration-300"> + + Back +
+

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

+
+ + + + ); + } + const InactiveStudentsList = () => { const filter = (x: User) => x.type === "student" && (x.status === "disabled" || moment().isAfter(x.subscriptionExpirationDate)); @@ -200,14 +219,14 @@ export default function AdminDashboard({user}: Props) { color="purple" /> x.type === "teacher").length} onClick={() => setPage("teachers")} color="purple" /> x.type === "corporate").length} onClick={() => setPage("corporate")} @@ -236,6 +255,13 @@ export default function AdminDashboard({user}: Props) { } color="rose" /> + setPage("inactiveCountryManagers")} + Icon={BsPerson} + label="Inactive Country Managers" + value={users.filter(inactiveCountryManagerFilter).length} + color="rose" + /> setPage("inactiveCorporate")} Icon={BsPerson} @@ -298,7 +324,7 @@ export default function AdminDashboard({user}: Props) {
- Teachers expiring in 1 month + Country Manager expiring in 1 month
{users .filter( @@ -342,7 +368,7 @@ export default function AdminDashboard({user}: Props) {
- Expired Teachers + Expired Country Manager
{users .filter( @@ -454,7 +480,9 @@ export default function AdminDashboard({user}: Props) { {page === "agents" && } {page === "inactiveStudents" && } {page === "inactiveCorporate" && } + {page === "inactiveCountryManagers" && } {page === "" && } + ); } diff --git a/src/dashboards/Agent.tsx b/src/dashboards/Agent.tsx index f951f04e..0ed93eea 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"; @@ -50,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 ( <>
@@ -79,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})

+
+ + ); }; @@ -118,8 +126,15 @@ export default function AgentDashboard({user}: Props) { color="purple" /> setPage("corporate")} + onClick={() => setPage("inactiveReferredCorporate")} Icon={BsPersonFill} + label="Inactive Referred Corporate" + value={users.filter(inactiveReferredCorporateFilter).length} + color="rose" + /> + setPage("corporate")} + Icon={BsBank} label="Corporate" value={users.filter(corporateFilter).length} color="purple" @@ -149,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) => ( + + ))} +
+
); @@ -177,6 +207,7 @@ export default function AgentDashboard({user}: Props) { {page === "referredCorporate" && } {page === "corporate" && } + {page === "inactiveReferredCorporate" && } {page === "" && } ); diff --git a/src/dashboards/AssignmentCreator.tsx b/src/dashboards/AssignmentCreator.tsx index 08b29b90..358f3721 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); @@ -46,36 +49,33 @@ 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, + generateMultiple, + } + ) + .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) { @@ -284,6 +284,11 @@ export default function AssignmentCreator({isCreating, assignment, assigner, gro ))}
+
+ setGenerateMultiple(d => !d)}> + Generate different exams + +