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 { checkAccess } from "@/utils/permissions"; import axios from "axios"; import clsx from "clsx"; import { Dispatch, memo, SetStateAction, useCallback, useEffect, useState, } from "react"; import { BsPlusCircle, BsTrash } from "react-icons/bs"; import { toast } from "react-toastify"; const areStepsOverlapped = (steps: Step[]) => { for (let i = 0; i < steps.length; i++) { if (i === 0) continue; const step = steps[i]; const previous = steps[i - 1]; if (previous.max >= step.min) return true; } return false; }; interface RowProps { min: number; max: number; index: number; label: string; isLast: boolean; isLoading: boolean; setSteps: Dispatch>; addRow: (index: number) => void; } function GradingRow({ min, max, label, index, isLoading, isLast, setSteps, addRow, }: RowProps) { const onChangeMin = useCallback( (e: string) => { setSteps((prev) => prev.map((x, i) => (i === index ? { ...x, min: parseInt(e) } : x)) ); }, [index, setSteps] ); const onChangeMax = useCallback( (e: string) => { setSteps((prev) => prev.map((x, i) => (i === index ? { ...x, max: parseInt(e) } : x)) ); }, [index, setSteps] ); const onChangeLabel = useCallback( (e: string) => { setSteps((prev) => prev.map((x, i) => (i === index ? { ...x, label: e } : x)) ); }, [index, setSteps] ); const onAddRow = useCallback(() => addRow(index), [addRow, index]); const removeRow = useCallback( () => setSteps((prev) => prev.filter((_, i) => i !== index)), [index, setSteps] ); return ( <>
{index !== 0 && !isLast && ( )}
{!isLast && ( )} ); } const GradingRowMemo = memo(GradingRow); interface Props { user: User; entitiesGrading: Grading[]; entities: Entity[]; mutate: () => void; } export default function CorporateGradingSystem({ user, entitiesGrading = [], entities = [], mutate, }: Props) { const [entity, setEntity] = useState(entitiesGrading[0]?.entity || undefined); const [isLoading, setIsLoading] = useState(false); const [steps, setSteps] = useState([]); const [otherEntities, setOtherEntities] = useState([]); useEffect(() => { if (entity) { const entitySteps = entitiesGrading.find( (e) => e.entity === entity )!.steps; setSteps(entitySteps || []); } }, [entitiesGrading, entity]); const saveGradingSystem = () => { 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."); setIsLoading(true); axios .post("/api/grading", { user: user.id, entity, 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)); }; 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)); }; const addRow = useCallback((index: number) => { setSteps((prev) => { const item = { min: prev[index === 0 ? 0 : index - 1].max + 1, max: prev[index + 1].min - 1, label: "", }; return [ ...prev.slice(0, index + 1), item, ...prev.slice(index + 1, prev.length), ]; }); }, []); return (
({ value: e.id, label: e.label }))} onChange={(e) => !e ? setOtherEntities([]) : setOtherEntities(e.map((o) => o.value!)) } isMulti /> )}
{steps.map((step, index) => ( ))}
); }