Untitled
plain_text
a month ago
34 kB
1
Indexable
Never
import React, { useState } from "react"; import { useRouter } from "next/router"; import { resetServerContext } from "react-beautiful-dnd"; import { format } from "date-fns"; import { MdEdit, MdPayment, MdDeleteForever } from "react-icons/md"; import { Backdrop, CircularProgress } from "@material-ui/core"; import { withAuth, Head, Dashboard, Alert, MaterialTable } from "../../../components"; import { useGetStudentsQuery } from "../../../state/services"; import { HookAutoComplete } from "mui-react-hook-form-plus"; import { Box, Button, Grid, Modal } from "@mui/material"; import { useSeatchList } from "../../../hooks/useSearchList"; import { useAddPaymentMutation, useDeleteStudentMutation } from "../../../state/services"; import withAdmin from "../../../components/WithAdmin"; import withPermissions from "../../../components/withPermissions"; import { useUser } from "../../../hooks/useUser"; import { AiOutlineClose } from "react-icons/ai"; import * as XLSX from "xlsx"; import { saveAs } from "file-saver"; import { FaFileExcel, FaTimes } from "react-icons/fa"; const defaultValues = { courseTitle: null as string | null, batch: null as string | null, isEnrolled: null as boolean | null, isValid: null as boolean | null, profession: null as boolean | null, }; type DefaultValues = typeof defaultValues; const Students = () => { const router = useRouter(); const { role } = useUser(); const [filterRef, setFilterRef] = React.useState<Partial<DefaultValues>>({}); const [studentId, setStudentId] = React.useState(null); const [open, setOpen] = React.useState(false); const [rmvOpen, setROpen] = React.useState(false); const { isLoading, isFetching, isError, data, error, refetch: refetchList, } = useGetStudentsQuery(filterRef); const [addPayment, editState] = useAddPaymentMutation(); const [removeStudent, editRmvState] = useDeleteStudentMutation(); const [installment, setInstallment] = React.useState<null | number>(); const [discount, setDiscount] = React.useState(0); const [amount, setAmount] = React.useState(0); const [due, setDue] = React.useState(0); const [comment, setComment] = React.useState(""); const [installmentNo, setInstallmentNo] = React.useState(0); const [message, setMessage] = React.useState(""); const [err, setError] = React.useState(""); const handleExcelDownload = () => { const xlsData = studentsData.map((student) => [ student.batch, student.courseTitle, student.name, student.email, student.mobile, student.area, student.profession, student.package, student.university, student.company, student.experience, student.passingYear, student.knowMe, student.shareSomething, student.isEnrolled, student.isValid, ]); const wb = XLSX.utils.book_new(); const ws = XLSX.utils.aoa_to_sheet([ ["Batch", "Course Title", "Name", "Email", "Mobile", "Area", "Proffession", "Package", "University", "Company", "Experience", "Passing Year", "Know About Us", "Comment if Any", "Is Enrolled", "Is Valid"], ...xlsData, ]); XLSX.utils.book_append_sheet(wb, ws, "Students"); const wbout = XLSX.write(wb, { type: "binary", bookType: "xls" }); const blob = new Blob([s2ab(wbout)], { type: "application/vnd.ms-excel" }); const uniqueBatches = [...new Set(batches)]; const batchFileName = uniqueBatches.length ? "students.xls" : "students_empty.xls"; saveAs(blob, batchFileName); }; const s2ab = (s) => { const buf = new ArrayBuffer(s.length); const view = new Uint8Array(buf); for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff; return buf; }; const studentsData = React.useMemo(() => { return data?.map((student: any) => ({ ...student, enrolledAt: format(new Date(student.createdAt), "dd MMM yyyy, hh:mm a"), })); }, [data]); const totalStudentsCount = studentsData?.length || 0; const { registerState } = useSeatchList({ setFilterRef, listData: studentsData, defaultValues, }); const courses = studentsData?.map((student: any) => student.courseTitle) ?? []; const batches = studentsData?.map((student: any) => `${student.batch}`) ?? []; const coursesUnique = [...(new Set<string>(courses) as any)]; const batchesUnique = [...(new Set<string>(batches) as any)].sort((a, b) => a - b); const handleClose = () => setOpen(false); const handleRmvClose = () => setROpen(false); const handleClick = (event, rowData) => { setStudentId(rowData); setOpen(true); }; const handleRmvClick = (event, rowData) => { setStudentId(rowData); setROpen(true); }; const handlePayment = (e) => { e.preventDefault(); if (comment.trim() === "") { setError("Please enter a comment."); return; } const paymentData = { id: studentId?.id, courseId: studentId?.courseId, installmentNo: installmentNo, installmentAmount: installment, discount: discount, paidAmount: amount, due: due, comment: comment, }; // console.log(paymentData); try { addPayment(paymentData) .unwrap() .then((payload) => setMessage("Add payment successfull")) .catch((error) => setError("Payment unsuccessfull! Please try again..")); } catch (e) { // console.log("error"); } handleClose(); }; const handleRmvStudent = (e) => { e.preventDefault(); const stData = { id: studentId?.id, }; console.log(stData); try { removeStudent(stData) .unwrap() .then((payload) => { setMessage("Remove student successfull."); refetchList(); }) .catch((error) => setError("Remove student unsuccessfull! Please try again..")); } catch (e) { // console.log("error"); } handleRmvClose(); }; return ( <> <Head title="Students" hasMaterialTable={undefined} /> <Dashboard> <Backdrop className="z-50" open={isFetching || isLoading}> <CircularProgress color="inherit" /> </Backdrop> <div className="mb-4 bg-white p-4"> <Grid container gap={2}> <HookAutoComplete gridProps={{ xs: 6, md: 3, }} {...registerState("courseTitle")} autocompleteProps={{ options: coursesUnique, isOptionEqualToValue: (option, value) => option === value, sx: { "& .MuiAutocomplete-endAdornment": { top: 2, }, }, }} textFieldProps={{ label: "Course Name", }} /> <HookAutoComplete gridProps={{ xs: 6, md: 2, }} {...registerState("batch")} autocompleteProps={{ options: batchesUnique, isOptionEqualToValue: (option, value) => option === value, sx: { "& .MuiAutocomplete-endAdornment": { top: 2, }, }, }} textFieldProps={{ label: "Batch Number", }} /> <HookAutoComplete gridProps={{ xs: 6, md: 2, }} {...registerState("isEnrolled")} autocompleteProps={{ options: ["1", "0"], getOptionLabel: (option) => (option == "1" ? "true" : "false"), isOptionEqualToValue: (option, value) => option === value, sx: { "& .MuiAutocomplete-endAdornment": { top: 2, }, }, }} textFieldProps={{ label: "Enrollment Status", }} /> <HookAutoComplete gridProps={{ xs: 6, md: 2, }} {...registerState("isValid")} autocompleteProps={{ options: ["1", "0"], getOptionLabel: (option) => (option == "1" ? "true" : "false"), isOptionEqualToValue: (option, value) => option === value, sx: { "& .MuiAutocomplete-endAdornment": { top: 2, }, }, }} textFieldProps={{ label: "Validity Status", }} /> <HookAutoComplete gridProps={{ xs: 6, md: 2, }} {...registerState("profession")} autocompleteProps={{ options: ["Fresh Graduate", "Job Holder", "Student"], // Updated options isOptionEqualToValue: (option, value) => option === value, sx: { "& .MuiAutocomplete-endAdornment": { top: 2, }, }, }} textFieldProps={{ label: "Profession", }} /> </Grid> </div> <MaterialTable title={ <div className="count bg-white p-4 rounded-lg shadow-lg text-gray-800 flex items-center justify-between"> <div> <span className="text-xl font-bold">All Students:</span> <span className="text-xl font-bold ml-2">{totalStudentsCount}</span> </div> <button onClick={handleExcelDownload} className="ml-4 py-2 px-4 hover:bg-green-700 rounded-lg bg-green-500 text-white flex items-center focus:outline-none" > <FaFileExcel className="mr-2" />XLSX </button> </div> } columns={[ { title: "Batch", field: "batch" }, { title: "Course Title", field: "courseTitle" }, { title: "Name", field: "name", render: (rowdata) => { return ( <button className="text-indigo-500 underline" onClick={(e) => handleClick(e, rowdata)} > {rowdata.name} </button> ); }, width: "300%", }, { title: "Email", field: "email" }, { title: "Mobile", field: "mobile" }, { title: "Package", field: "package", hidden: true }, { title: "University", field: "university", filtering: false }, { title: "Profession", field: "profession", filtering: false }, // { title: "Company", field: "company" }, // { title: "Experience", field: "experience" }, { title: "Enrollment Status", field: "isEnrolled", // hidden: role != "admin", hidden: true, hiddenByColumnsButton: role != "admin", }, { title: "Validity Status", field: "isValid", hidden: role != "admin", hiddenByColumnsButton: role != "admin", }, { title: "Show Story", field: "ssEnable", // hidden: role != "admin", hidden: true, hiddenByColumnsButton: role != "admin", }, { title: "Success Story", field: "successStory", hidden: true, hiddenByColumnsButton: role != "admin", }, // { title: "Enrolled At", field: "enrolledAt" }, ]} data={studentsData} actions={[ { icon: () => <MdEdit />, tooltip: "Edit Student", onClick: (event, rowData) => router.push( `/dashboard/student/edit/${rowData?.id}?courseId=${rowData?.courseId}&package=${rowData?.package}` ), disabled: role !== "admin", hidden: role !== "admin", }, { icon: () => <MdPayment />, tooltip: "Add Payment", onClick: (event, rowData) => { handleClick(event, rowData); }, disabled: role !== "admin", hidden: role !== "admin", }, { icon: () => <MdDeleteForever />, tooltip: "Remove Student", onClick: (event, rowData) => { handleRmvClick(event, rowData); }, disabled: role !== "admin", hidden: role !== "admin", }, ]} options={{ columnsButton: role == "admin", actionsColumnIndex: -1, filtering: true, pagination: true, pageSize: 20, pageSizeOptions: [20, 50, 100, 500], // tableLayout: "fixed" }} // detailPanel={[ // { // // icon: "Show Name", // tooltip: "Show Surname", // render: (rowData) => { // return ( // <div // style={{ // fontSize: 14, // // textAlign: "center", // color: "black", // backgroundColor: "#00000", // }} // > // Name: {rowData.name} Email: {rowData.email} Mobile: {rowData.mobile} // <br/> // University:{rowData.university} Profession: {rowData.profession} // </div> // ); // }, // }, // ]} /> {message != "" && <Alert variant="success" message={message} />} {err != "" && <Alert variant="error" message={err} />} {isError && <Alert variant="error" message={(error as any)?.data?.message} />} {/* {editState.isError && <Alert variant="error" message={editState.error} />} */} <Modal open={open} onClose={handleClose} aria-labelledby="Student information and add payment." aria-describedby="This modal will show student information and add payment of individual student." > <div className="flex h-screen items-center justify-center text-blue-400"> <div className="mt-5 flex max-h-screen w-5/6 flex-col items-center justify-center self-center overflow-y-auto rounded-xl bg-white shadow-2xl"> <form className="flex-col-3 flex w-full flex-wrap gap-3 p-5"> <div className="closeButton" style={{ display: 'flex', justifyContent: 'flex-end' }}> </div> <div className="flex-col-3 flex w-full flex-wrap justify-center gap-3 border-2 border-solid border-teal-300 bg-teal-300 p-1"> <p className="text-xl font-bold text-black">Student Information</p> </div> <div className="flex-col-3 flex w-full flex-wrap gap-3 p-5"> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Student id</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="studentId" placeholder="student id" value={studentId?.id} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Course ID</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="studentId" placeholder="student id" value={studentId?.courseId} readOnly /> </label> <label className="relative mt-3 flex-1 flex-col"> <span className="mb-3 font-bold">Course Name</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="courseName" placeholder="course name" value={studentId?.courseTitle} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Student name</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="studentName" placeholder="student name" value={studentId?.name} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Batch no</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="batchNo" placeholder="Batch No" value={studentId?.batch} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Profession</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="profession" placeholder="profession" value={studentId?.profession} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Package</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="profession" placeholder="profession" value={studentId?.package} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Company</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="company" placeholder="Company" value={studentId?.company} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Experience</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="experience" placeholder="Experience" value={studentId?.experience} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">City</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="city" placeholder="city" value={studentId?.city} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Enrolled At</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="enrolled at" placeholder="enrolled at" value={studentId?.enrolledAt} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Passing Year</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="shareSomething" placeholder="Passing Year" value={studentId?.passingYear} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">How did you know about us?</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="knowMe" placeholder="How did you know about us" value={studentId?.knowMe} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">My Opinion</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="shareSomething" placeholder="If you share something important about you" value={studentId?.shareSomething} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Github</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="certificate" placeholder="Certificate URL" value={studentId?.github} readOnly /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Certificate URL</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="certificate" placeholder="Certificate URL" value={studentId?.certificate} readOnly /> </label> </div> {role == "admin" ? ( <div> <div className="flex-col-3 flex w-full flex-wrap justify-center gap-3 border-2 border-solid border-teal-300 bg-teal-300 p-1 "> <p className="0 text-xl font-bold text-black">Add New Payment</p> </div> <div className="flex-col-3 flex w-full flex-wrap gap-3 p-5"> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Installment no</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="installment" placeholder="installment" value={installmentNo} onChange={( e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement> ) => { setInstallmentNo(Number(e.target.value)); }} /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Installment Amount</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="installment" placeholder="installment" value={installment} onChange={( e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement> ) => { setInstallment(Number(e.target.value)); }} /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Discount</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="discount" placeholder="Discount" value={discount} onChange={( e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement> ) => { setDiscount(Number(e.target.value)); }} /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Paid Amount</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="amount" placeholder="Amount" value={amount} onChange={( e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement> ) => { setAmount(Number(e.target.value)); }} /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Due Amount</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="due" placeholder="Due" value={due} onChange={( e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement> ) => { setDue(Number(e.target.value)); }} /> </label> <label className="relative flex flex-1 flex-col"> <span className="mb-3 font-bold">Comment</span> <input className="peer rounded-md border-2 border-gray-200 py-2 pr-2 text-black placeholder-gray-300" type="text" name="comment" placeholder="comment" value={comment} onChange={( e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement> ) => { setComment(e.target.value); }} /> </label> <div className="mt-2 mb-2 flex w-full justify-center"> <button className="bg-green-600 px-4 py-3 text-white" onClick={handlePayment} > Add Payment{" "} </button> <button className="bg-blue-600 px-4 py-3 text-white" onClick={(e)=> router.push( `/dashboard/student/edit/${studentId?.id}?courseId=${studentId?.courseId}&package=${studentId?.package}` )}> Edit Student </button> <button onClick={handleClose} className="ml-4 px-6 py-2 bg-red-600 hover:bg-red-700 rounded-none text-white flex items-center focus:outline-none"> <FaTimes className="mr-2" />Close </button> </div> </div> </div> ) : ( <div className="mt-2 mb-4 w-full justify-around"> </div> )} </form> </div> </div> </Modal> <Modal open={rmvOpen} onClose={handleRmvClose} aria-labelledby="modal-modal-title" aria-describedby="modal-modal-description" > <div className="grid h-full grid-cols-1 place-content-center place-items-center "> <div className="w-[500px] justify-self-center"> <div className="modal-dialog modal-dialog-centered pointer-events-none relative w-auto"> <div className="modal-content pointer-events-auto relative flex w-full flex-col rounded-md border-none bg-white bg-clip-padding text-current shadow-lg outline-none dark:bg-dark-400 dark:text-white"> <div className="modal-header flex flex-shrink-0 items-center justify-between rounded-t-md border-b border-gray-200 bg-red-400 p-4 text-black"> <h5 className="bg text-xl font-medium leading-normal text-black dark:text-white" id="exampleModalScrollableLabel" > Are you sure? </h5> </div> <div className="modal-body relative p-4"> <p> Are you sure wanted to delete the student with id {studentId?.id} and name{" "} {studentId?.name} </p> </div> <div className="modal-footer flex flex-shrink-0 flex-wrap items-center justify-end rounded-b-md border-t border-gray-200 p-4"> <button type="button" className="inline-block rounded bg-blue-600 px-6 py-2.5 text-xs font-medium uppercase leading-tight text-white shadow-md transition duration-150 ease-in-out hover:bg-blue-700 hover:shadow-lg focus:bg-purple-700 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-purple-800 active:shadow-lg" onClick={handleRmvClose} > Close </button> <button type="button" className="ml-1 inline-block rounded bg-red-600 px-6 py-2.5 text-xs font-medium uppercase leading-tight text-white shadow-md transition duration-150 ease-in-out hover:bg-red-700 hover:shadow-lg focus:bg-blue-700 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-blue-800 active:shadow-lg" onClick={handleRmvStudent} > Confirm Delete </button> </div> </div> </div> </div> </div> </Modal> </Dashboard> </> ); }; export const getServerSideProps = ({ query }) => { resetServerContext(); return { props: {}, }; }; export default withPermissions(["admin", "teacher"])(Students);