import Button from "@/components/Low/Button"; import Input from "@/components/Low/Input"; import Modal from "@/components/Modal"; import useGroups from "@/hooks/useGroups"; import useUsers from "@/hooks/useUsers"; import { Group, User } from "@/interfaces/user"; import { createColumnHelper, flexRender, getCoreRowModel, useReactTable, } from "@tanstack/react-table"; import axios from "axios"; import { capitalize, uniq } from "lodash"; import { useEffect, useState } from "react"; import { BsPencil, BsQuestionCircleFill, BsTrash } from "react-icons/bs"; import Select from "react-select"; 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]+)*$/, ); interface CreateDialogProps { 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", }); 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; } 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]); 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); }; return (