import {useMemo} from "react"; import {PERMISSIONS} from "@/constants/userPermissions"; import useExams from "@/hooks/useExams"; import useUsers from "@/hooks/useUsers"; import {Module} from "@/interfaces"; import {Exam} from "@/interfaces/exam"; import {Type, User} from "@/interfaces/user"; import useExamStore from "@/stores/examStore"; import {getExamById} from "@/utils/exams"; import {countExercises} from "@/utils/moduleUtils"; import {createColumnHelper, flexRender, getCoreRowModel, useReactTable} from "@tanstack/react-table"; import axios from "axios"; import clsx from "clsx"; import {capitalize} from "lodash"; import {useRouter} from "next/router"; import {BsCheck, BsTrash, BsUpload} from "react-icons/bs"; import {toast} from "react-toastify"; import {useListSearch} from "@/hooks/useListSearch"; const searchFields = [["module"], ["id"], ["createdBy"]]; const CLASSES: {[key in Module]: string} = { reading: "text-ielts-reading", listening: "text-ielts-listening", speaking: "text-ielts-speaking", writing: "text-ielts-writing", level: "text-ielts-level", }; const columnHelper = createColumnHelper(); export default function ExamList({user}: {user: User}) { const {exams, reload} = useExams(); const {users} = useUsers(); const parsedExams = useMemo(() => { return exams.map((exam) => { if (exam.createdBy) { const user = users.find((u) => u.id === exam.createdBy); if (!user) return exam; return { ...exam, createdBy: user.type === "developer" ? "system" : user.name, }; } return exam; }); }, [exams, users]); const {rows: filteredRows, renderSearch} = useListSearch(searchFields, parsedExams); const setExams = useExamStore((state) => state.setExams); const setSelectedModules = useExamStore((state) => state.setSelectedModules); const router = useRouter(); const loadExam = async (module: Module, examId: string) => { const exam = await getExamById(module, examId.trim()); if (!exam) { toast.error("Unknown Exam ID! Please make sure you selected the right module and entered the right exam ID", { toastId: "invalid-exam-id", }); return; } setExams([exam]); setSelectedModules([module]); router.push("/exercises"); }; const deleteExam = async (exam: Exam) => { if (!confirm(`Are you sure you want to delete this ${capitalize(exam.module)} exam?`)) return; axios .delete(`/api/exam/${exam.module}/${exam.id}`) .then(() => toast.success(`Deleted the "${exam.id}" exam`)) .catch((reason) => { if (reason.response.status === 404) { toast.error("Exam not found!"); return; } if (reason.response.status === 403) { toast.error("You do not have permission to delete this exam!"); return; } toast.error("Something went wrong, please try again later."); }) .finally(reload); }; const getTotalExercises = (exam: Exam) => { if (exam.module === "reading" || exam.module === "listening" || exam.module === "level") { return countExercises(exam.parts.flatMap((x) => x.exercises)); } return countExercises(exam.exercises); }; const defaultColumns = [ columnHelper.accessor("id", { header: "ID", cell: (info) => info.getValue(), }), columnHelper.accessor("module", { header: "Module", cell: (info) => {capitalize(info.getValue())}, }), columnHelper.accessor((x) => getTotalExercises(x), { header: "Exercises", cell: (info) => info.getValue(), }), columnHelper.accessor("minTimer", { header: "Timer", cell: (info) => <>{info.getValue()} minute(s), }), columnHelper.accessor("createdAt", { header: "Created At", cell: (info) => { const value = info.getValue(); if (value) { return new Date(value).toLocaleDateString(); } return null; }, }), columnHelper.accessor("createdBy", { header: "Created By", cell: (info) => info.getValue(), }), { header: "", id: "actions", cell: ({row}: {row: {original: Exam}}) => { return (
await loadExam(row.original.module, row.original.id)}>
{PERMISSIONS.examManagement.delete.includes(user.type) && (
deleteExam(row.original)}>
)}
); }, }, ]; const table = useReactTable({ data: filteredRows, columns: defaultColumns, getCoreRowModel: getCoreRowModel(), }); return (
{renderSearch()} {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( ))} ))} {table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( ))} ))}
{header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())}
{flexRender(cell.column.columnDef.cell, cell.getContext())}
); }