diff --git a/src/pages/(admin)/Lists/GroupList.tsx b/src/pages/(admin)/Lists/GroupList.tsx index a0c017ca..f3a02401 100644 --- a/src/pages/(admin)/Lists/GroupList.tsx +++ b/src/pages/(admin)/Lists/GroupList.tsx @@ -1,301 +1,387 @@ import Button from "@/components/Low/Button"; -import Checkbox from "@/components/Low/Checkbox"; import Input from "@/components/Low/Input"; +import Modal from "@/components/Modal"; import useGroups from "@/hooks/useGroups"; import useUsers from "@/hooks/useUsers"; -import {Module} from "@/interfaces"; -import {Group, User} from "@/interfaces/user"; -import {Disclosure, Transition} from "@headlessui/react"; -import {createColumnHelper, flexRender, getCoreRowModel, useReactTable} from "@tanstack/react-table"; +import { Group, User } from "@/interfaces/user"; +import { + createColumnHelper, + flexRender, + getCoreRowModel, + useReactTable, +} from "@tanstack/react-table"; import axios from "axios"; -import clsx from "clsx"; -import {capitalize, uniq, uniqBy} from "lodash"; -import {useEffect, useRef, useState} from "react"; -import {BsCheck, BsDash, BsPencil, BsPlus, BsQuestionCircleFill, BsTrash} from "react-icons/bs"; -import {toast} from "react-toastify"; +import { capitalize, uniq } from "lodash"; +import { useEffect, useState } from "react"; +import { BsPencil, BsQuestionCircleFill, BsTrash } from "react-icons/bs"; import Select from "react-select"; -import {uuidv4} from "@firebase/util"; -import {useFilePicker} from "use-file-picker"; -import Modal from "@/components/Modal"; +import { toast } from "react-toastify"; import readXlsxFile from "read-excel-file"; +import { useFilePicker } from "use-file-picker"; const columnHelper = createColumnHelper(); -const EMAIL_REGEX = new RegExp(/^[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*@[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*$/); +const EMAIL_REGEX = new RegExp( + /^[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*@[a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*$/, +); interface CreateDialogProps { - user: User; - users: User[]; - group?: Group; - onClose: () => void; + user: User; + users: User[]; + group?: Group; + onClose: () => void; } -const CreatePanel = ({user, users, group, onClose}: CreateDialogProps) => { - const [name, setName] = useState(group?.name || undefined); - const [admin, setAdmin] = useState(group?.admin || user.id); - const [participants, setParticipants] = useState(group?.participants || []); - const {openFilePicker, filesContent, clear} = useFilePicker({ - accept: ".xlsx", - multiple: false, - readAs: "ArrayBuffer", - }); +const CreatePanel = ({ user, users, group, onClose }: CreateDialogProps) => { + const [name, setName] = useState( + group?.name || undefined, + ); + const [admin, setAdmin] = useState(group?.admin || user.id); + const [participants, setParticipants] = useState( + group?.participants || [], + ); + const { openFilePicker, filesContent, clear } = useFilePicker({ + accept: ".xlsx", + multiple: false, + readAs: "ArrayBuffer", + }); - useEffect(() => { - if (filesContent.length > 0) { - const file = filesContent[0]; - readXlsxFile(file.content).then((rows) => { - const emails = uniq( - rows - .map((row) => { - const [email] = row as string[]; - return EMAIL_REGEX.test(email) && !users.map((u) => u.email).includes(email) ? email.toString().trim() : undefined; - }) - .filter((x) => !!x), - ); + useEffect(() => { + if (filesContent.length > 0) { + const file = filesContent[0]; + readXlsxFile(file.content).then((rows) => { + const emails = uniq( + rows + .map((row) => { + const [email] = row as string[]; + return EMAIL_REGEX.test(email) && + !users.map((u) => u.email).includes(email) + ? email.toString().trim() + : undefined; + }) + .filter((x) => !!x), + ); - if (emails.length === 0) { - toast.error("Please upload an Excel file containing e-mails!"); - clear(); - return; - } + if (emails.length === 0) { + toast.error("Please upload an Excel file containing e-mails!"); + clear(); + return; + } - const emailUsers = [...new Set(emails)].map((x) => users.find((y) => y.email.toLowerCase() === x)).filter((x) => x !== undefined); - const filteredUsers = emailUsers.filter( - (x) => - ((user.type === "developer" || user.type === "admin" || user.type === "corporate") && - (x?.type === "student" || x?.type === "teacher")) || - (user.type === "teacher" && x?.type === "student"), - ); + const emailUsers = [...new Set(emails)] + .map((x) => users.find((y) => y.email.toLowerCase() === x)) + .filter((x) => x !== undefined); + const filteredUsers = emailUsers.filter( + (x) => + ((user.type === "developer" || + user.type === "admin" || + user.type === "corporate") && + (x?.type === "student" || x?.type === "teacher")) || + (user.type === "teacher" && x?.type === "student"), + ); - setParticipants(filteredUsers.filter((x) => !!x).map((x) => x!.id)); - toast.success( - user.type !== "teacher" - ? "Added all teachers and students found in the file you've provided!" - : "Added all students found in the file you've provided!", - {toastId: "upload-success"}, - ); - }); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [filesContent, user.type, users]); + setParticipants(filteredUsers.filter((x) => !!x).map((x) => x!.id)); + toast.success( + user.type !== "teacher" + ? "Added all teachers and students found in the file you've provided!" + : "Added all students found in the file you've provided!", + { toastId: "upload-success" }, + ); + }); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [filesContent, user.type, users]); - const submit = () => { - if (name !== group?.name && (name === "Students" || name === "Teachers")) { - toast.error("That group name is reserved and cannot be used, please enter another one."); - return; - } + const submit = () => { + if (name !== group?.name && (name === "Students" || name === "Teachers")) { + toast.error( + "That group name is reserved and cannot be used, please enter another one.", + ); + return; + } - (group ? axios.patch : axios.post)(group ? `/api/groups/${group.id}` : "/api/groups", {name, admin, participants}) - .then(() => { - toast.success(`Group "${name}" ${group ? "edited" : "created"} successfully`); - return true; - }) - .catch(() => { - toast.error("Something went wrong, please try again later!"); - return false; - }) - .finally(onClose); - }; + (group ? axios.patch : axios.post)( + group ? `/api/groups/${group.id}` : "/api/groups", + { name, admin, participants }, + ) + .then(() => { + toast.success( + `Group "${name}" ${group ? "edited" : "created"} successfully`, + ); + return true; + }) + .catch(() => { + toast.error("Something went wrong, please try again later!"); + return false; + }) + .finally(onClose); + }; - return ( -
-
- -
-
- -
- -
-
-
- +
+
+ +
+ +
+
+
+