ENCOA-275

This commit is contained in:
Tiago Ribeiro
2024-12-13 15:13:27 +00:00
parent 61d1bbbe13
commit f3057c675f
4 changed files with 109 additions and 10 deletions

View File

@@ -1,13 +1,16 @@
import Button from "@/components/Low/Button";
import Input from "@/components/Low/Input";
import Select from "@/components/Low/Select";
import Separator from "@/components/Low/Separator";
import { Grading, Step } from "@/interfaces";
import { Entity } from "@/interfaces/entity";
import { User } from "@/interfaces/user";
import { CEFR_STEPS, GENERAL_STEPS, IELTS_STEPS, TOFEL_STEPS } from "@/resources/grading";
import { mapBy } from "@/utils";
import { checkAccess } from "@/utils/permissions";
import axios from "axios";
import clsx from "clsx";
import { Divider } from "primereact/divider";
import { useEffect, useState } from "react";
import { BsPlusCircle, BsTrash } from "react-icons/bs";
import { toast } from "react-toastify";
@@ -36,6 +39,7 @@ export default function CorporateGradingSystem({ user, entitiesGrading = [], ent
const [entity, setEntity] = useState(entitiesGrading[0]?.entity || undefined)
const [isLoading, setIsLoading] = useState(false);
const [steps, setSteps] = useState<Step[]>([]);
const [otherEntities, setOtherEntities] = useState<string[]>([])
useEffect(() => {
if (entity) {
@@ -63,6 +67,27 @@ export default function CorporateGradingSystem({ user, entitiesGrading = [], ent
.finally(() => setIsLoading(false));
};
const applyToOtherEntities = () => {
if (!steps.every((x) => x.min < x.max)) return toast.error("One of your steps has a minimum threshold inferior to its superior threshold.");
if (areStepsOverlapped(steps)) return toast.error("There seems to be an overlap in one of your steps.");
if (
steps.reduce((acc, curr) => {
return acc - (curr.max - curr.min + 1);
}, 100) > 0
)
return toast.error("There seems to be an open interval in your steps.");
if (otherEntities.length === 0) return toast.error("Select at least one entity")
setIsLoading(true);
axios
.post("/api/grading/multiple", { user: user.id, entities: otherEntities, steps })
.then(() => toast.success("Your grading system has been saved!"))
.then(mutate)
.catch(() => toast.error("Something went wrong, please try again later"))
.finally(() => setIsLoading(false));
};
return (
<div className="flex flex-col gap-4 border p-4 border-mti-gray-platinum rounded-xl">
<label className="font-normal text-base text-mti-gray-dim">Grading System</label>
@@ -76,6 +101,22 @@ export default function CorporateGradingSystem({ user, entitiesGrading = [], ent
/>
</div>
{entities.length > 1 && (
<>
<Separator />
<label className="font-normal text-base text-mti-gray-dim">Apply this grading system to other entities</label>
<Select
options={entities.map((e) => ({ value: e.id, label: e.label }))}
onChange={(e) => !e ? setOtherEntities([]) : setOtherEntities(e.map(o => o.value!))}
isMulti
/>
<Button onClick={applyToOtherEntities} isLoading={isLoading} disabled={isLoading || otherEntities.length === 0} variant="outline">
Apply to {otherEntities.length} other entities
</Button>
<Separator />
</>
)}
<label className="font-normal text-base text-mti-gray-dim">Preset Systems</label>
<div className="grid grid-cols-4 gap-4">
<Button variant="outline" onClick={() => setSteps(CEFR_STEPS)}>

View File

@@ -0,0 +1,48 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next";
import { app } from "@/firebase";
import { withIronSessionApiRoute } from "iron-session/next";
import { sessionOptions } from "@/lib/session";
import { CorporateUser, Group } from "@/interfaces/user";
import { Discount, Package } from "@/interfaces/paypal";
import { v4 } from "uuid";
import { checkAccess } from "@/utils/permissions";
import { CEFR_STEPS } from "@/resources/grading";
import { getCorporateUser } from "@/resources/user";
import { getUserCorporate } from "@/utils/groups.be";
import { Grading, Step } from "@/interfaces";
import { getGroupsForUser } from "@/utils/groups.be";
import { uniq } from "lodash";
import { getSpecificUsers, getUser } from "@/utils/users.be";
import client from "@/lib/mongodb";
import { getGradingSystemByEntity } from "@/utils/grading.be";
const db = client.db(process.env.MONGODB_DB);
export default withIronSessionApiRoute(handler, sessionOptions);
async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "POST") await post(req, res);
}
async function post(req: NextApiRequest, res: NextApiResponse) {
if (!req.session.user) {
res.status(401).json({ ok: false });
return;
}
if (!checkAccess(req.session.user, ["admin", "developer", "mastercorporate", "corporate"]))
return res.status(403).json({
ok: false,
reason: "You do not have permission to create a new grading system",
});
const body = req.body as {
entities: string[]
steps: Step[];
};
await db.collection("grading").updateMany({ entity: { $in: body.entities } }, { $set: { steps: body.steps } }, { upsert: true });
res.status(200).json({ ok: true });
}

View File

@@ -149,7 +149,7 @@ export default function Dashboard({
<IconCard Icon={BsPersonFillGear}
onClick={() => router.push("/users/performance")}
label="Student Performance"
value={students.length}
value={usersCount.student}
color="purple"
/>
<IconCard