import Input from "@/components/Low/Input"; import Modal from "@/components/Modal"; import { Module } from "@/interfaces"; import clsx from "clsx"; import { useEffect, useState } from "react"; import { BsBook, BsCheckCircle, BsClipboard, BsHeadphones, BsMegaphone, BsPen, BsXCircle, } from "react-icons/bs"; import { generate } from "random-words"; import { capitalize } from "lodash"; import useUsers from "@/hooks/useUsers"; import { Group, User } from "@/interfaces/user"; import ProgressBar from "@/components/Low/ProgressBar"; import { calculateAverageLevel } from "@/utils/score"; import Button from "@/components/Low/Button"; import ReactDatePicker from "react-datepicker"; import moment from "moment"; import axios from "axios"; import { getExam } from "@/utils/exams"; import { toast } from "react-toastify"; import { Assignment } from "@/interfaces/results"; import Checkbox from "@/components/Low/Checkbox"; import { InstructorGender, Variant } from "@/interfaces/exam"; import Select from "@/components/Low/Select"; import useExams from "@/hooks/useExams"; interface Props { isCreating: boolean; assigner: string; users: User[]; groups: Group[]; assignment?: Assignment; cancelCreation: () => void; } export default function AssignmentCreator({ isCreating, assignment, assigner, groups, users, cancelCreation, }: Props) { const [selectedModules, setSelectedModules] = useState( assignment?.exams.map((e) => e.module) || [] ); const [assignees, setAssignees] = useState( assignment?.assignees || [] ); const [name, setName] = useState( assignment?.name || generate({ minLength: 6, maxLength: 8, min: 2, max: 3, join: " ", formatter: capitalize, }) ); const [isLoading, setIsLoading] = useState(false); const [startDate, setStartDate] = useState( assignment ? moment(assignment.startDate).toDate() : new Date() ); const [endDate, setEndDate] = useState( assignment ? moment(assignment.endDate).toDate() : moment().hours(23).minutes(59).add(8, "day").toDate() ); const [variant, setVariant] = useState("full"); const [instructorGender, setInstructorGender] = useState( assignment?.instructorGender || "varied" ); // creates a new exam for each assignee or just one exam for all assignees const [generateMultiple, setGenerateMultiple] = useState(false); const [useRandomExams, setUseRandomExams] = useState(true); const [examIDs, setExamIDs] = useState<{ id: string; module: Module }[]>([]); const { exams } = useExams(); useEffect(() => { setExamIDs((prev) => prev.filter((x) => selectedModules.includes(x.module)) ); }, [selectedModules]); const toggleModule = (module: Module) => { const modules = selectedModules.filter((x) => x !== module); setSelectedModules((prev) => prev.includes(module) ? modules : [...modules, module] ); }; const toggleAssignee = (user: User) => { setAssignees((prev) => prev.includes(user.id) ? prev.filter((a) => a !== user.id) : [...prev, user.id] ); }; const createAssignment = () => { setIsLoading(true); (assignment ? axios.patch : axios.post)( `/api/assignments${assignment ? `/${assignment.id}` : ""}`, { assignees, name, startDate, examIDs: !useRandomExams ? examIDs : undefined, endDate, selectedModules, generateMultiple, variant, instructorGender, } ) .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) { setIsLoading(true); if ( !confirm( `Are you sure you want to delete the "${assignment.name}" assignment?` ) ) return; axios .delete(`api/assignments/${assignment.id}`) .then(() => { toast.success( `The assignment "${name}" has been deleted successfully!` ); cancelCreation(); }) .catch((e) => { console.log(e); toast.error("Something went wrong, please try again later!"); }) .finally(() => setIsLoading(false)); } }; const startAssignment = () => { if (assignment) { setIsLoading(true); axios .post(`/api/assignments/${assignment.id}/start`) .then(() => { toast.success( `The assignment "${name}" has been started successfully!` ); cancelCreation(); }) .catch((e) => { console.log(e); toast.error("Something went wrong, please try again later!"); }) .finally(() => setIsLoading(false)); } } return (
toggleModule("reading") : undefined } className={clsx( "w-52 relative max-w-xs flex items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-8 cursor-pointer", "lg:col-span-2", selectedModules.includes("reading") ? "border-mti-purple-light" : "border-mti-gray-platinum" )} >
Reading {!selectedModules.includes("reading") && !selectedModules.includes("level") && (
)} {selectedModules.includes("level") && ( )} {selectedModules.includes("reading") && ( )}
toggleModule("listening") : undefined } className={clsx( "w-52 relative max-w-xs flex items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-8 cursor-pointer", "lg:col-span-2", selectedModules.includes("listening") ? "border-mti-purple-light" : "border-mti-gray-platinum" )} >
Listening {!selectedModules.includes("listening") && !selectedModules.includes("level") && (
)} {selectedModules.includes("level") && ( )} {selectedModules.includes("listening") && ( )}
toggleModule("writing") : undefined } className={clsx( "w-52 relative max-w-xs flex items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-8 cursor-pointer", "lg:col-span-2", selectedModules.includes("writing") ? "border-mti-purple-light" : "border-mti-gray-platinum" )} >
Writing {!selectedModules.includes("writing") && !selectedModules.includes("level") && (
)} {selectedModules.includes("level") && ( )} {selectedModules.includes("writing") && ( )}
toggleModule("speaking") : undefined } className={clsx( "w-52 relative max-w-xs flex items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-8 cursor-pointer", "lg:col-span-3", selectedModules.includes("speaking") ? "border-mti-purple-light" : "border-mti-gray-platinum" )} >
Speaking {!selectedModules.includes("speaking") && !selectedModules.includes("level") && (
)} {selectedModules.includes("level") && ( )} {selectedModules.includes("speaking") && ( )}
toggleModule("level") : undefined } className={clsx( "w-52 relative max-w-xs flex items-center bg-mti-white-alt transition duration-300 ease-in-out border p-5 rounded-xl gap-8 cursor-pointer", "lg:col-span-3", selectedModules.includes("level") ? "border-mti-purple-light" : "border-mti-gray-platinum" )} >
Level {!selectedModules.includes("level") && selectedModules.length === 0 && (
)} {!selectedModules.includes("level") && selectedModules.length > 0 && ( )} {selectedModules.includes("level") && ( )}
setName(e)} defaultValue={name} label="Assignment Name" required />
moment(date).isSameOrAfter(new Date())} dateFormat="dd/MM/yyyy HH:mm" selected={startDate} showTimeSelect onChange={(date) => setStartDate(date)} />
moment(date).isAfter(startDate)} dateFormat="dd/MM/yyyy HH:mm" selected={endDate} showTimeSelect onChange={(date) => setEndDate(date)} />
{selectedModules.includes("speaking") && (
e.module === module)?.id || null, label: examIDs.find((e) => e.module === module)?.id || "", }} onChange={(value) => value ? setExamIDs((prev) => [ ...prev.filter((x) => x.module !== module), { id: value.value!, module }, ]) : setExamIDs((prev) => prev.filter((x) => x.module !== module) ) } options={exams .filter((x) => !x.isDiagnostic && x.module === module) .map((x) => ({ value: x.id, label: x.id }))} />
))}
)} )}
Assignees ({assignees.length} selected)
{groups.map((g) => ( ))}
{users.map((user) => (
toggleAssignee(user)} className={clsx( "p-4 flex flex-col gap-2 rounded-xl border cursor-pointer w-72", "transition ease-in-out duration-300", assignees.includes(user.id) ? "border-mti-purple" : "border-mti-gray-platinum" )} key={user.id} > {user.name} {user.email} Groups:{" "} {groups .filter((g) => g.participants.includes(user.id)) .map((g) => g.name) .join(", ")}
))}
setVariant((prev) => (prev === "full" ? "partial" : "full")) } > Full length exams setGenerateMultiple((d) => !d)} > Generate different exams
{assignment && ( <> )}
); }