Added filtering and pagination for the assignment creator
This commit is contained in:
@@ -21,6 +21,7 @@ import Checkbox from "@/components/Low/Checkbox";
|
||||
import {InstructorGender, Variant} from "@/interfaces/exam";
|
||||
import Select from "@/components/Low/Select";
|
||||
import useExams from "@/hooks/useExams";
|
||||
import {useListSearch} from "@/hooks/useListSearch";
|
||||
|
||||
interface Props {
|
||||
isCreating: boolean;
|
||||
@@ -31,7 +32,12 @@ interface Props {
|
||||
cancelCreation: () => void;
|
||||
}
|
||||
|
||||
const SIZE = 12;
|
||||
|
||||
export default function AssignmentCreator({isCreating, assignment, user, groups, users, cancelCreation}: Props) {
|
||||
const [studentsPage, setStudentsPage] = useState(0);
|
||||
const [teachersPage, setTeachersPage] = useState(0);
|
||||
|
||||
const [selectedModules, setSelectedModules] = useState<Module[]>(assignment?.exams.map((e) => e.module) || []);
|
||||
const [assignees, setAssignees] = useState<string[]>(assignment?.assignees || []);
|
||||
const [teachers, setTeachers] = useState<string[]>(!!assignment ? assignment.teachers || [] : [...(user.type === "teacher" ? [user.id] : [])]);
|
||||
@@ -69,6 +75,29 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
||||
const userStudents = useMemo(() => users.filter((x) => x.type === "student"), [users]);
|
||||
const userTeachers = useMemo(() => users.filter((x) => x.type === "teacher"), [users]);
|
||||
|
||||
const {rows: filteredStudentsRows, renderSearch: renderStudentSearch, text: studentText} = useListSearch([["name"], ["email"]], userStudents);
|
||||
const {rows: filteredTeachersRows, renderSearch: renderTeacherSearch, text: teacherText} = useListSearch([["name"], ["email"]], userTeachers);
|
||||
|
||||
useEffect(() => setStudentsPage(0), [studentText]);
|
||||
const studentRows = useMemo(
|
||||
() =>
|
||||
filteredStudentsRows.slice(
|
||||
studentsPage * SIZE,
|
||||
(studentsPage + 1) * SIZE > filteredStudentsRows.length ? filteredStudentsRows.length : (studentsPage + 1) * SIZE,
|
||||
),
|
||||
[filteredStudentsRows, studentsPage],
|
||||
);
|
||||
|
||||
useEffect(() => setTeachersPage(0), [teacherText]);
|
||||
const teacherRows = useMemo(
|
||||
() =>
|
||||
filteredTeachersRows.slice(
|
||||
teachersPage * SIZE,
|
||||
(teachersPage + 1) * SIZE > filteredTeachersRows.length ? filteredTeachersRows.length : (teachersPage + 1) * SIZE,
|
||||
),
|
||||
[filteredTeachersRows, teachersPage],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setExamIDs((prev) => prev.filter((x) => selectedModules.includes(x.module)));
|
||||
}, [selectedModules]);
|
||||
@@ -347,9 +376,9 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
||||
</div>
|
||||
)}
|
||||
|
||||
<section className="w-full flex flex-col gap-3">
|
||||
<section className="w-full flex flex-col gap-4">
|
||||
<span className="font-semibold">Assignees ({assignees.length} selected)</span>
|
||||
<div className="flex gap-4 overflow-x-scroll scrollbar-hide">
|
||||
<div className="grid grid-cols-5 gap-4">
|
||||
{groups.map((g) => (
|
||||
<button
|
||||
key={g.id}
|
||||
@@ -371,8 +400,11 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{renderStudentSearch()}
|
||||
|
||||
<div className="flex flex-wrap -md:justify-center gap-4">
|
||||
{userStudents.map((user) => (
|
||||
{studentRows.map((user) => (
|
||||
<div
|
||||
onClick={() => toggleAssignee(user)}
|
||||
className={clsx(
|
||||
@@ -402,12 +434,32 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="w-full flex gap-2 justify-between items-center">
|
||||
<div className="flex items-center gap-4 w-fit">
|
||||
<Button className="w-[200px] h-fit" disabled={studentsPage === 0} onClick={() => setStudentsPage((prev) => prev - 1)}>
|
||||
Previous Page
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex items-center gap-4 w-fit">
|
||||
<span className="opacity-80">
|
||||
{studentsPage * SIZE + 1} -{" "}
|
||||
{(studentsPage + 1) * SIZE > filteredStudentsRows.length ? filteredStudentsRows.length : (studentsPage + 1) * SIZE} /{" "}
|
||||
{filteredStudentsRows.length}
|
||||
</span>
|
||||
<Button
|
||||
className="w-[200px]"
|
||||
disabled={(studentsPage + 1) * SIZE >= filteredStudentsRows.length}
|
||||
onClick={() => setStudentsPage((prev) => prev + 1)}>
|
||||
Next Page
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{user.type !== "teacher" && (
|
||||
<section className="w-full flex flex-col gap-3">
|
||||
<span className="font-semibold">Teachers ({teachers.length} selected)</span>
|
||||
<div className="flex gap-4 overflow-x-scroll scrollbar-hide">
|
||||
<div className="grid grid-cols-5 gap-4">
|
||||
{groups.map((g) => (
|
||||
<button
|
||||
key={g.id}
|
||||
@@ -429,8 +481,11 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{renderTeacherSearch()}
|
||||
|
||||
<div className="flex flex-wrap -md:justify-center gap-4">
|
||||
{userTeachers.map((user) => (
|
||||
{teacherRows.map((user) => (
|
||||
<div
|
||||
onClick={() => toggleTeacher(user)}
|
||||
className={clsx(
|
||||
@@ -453,6 +508,29 @@ export default function AssignmentCreator({isCreating, assignment, user, groups,
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="w-full flex gap-2 justify-between items-center">
|
||||
<div className="flex items-center gap-4 w-fit">
|
||||
<Button className="w-[200px] h-fit" disabled={teachersPage === 0} onClick={() => setTeachersPage((prev) => prev - 1)}>
|
||||
Previous Page
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex items-center gap-4 w-fit">
|
||||
<span className="opacity-80">
|
||||
{teachersPage * SIZE + 1} -{" "}
|
||||
{(teachersPage + 1) * SIZE > filteredTeachersRows.length
|
||||
? filteredTeachersRows.length
|
||||
: (teachersPage + 1) * SIZE}{" "}
|
||||
/ {filteredTeachersRows.length}
|
||||
</span>
|
||||
<Button
|
||||
className="w-[200px]"
|
||||
disabled={(teachersPage + 1) * SIZE >= filteredTeachersRows.length}
|
||||
onClick={() => setTeachersPage((prev) => prev + 1)}>
|
||||
Next Page
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user